xref: /aosp_15_r20/external/skia/src/gpu/tessellate/MidpointContourParser.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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