| 1 | /* |
|---|---|
| 2 | * Copyright 2020 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
| 8 | #ifndef GrMidpointContourParser_DEFINED |
| 9 | #define GrMidpointContourParser_DEFINED |
| 10 | |
| 11 | #include "src/core/SkPathPriv.h" |
| 12 | |
| 13 | // Parses out each contour in a path and tracks the midpoint. Example usage: |
| 14 | // |
| 15 | // SkTPathContourParser parser; |
| 16 | // while (parser.parseNextContour()) { |
| 17 | // SkPoint midpoint = parser.currentMidpoint(); |
| 18 | // for (auto [verb, pts] : parser.currentContour()) { |
| 19 | // ... |
| 20 | // } |
| 21 | // } |
| 22 | // |
| 23 | class GrMidpointContourParser { |
| 24 | public: |
| 25 | GrMidpointContourParser(const SkPath& path) |
| 26 | : fPath(path) |
| 27 | , fVerbs(SkPathPriv::VerbData(fPath)) |
| 28 | , fNumRemainingVerbs(fPath.countVerbs()) |
| 29 | , fPoints(SkPathPriv::PointData(fPath)) {} |
| 30 | // Advances the internal state to the next contour in the path. Returns false if there are no |
| 31 | // more contours. |
| 32 | bool parseNextContour() { |
| 33 | bool hasGeometry = false; |
| 34 | for (; fVerbsIdx < fNumRemainingVerbs; ++fVerbsIdx) { |
| 35 | switch (fVerbs[fVerbsIdx]) { |
| 36 | case SkPath::kMove_Verb: |
| 37 | if (!hasGeometry) { |
| 38 | fMidpoint = fPoints[fPtsIdx]; |
| 39 | fMidpointWeight = 1; |
| 40 | this->advance(); |
| 41 | ++fPtsIdx; |
| 42 | continue; |
| 43 | } |
| 44 | return true; |
| 45 | default: |
| 46 | continue; |
| 47 | case SkPath::kLine_Verb: |
| 48 | ++fPtsIdx; |
| 49 | break; |
| 50 | case SkPath::kQuad_Verb: |
| 51 | case SkPath::kConic_Verb: |
| 52 | fPtsIdx += 2; |
| 53 | break; |
| 54 | case SkPath::kCubic_Verb: |
| 55 | fPtsIdx += 3; |
| 56 | break; |
| 57 | } |
| 58 | fMidpoint += fPoints[fPtsIdx - 1]; |
| 59 | ++fMidpointWeight; |
| 60 | hasGeometry = true; |
| 61 | } |
| 62 | return hasGeometry; |
| 63 | } |
| 64 | |
| 65 | // Allows for iterating the current contour using a range-for loop. |
| 66 | SkPathPriv::Iterate currentContour() { |
| 67 | return SkPathPriv::Iterate(fVerbs, fVerbs + fVerbsIdx, fPoints, nullptr); |
| 68 | } |
| 69 | |
| 70 | SkPoint currentMidpoint() { return fMidpoint * (1.f / fMidpointWeight); } |
| 71 | |
| 72 | private: |
| 73 | void advance() { |
| 74 | fVerbs += fVerbsIdx; |
| 75 | fNumRemainingVerbs -= fVerbsIdx; |
| 76 | fVerbsIdx = 0; |
| 77 | fPoints += fPtsIdx; |
| 78 | fPtsIdx = 0; |
| 79 | } |
| 80 | |
| 81 | const SkPath& fPath; |
| 82 | |
| 83 | const uint8_t* fVerbs; |
| 84 | int fNumRemainingVerbs = 0; |
| 85 | int fVerbsIdx = 0; |
| 86 | |
| 87 | const SkPoint* fPoints; |
| 88 | int fPtsIdx = 0; |
| 89 | |
| 90 | SkPoint fMidpoint; |
| 91 | int fMidpointWeight; |
| 92 | }; |
| 93 | |
| 94 | #endif |
| 95 |