Flutter Engine
The Flutter Engine
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])
Definition: SkGeometry.cpp:344
int SkChopQuadAtMaxCurvature(const SkPoint src[3], SkPoint dst[5])
Definition: SkGeometry.cpp:367
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
void addConic(SkPoint pts[3], SkScalar weight)
Definition: SkOpContour.cpp:46
void addCurve(SkPath::Verb verb, const SkPoint pts[4], SkScalar weight=1)
Definition: SkOpContour.cpp:56
void setContour(SkOpContour *contour)
Definition: SkOpContour.h:455
void addCubic(SkPoint pts[4])
Definition: SkOpContour.cpp:51
void addQuad(SkPoint pts[3])
Definition: SkOpContour.cpp:97
void addLine(const SkPoint pts[2])
Definition: SkOpContour.cpp:83
SkOpContour * contour()
Definition: SkOpContour.h:454
SkOpContour * appendContour()
Definition: SkOpContour.h:402
void remove(SkOpContour *contour)
Definition: SkOpContour.h:424
void addOperand(const SkPath &path)
Definition: SkPath.h:59
bool isFinite() const
Definition: SkPath.cpp:421
SkPathFillType getFillType() const
Definition: SkPath.h:230
@ kClose_Verb
Definition: SkPath.h:1471
@ kMove_Verb
Definition: SkPath.h:1466
@ kConic_Verb
Definition: SkPath.h:1469
@ kDone_Verb
Definition: SkPath.h:1472
@ kCubic_Verb
Definition: SkPath.h:1470
@ kQuad_Verb
Definition: SkPath.h:1468
@ kLine_Verb
Definition: SkPath.h:1467
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
static float min(float r, float g, float b)
Definition: hsl.cpp:48
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
AI float conic(float tolerance, const SkPoint pts[], float w, const VectorXform &vectorXform=VectorXform())
Definition: WangsFormula.h:287
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
Definition: SkPoint_impl.h:164
float dot(const SkVector &vec) const
Definition: SkPoint_impl.h:554
float fY
y-axis value
Definition: SkPoint_impl.h:165
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)