1 /*
2 * Copyright 2015 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 #include "include/core/SkPathTypes.h"
9 #include "include/core/SkPoint.h"
10 #include "include/core/SkTypes.h"
11 #include "include/private/base/SkDebug.h"
12 #include "src/base/SkMathPriv.h"
13 #include "src/core/SkPathPriv.h"
14 #include "tests/SubsetPath.h"
15
SubsetPath(const SkPath & path)16 SubsetPath::SubsetPath(const SkPath& path)
17 : fPath(path)
18 , fSubset(1) {
19 }
20
range(int * end) const21 int SubsetPath::range(int* end) const {
22 int leadingZero = SkCLZ(fSubset);
23 int parts = 1 << (31 - leadingZero);
24 int partIndex = fSubset - parts;
25 SkASSERT(partIndex >= 0);
26 int count = fSelected.size();
27 int start = count * partIndex / parts;
28 *end = count * (partIndex + 1) / parts;
29 return start;
30 }
31
subset(bool testFailed,SkPath * sub)32 bool SubsetPath::subset(bool testFailed, SkPath* sub) {
33 int start, end;
34 if (!testFailed) {
35 start = range(&end);
36 for (; start < end; ++start) {
37 fSelected[start] = true;
38 }
39 }
40 do {
41 do {
42 ++fSubset;
43 start = range(&end);
44 // SkDebugf("%d s=%d e=%d t=%d\n", fSubset, start, end, fTries);
45 if (end - start > 1) {
46 fTries = fSelected.size();
47 } else if (end - start == 1) {
48 if (--fTries <= 0) {
49 return false;
50 }
51 }
52 } while (start == end);
53 } while (!fSelected[start]);
54 for (; start < end; ++start) {
55 fSelected[start] = false;
56 }
57 #if 1
58 SkDebugf("selected: ");
59 for (int index = 0; index < fSelected.size(); ++index) {
60 SkDebugf("%c", fSelected[index] ? 'x' : '-');
61 }
62 #endif
63 *sub = getSubsetPath();
64 return true;
65 }
66
SubsetContours(const SkPath & path)67 SubsetContours::SubsetContours(const SkPath& path)
68 : SubsetPath(path) {
69 bool foundCurve = false;
70 int contourCount = 0;
71 for (auto [verb, pts, w] : SkPathPriv::Iterate(fPath)) {
72 switch (verb) {
73 case SkPathVerb::kMove:
74 break;
75 case SkPathVerb::kLine:
76 case SkPathVerb::kQuad:
77 case SkPathVerb::kConic:
78 case SkPathVerb::kCubic:
79 foundCurve = true;
80 break;
81 case SkPathVerb::kClose:
82 ++contourCount;
83 foundCurve = false;
84 break;
85 default:
86 SkDEBUGFAIL("bad verb");
87 return;
88 }
89 }
90 contourCount += foundCurve;
91 for (int index = 0; index < contourCount; ++index) {
92 *fSelected.append() = true;
93 }
94 fTries = contourCount;
95 }
96
getSubsetPath() const97 SkPath SubsetContours::getSubsetPath() const {
98 SkPath result;
99 result.setFillType(fPath.getFillType());
100 if (!fSelected.size()) {
101 return result;
102 }
103 int contourCount = 0;
104 bool enabled = fSelected[0];
105 bool addMoveTo = true;
106 for (auto [verb, pts, w] : SkPathPriv::Iterate(fPath)) {
107 if (enabled && addMoveTo) {
108 result.moveTo(pts[0]);
109 addMoveTo = false;
110 }
111 switch (verb) {
112 case SkPathVerb::kMove:
113 break;
114 case SkPathVerb::kLine:
115 if (enabled) {
116 result.lineTo(pts[1]);
117 }
118 break;
119 case SkPathVerb::kQuad:
120 if (enabled) {
121 result.quadTo(pts[1], pts[2]);
122 }
123 break;
124 case SkPathVerb::kConic:
125 if (enabled) {
126 result.conicTo(pts[1], pts[2], *w);
127 }
128 break;
129 case SkPathVerb::kCubic:
130 if (enabled) {
131 result.cubicTo(pts[1], pts[2], pts[3]);
132 }
133 break;
134 case SkPathVerb::kClose:
135 if (enabled) {
136 result.close();
137 }
138 if (++contourCount >= fSelected.size()) {
139 break;
140 }
141 enabled = fSelected[contourCount];
142 addMoveTo = true;
143 continue;
144 default:
145 SkDEBUGFAIL("bad verb");
146 return result;
147 }
148 }
149 return result;
150 }
151
SubsetVerbs(const SkPath & path)152 SubsetVerbs::SubsetVerbs(const SkPath& path)
153 : SubsetPath(path) {
154 int verbCount = 0;
155 for (auto [verb, pts, w] : SkPathPriv::Iterate(fPath)) {
156 switch (verb) {
157 case SkPathVerb::kMove:
158 break;
159 case SkPathVerb::kLine:
160 case SkPathVerb::kQuad:
161 case SkPathVerb::kConic:
162 case SkPathVerb::kCubic:
163 ++verbCount;
164 break;
165 case SkPathVerb::kClose:
166 break;
167 default:
168 SkDEBUGFAIL("bad verb");
169 return;
170 }
171 }
172 for (int index = 0; index < verbCount; ++index) {
173 *fSelected.append() = true;
174 }
175 fTries = verbCount;
176 }
177
getSubsetPath() const178 SkPath SubsetVerbs::getSubsetPath() const {
179 SkPath result;
180 result.setFillType(fPath.getFillType());
181 if (!fSelected.size()) {
182 return result;
183 }
184 int verbIndex = 0;
185 bool addMoveTo = true;
186 bool addLineTo = false;
187 for (auto [verb, pts, w] : SkPathPriv::Iterate(fPath)) {
188 bool enabled = SkPathVerb::kLine <= verb && verb <= SkPathVerb::kCubic
189 ? fSelected[verbIndex++] : false;
190 if (enabled) {
191 if (addMoveTo) {
192 result.moveTo(pts[0]);
193 addMoveTo = false;
194 } else if (addLineTo) {
195 result.lineTo(pts[0]);
196 addLineTo = false;
197 }
198 }
199 switch (verb) {
200 case SkPathVerb::kMove:
201 break;
202 case SkPathVerb::kLine:
203 if (enabled) {
204 result.lineTo(pts[1]);
205 }
206 break;
207 case SkPathVerb::kQuad:
208 if (enabled) {
209 result.quadTo(pts[1], pts[2]);
210 }
211 break;
212 case SkPathVerb::kConic:
213 if (enabled) {
214 result.conicTo(pts[1], pts[2], *w);
215 }
216 break;
217 case SkPathVerb::kCubic:
218 if (enabled) {
219 result.cubicTo(pts[1], pts[2], pts[3]);
220 }
221 break;
222 case SkPathVerb::kClose:
223 result.close();
224 addMoveTo = true;
225 addLineTo = false;
226 continue;
227 default:
228 SkDEBUGFAIL("bad verb");
229 return result;
230 }
231 addLineTo = !enabled;
232 }
233 return result;
234 }
235