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