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:
GrMidpointContourParser(const SkPath & path)25     GrMidpointContourParser(const SkPath& path)
26             : fPath(path)
27             , fVerbs(SkPathPriv::VerbData(fPath))
28             , fNumRemainingVerbs(fPath.countVerbs())
29             , fPoints(SkPathPriv::PointData(fPath))
30             , fWeights(SkPathPriv::ConicWeightData(fPath)) {}
31     // Advances the internal state to the next contour in the path. Returns false if there are no
32     // more contours.
parseNextContour()33     bool parseNextContour() {
34         bool hasGeometry = false;
35         for (; fVerbsIdx < fNumRemainingVerbs; ++fVerbsIdx) {
36             switch (fVerbs[fVerbsIdx]) {
37                 case SkPath::kMove_Verb:
38                     if (!hasGeometry) {
39                         fMidpoint = fPoints[fPtsIdx];
40                         fMidpointWeight = 1;
41                         this->advance();
42                         ++fPtsIdx;
43                         continue;
44                     }
45                     return true;
46                 default:
47                     continue;
48                 case SkPath::kLine_Verb:
49                     ++fPtsIdx;
50                     break;
51                 case SkPath::kConic_Verb:
52                     ++fWtsIdx;
53                     [[fallthrough]];
54                 case SkPath::kQuad_Verb:
55                     fPtsIdx += 2;
56                     break;
57                 case SkPath::kCubic_Verb:
58                     fPtsIdx += 3;
59                     break;
60             }
61             fMidpoint += fPoints[fPtsIdx - 1];
62             ++fMidpointWeight;
63             hasGeometry = true;
64         }
65         return hasGeometry;
66     }
67 
68     // Allows for iterating the current contour using a range-for loop.
currentContour()69     SkPathPriv::Iterate currentContour() {
70         return SkPathPriv::Iterate(fVerbs, fVerbs + fVerbsIdx, fPoints, fWeights);
71     }
72 
currentMidpoint()73     SkPoint currentMidpoint() { return fMidpoint * (1.f / fMidpointWeight); }
74 
75 private:
advance()76     void advance() {
77         fVerbs += fVerbsIdx;
78         fNumRemainingVerbs -= fVerbsIdx;
79         fVerbsIdx = 0;
80         fPoints += fPtsIdx;
81         fPtsIdx = 0;
82         fWeights += fWtsIdx;
83         fWtsIdx = 0;
84     }
85 
86     const SkPath& fPath;
87 
88     const uint8_t* fVerbs;
89     int fNumRemainingVerbs = 0;
90     int fVerbsIdx = 0;
91 
92     const SkPoint* fPoints;
93     int fPtsIdx = 0;
94 
95     const float* fWeights;
96     int fWtsIdx = 0;
97 
98     SkPoint fMidpoint;
99     int fMidpointWeight;
100 };
101 
102 #endif
103