1 /* 2 * Copyright 2022 Google LLC. 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 skgpu_tessellate_MidpointContourParser_DEFINED 9 #define skgpu_tessellate_MidpointContourParser_DEFINED 10 11 #include "include/core/SkPath.h" 12 #include "src/core/SkPathPriv.h" 13 14 namespace skgpu::tess { 15 16 // Parses out each contour in a path and tracks the midpoint. Example usage: 17 // 18 // MidpointContourParser parser; 19 // while (parser.parseNextContour()) { 20 // SkPoint midpoint = parser.currentMidpoint(); 21 // for (auto [verb, pts] : parser.currentContour()) { 22 // ... 23 // } 24 // } 25 // 26 class MidpointContourParser { 27 public: MidpointContourParser(const SkPath & path)28 MidpointContourParser(const SkPath& path) 29 : fPath(path) 30 , fVerbs(SkPathPriv::VerbData(fPath)) 31 , fNumRemainingVerbs(fPath.countVerbs()) 32 , fPoints(SkPathPriv::PointData(fPath)) 33 , fWeights(SkPathPriv::ConicWeightData(fPath)) {} 34 // Advances the internal state to the next contour in the path. Returns false if there are no 35 // more contours. parseNextContour()36 bool parseNextContour() { 37 bool hasGeometry = false; 38 for (; fVerbsIdx < fNumRemainingVerbs; ++fVerbsIdx) { 39 switch (fVerbs[fVerbsIdx]) { 40 case SkPath::kMove_Verb: 41 if (!hasGeometry) { 42 fMidpoint = {0,0}; 43 fMidpointWeight = 0; 44 this->advance(); // Resets fPtsIdx to 0 and advances fPoints. 45 fPtsIdx = 1; // Increment fPtsIdx past the kMove. 46 continue; 47 } 48 if (fPoints[0] != fPoints[fPtsIdx - 1]) { 49 // There's an implicit close at the end. Add the start point to our mean. 50 fMidpoint += fPoints[0]; 51 ++fMidpointWeight; 52 } 53 return true; 54 default: 55 continue; 56 case SkPath::kLine_Verb: 57 ++fPtsIdx; 58 break; 59 case SkPath::kConic_Verb: 60 ++fWtsIdx; 61 [[fallthrough]]; 62 case SkPath::kQuad_Verb: 63 fPtsIdx += 2; 64 break; 65 case SkPath::kCubic_Verb: 66 fPtsIdx += 3; 67 break; 68 } 69 fMidpoint += fPoints[fPtsIdx - 1]; 70 ++fMidpointWeight; 71 hasGeometry = true; 72 } 73 if (hasGeometry && fPoints[0] != fPoints[fPtsIdx - 1]) { 74 // There's an implicit close at the end. Add the start point to our mean. 75 fMidpoint += fPoints[0]; 76 ++fMidpointWeight; 77 } 78 return hasGeometry; 79 } 80 81 // Allows for iterating the current contour using a range-for loop. currentContour()82 SkPathPriv::Iterate currentContour() { 83 return SkPathPriv::Iterate(fVerbs, fVerbs + fVerbsIdx, fPoints, fWeights); 84 } 85 currentMidpoint()86 SkPoint currentMidpoint() { return fMidpoint * (1.f / fMidpointWeight); } 87 88 private: advance()89 void advance() { 90 fVerbs += fVerbsIdx; 91 fNumRemainingVerbs -= fVerbsIdx; 92 fVerbsIdx = 0; 93 fPoints += fPtsIdx; 94 fPtsIdx = 0; 95 fWeights += fWtsIdx; 96 fWtsIdx = 0; 97 } 98 99 const SkPath& fPath; 100 101 const uint8_t* fVerbs; 102 int fNumRemainingVerbs = 0; 103 int fVerbsIdx = 0; 104 105 const SkPoint* fPoints; 106 int fPtsIdx = 0; 107 108 const float* fWeights; 109 int fWtsIdx = 0; 110 111 SkPoint fMidpoint; 112 int fMidpointWeight; 113 }; 114 115 } // namespace skgpu::tess 116 117 #endif // skgpu_tessellate_MidpointContourParser_DEFINED 118