Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkOpEdgeBuilder.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2012 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 */
8
13#include "src/base/SkTSort.h"
14#include "src/core/SkGeometry.h"
15#include "src/core/SkPathPriv.h"
19
20#include <algorithm>
21#include <array>
22
24 fOperand = false;
25 fXorMask[0] = fXorMask[1] = ((int)fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask
27 fUnparseable = false;
28 fSecondHalf = preFetch();
29}
30
31// very tiny points cause numerical instability : don't allow them
33 SkPoint ret = pt;
35 ret.fX = 0;
36 }
38 ret.fY = 0;
39 }
40 return ret;
41}
42
43static bool can_add_curve(SkPath::Verb verb, SkPoint* curve) {
44 if (SkPath::kMove_Verb == verb) {
45 return false;
46 }
47 for (int index = 0; index <= SkPathOpsVerbToPoints(verb); ++index) {
48 curve[index] = force_small_to_zero(curve[index]);
49 }
50 return SkPath::kLine_Verb != verb || !SkDPoint::ApproximatelyEqual(curve[0], curve[1]);
51}
52
54 SkASSERT(!fPathVerbs.empty() && fPathVerbs.back() == SkPath::kDone_Verb);
55 fPathVerbs.pop_back();
56 fPath = &path;
57 fXorMask[1] = ((int)fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask
59 preFetch();
60}
61
63 fOperand = false;
64 if (fUnparseable || !walk()) {
65 return false;
66 }
67 complete();
68 SkOpContour* contour = fContourBuilder.contour();
69 if (contour && !contour->count()) {
70 fContoursHead->remove(contour);
71 }
72 return true;
73}
74
75void SkOpEdgeBuilder::closeContour(const SkPoint& curveEnd, const SkPoint& curveStart) {
76 if (!SkDPoint::ApproximatelyEqual(curveEnd, curveStart)) {
77 *fPathVerbs.append() = SkPath::kLine_Verb;
78 *fPathPts.append() = curveStart;
79 } else {
80 int verbCount = fPathVerbs.size();
81 int ptsCount = fPathPts.size();
82 if (SkPath::kLine_Verb == fPathVerbs[verbCount - 1]
83 && fPathPts[ptsCount - 2] == curveStart) {
84 fPathVerbs.pop_back();
85 fPathPts.pop_back();
86 } else {
87 fPathPts[ptsCount - 1] = curveStart;
88 }
89 }
90 *fPathVerbs.append() = SkPath::kClose_Verb;
91}
92
93int SkOpEdgeBuilder::preFetch() {
94 if (!fPath->isFinite()) {
95 fUnparseable = true;
96 return 0;
97 }
98 SkPoint curveStart;
99 SkPoint curve[4];
100 bool lastCurve = false;
101 for (auto [pathVerb, pts, w] : SkPathPriv::Iterate(*fPath)) {
102 auto verb = static_cast<SkPath::Verb>(pathVerb);
103 switch (verb) {
105 if (!fAllowOpenContours && lastCurve) {
106 closeContour(curve[0], curveStart);
107 }
108 *fPathVerbs.append() = verb;
109 curve[0] = force_small_to_zero(pts[0]);
110 *fPathPts.append() = curve[0];
111 curveStart = curve[0];
112 lastCurve = false;
113 continue;
115 curve[1] = force_small_to_zero(pts[1]);
116 if (SkDPoint::ApproximatelyEqual(curve[0], curve[1])) {
117 uint8_t lastVerb = fPathVerbs.back();
118 if (lastVerb != SkPath::kLine_Verb && lastVerb != SkPath::kMove_Verb) {
119 fPathPts.back() = curve[0] = curve[1];
120 }
121 continue; // skip degenerate points
122 }
123 break;
125 curve[1] = force_small_to_zero(pts[1]);
126 curve[2] = force_small_to_zero(pts[2]);
127 verb = SkReduceOrder::Quad(curve, curve);
128 if (verb == SkPath::kMove_Verb) {
129 continue; // skip degenerate points
130 }
131 break;
133 curve[1] = force_small_to_zero(pts[1]);
134 curve[2] = force_small_to_zero(pts[2]);
135 verb = SkReduceOrder::Quad(curve, curve);
136 if (SkPath::kQuad_Verb == verb && 1 != *w) {
137 verb = SkPath::kConic_Verb;
138 } else if (verb == SkPath::kMove_Verb) {
139 continue; // skip degenerate points
140 }
141 break;
143 curve[1] = force_small_to_zero(pts[1]);
144 curve[2] = force_small_to_zero(pts[2]);
145 curve[3] = force_small_to_zero(pts[3]);
146 verb = SkReduceOrder::Cubic(curve, curve);
147 if (verb == SkPath::kMove_Verb) {
148 continue; // skip degenerate points
149 }
150 break;
152 closeContour(curve[0], curveStart);
153 lastCurve = false;
154 continue;
156 continue;
157 }
158 *fPathVerbs.append() = verb;
159 int ptCount = SkPathOpsVerbToPoints(verb);
160 fPathPts.append(ptCount, &curve[1]);
161 if (verb == SkPath::kConic_Verb) {
162 *fWeights.append() = *w;
163 }
164 curve[0] = curve[ptCount];
165 lastCurve = true;
166 }
167 if (!fAllowOpenContours && lastCurve) {
168 closeContour(curve[0], curveStart);
169 }
170 *fPathVerbs.append() = SkPath::kDone_Verb;
171 return fPathVerbs.size() - 1;
172}
173
174bool SkOpEdgeBuilder::close() {
175 complete();
176 return true;
177}
178
179bool SkOpEdgeBuilder::walk() {
180 uint8_t* verbPtr = fPathVerbs.begin();
181 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
182 SkPoint* pointsPtr = fPathPts.begin();
183 SkScalar* weightPtr = fWeights.begin();
184 SkPath::Verb verb;
185 SkOpContour* contour = fContourBuilder.contour();
186 int moveToPtrBump = 0;
187 while ((verb = (SkPath::Verb) *verbPtr) != SkPath::kDone_Verb) {
188 if (verbPtr == endOfFirstHalf) {
189 fOperand = true;
190 }
191 verbPtr++;
192 switch (verb) {
194 if (contour && contour->count()) {
195 if (fAllowOpenContours) {
196 complete();
197 } else if (!close()) {
198 return false;
199 }
200 }
201 if (!contour) {
202 fContourBuilder.setContour(contour = fContoursHead->appendContour());
203 }
204 contour->init(fGlobalState, fOperand,
205 fXorMask[fOperand] == kEvenOdd_PathOpsMask);
206 pointsPtr += moveToPtrBump;
207 moveToPtrBump = 1;
208 continue;
210 fContourBuilder.addLine(pointsPtr);
211 break;
213 {
214 SkVector vec1 = pointsPtr[1] - pointsPtr[0];
215 SkVector vec2 = pointsPtr[2] - pointsPtr[1];
216 if (vec1.dot(vec2) < 0) {
217 SkPoint pair[5];
218 if (SkChopQuadAtMaxCurvature(pointsPtr, pair) == 1) {
219 goto addOneQuad;
220 }
221 if (!SkIsFinite(&pair[0].fX, std::size(pair) * 2)) {
222 return false;
223 }
224 for (unsigned index = 0; index < std::size(pair); ++index) {
225 pair[index] = force_small_to_zero(pair[index]);
226 }
227 SkPoint cStorage[2][2];
228 SkPath::Verb v1 = SkReduceOrder::Quad(&pair[0], cStorage[0]);
229 SkPath::Verb v2 = SkReduceOrder::Quad(&pair[2], cStorage[1]);
230 SkPoint* curve1 = v1 != SkPath::kLine_Verb ? &pair[0] : cStorage[0];
231 SkPoint* curve2 = v2 != SkPath::kLine_Verb ? &pair[2] : cStorage[1];
232 if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) {
233 fContourBuilder.addCurve(v1, curve1);
234 fContourBuilder.addCurve(v2, curve2);
235 break;
236 }
237 }
238 }
239 addOneQuad:
240 fContourBuilder.addQuad(pointsPtr);
241 break;
242 case SkPath::kConic_Verb: {
243 SkVector vec1 = pointsPtr[1] - pointsPtr[0];
244 SkVector vec2 = pointsPtr[2] - pointsPtr[1];
245 SkScalar weight = *weightPtr++;
246 if (vec1.dot(vec2) < 0) {
247 // FIXME: max curvature for conics hasn't been implemented; use placeholder
248 SkScalar maxCurvature = SkFindQuadMaxCurvature(pointsPtr);
249 if (0 < maxCurvature && maxCurvature < 1) {
250 SkConic conic(pointsPtr, weight);
251 SkConic pair[2];
252 if (!conic.chopAt(maxCurvature, pair)) {
253 // if result can't be computed, use original
254 fContourBuilder.addConic(pointsPtr, weight);
255 break;
256 }
257 SkPoint cStorage[2][3];
258 SkPath::Verb v1 = SkReduceOrder::Conic(pair[0], cStorage[0]);
259 SkPath::Verb v2 = SkReduceOrder::Conic(pair[1], cStorage[1]);
260 SkPoint* curve1 = v1 != SkPath::kLine_Verb ? pair[0].fPts : cStorage[0];
261 SkPoint* curve2 = v2 != SkPath::kLine_Verb ? pair[1].fPts : cStorage[1];
262 if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) {
263 fContourBuilder.addCurve(v1, curve1, pair[0].fW);
264 fContourBuilder.addCurve(v2, curve2, pair[1].fW);
265 break;
266 }
267 }
268 }
269 fContourBuilder.addConic(pointsPtr, weight);
270 } break;
272 {
273 // Split complex cubics (such as self-intersecting curves or
274 // ones with difficult curvature) in two before proceeding.
275 // This can be required for intersection to succeed.
276 SkScalar splitT[3];
277 int breaks = SkDCubic::ComplexBreak(pointsPtr, splitT);
278 if (!breaks) {
279 fContourBuilder.addCubic(pointsPtr);
280 break;
281 }
282 SkASSERT(breaks <= (int) std::size(splitT));
283 struct Splitsville {
284 double fT[2];
285 SkPoint fPts[4];
286 SkPoint fReduced[4];
287 SkPath::Verb fVerb;
288 bool fCanAdd;
289 } splits[4];
290 SkASSERT(std::size(splits) == std::size(splitT) + 1);
291 SkTQSort(splitT, splitT + breaks);
292 for (int index = 0; index <= breaks; ++index) {
293 Splitsville* split = &splits[index];
294 split->fT[0] = index ? splitT[index - 1] : 0;
295 split->fT[1] = index < breaks ? splitT[index] : 1;
296 SkDCubic part = SkDCubic::SubDivide(pointsPtr, split->fT[0], split->fT[1]);
297 if (!part.toFloatPoints(split->fPts)) {
298 return false;
299 }
300 split->fVerb = SkReduceOrder::Cubic(split->fPts, split->fReduced);
301 SkPoint* curve = SkPath::kCubic_Verb == split->fVerb
302 ? split->fPts : split->fReduced;
303 split->fCanAdd = can_add_curve(split->fVerb, curve);
304 }
305 for (int index = 0; index <= breaks; ++index) {
306 Splitsville* split = &splits[index];
307 if (!split->fCanAdd) {
308 continue;
309 }
310 int prior = index;
311 while (prior > 0 && !splits[prior - 1].fCanAdd) {
312 --prior;
313 }
314 if (prior < index) {
315 split->fT[0] = splits[prior].fT[0];
316 split->fPts[0] = splits[prior].fPts[0];
317 }
318 int next = index;
319 int breakLimit = std::min(breaks, (int) std::size(splits) - 1);
320 while (next < breakLimit && !splits[next + 1].fCanAdd) {
321 ++next;
322 }
323 if (next > index) {
324 split->fT[1] = splits[next].fT[1];
325 split->fPts[3] = splits[next].fPts[3];
326 }
327 if (prior < index || next > index) {
328 split->fVerb = SkReduceOrder::Cubic(split->fPts, split->fReduced);
329 }
330 SkPoint* curve = SkPath::kCubic_Verb == split->fVerb
331 ? split->fPts : split->fReduced;
332 if (!can_add_curve(split->fVerb, curve)) {
333 return false;
334 }
335 fContourBuilder.addCurve(split->fVerb, curve);
336 }
337 }
338 break;
341 if (!close()) {
342 return false;
343 }
344 contour = nullptr;
345 continue;
346 default:
347 SkDEBUGFAIL("bad verb");
348 return false;
349 }
351 if (contour->count()) {
352 contour->debugValidate();
353 }
354 pointsPtr += SkPathOpsVerbToPoints(verb);
355 }
356 fContourBuilder.flush();
357 if (contour && contour->count() &&!fAllowOpenContours && !close()) {
358 return false;
359 }
360 return true;
361}
SkPoint fPts[2]
static float next(float f)
#define SkDEBUGFAIL(message)
Definition SkAssert.h:118
#define SkASSERT(cond)
Definition SkAssert.h:116
static bool SkIsFinite(T x, Pack... values)
SkScalar SkFindQuadMaxCurvature(const SkPoint src[3])
int SkChopQuadAtMaxCurvature(const SkPoint src[3], SkPoint dst[5])
static SkPoint force_small_to_zero(const SkPoint &pt)
static bool can_add_curve(SkPath::Verb verb, SkPoint *curve)
const double FLT_EPSILON_ORDERABLE_ERR
@ kWinding_PathOpsMask
@ kEvenOdd_PathOpsMask
int SkPathOpsVerbToPoints(SkPath::Verb verb)
#define SkScalarAbs(x)
Definition SkScalar.h:39
void SkTQSort(T *begin, T *end, const C &lessThan)
Definition SkTSort.h:194
Vec2Value v2
Type::kYUV Type::kRGBA() int(0.7 *637)
void addConic(SkPoint pts[3], SkScalar weight)
void addCurve(SkPath::Verb verb, const SkPoint pts[4], SkScalar weight=1)
void setContour(SkOpContour *contour)
void addCubic(SkPoint pts[4])
void addQuad(SkPoint pts[3])
void addLine(const SkPoint pts[2])
SkOpContour * contour()
SkOpContour * appendContour()
void remove(SkOpContour *contour)
void addOperand(const SkPath &path)
bool isFinite() const
Definition SkPath.cpp:411
SkPathFillType getFillType() const
Definition SkPath.h:230
@ kClose_Verb
Definition SkPath.h:1463
@ kMove_Verb
Definition SkPath.h:1458
@ kConic_Verb
Definition SkPath.h:1461
@ kDone_Verb
Definition SkPath.h:1464
@ kCubic_Verb
Definition SkPath.h:1462
@ kQuad_Verb
Definition SkPath.h:1460
@ kLine_Verb
Definition SkPath.h:1459
const T & back() const
Definition SkTDArray.h:162
int size() const
Definition SkTDArray.h:138
bool empty() const
Definition SkTDArray.h:135
T * begin()
Definition SkTDArray.h:150
T * append()
Definition SkTDArray.h:191
void pop_back()
Definition SkTDArray.h:223
float SkScalar
Definition extension.cpp:12
AI float conic(float tolerance, const SkPoint pts[], float w, const VectorXform &vectorXform=VectorXform())
SkScalar w
SkPoint fPts[3]
Definition SkGeometry.h:336
bool toFloatPoints(SkPoint *) const
static SkDCubic SubDivide(const SkPoint a[kPointCount], double t1, double t2)
static int ComplexBreak(const SkPoint pts[4], SkScalar *t)
static bool ApproximatelyEqual(const SkPoint &a, const SkPoint &b)
float fX
x-axis value
float dot(const SkVector &vec) const
float fY
y-axis value
static SkPath::Verb Cubic(const SkPoint pts[4], SkPoint *reducePts)
static SkPath::Verb Conic(const SkConic &conic, SkPoint *reducePts)
static SkPath::Verb Quad(const SkPoint pts[3], SkPoint *reducePts)