Flutter Engine
The Flutter Engine
Functions
SkPathOpsSimplify.cpp File Reference
#include "include/core/SkPath.h"
#include "include/core/SkPathTypes.h"
#include "include/core/SkTypes.h"
#include "include/pathops/SkPathOps.h"
#include "include/private/base/SkPoint_impl.h"
#include "include/private/base/SkTDArray.h"
#include "src/base/SkArenaAlloc.h"
#include "src/pathops/SkAddIntersections.h"
#include "src/pathops/SkOpCoincidence.h"
#include "src/pathops/SkOpContour.h"
#include "src/pathops/SkOpEdgeBuilder.h"
#include "src/pathops/SkOpSegment.h"
#include "src/pathops/SkOpSpan.h"
#include "src/pathops/SkPathOpsCommon.h"
#include "src/pathops/SkPathOpsTypes.h"
#include "src/pathops/SkPathWriter.h"

Go to the source code of this file.

Functions

static bool bridgeWinding (SkOpContourHead *contourList, SkPathWriter *writer)
 
static bool bridgeXor (SkOpContourHead *contourList, SkPathWriter *writer)
 
static bool path_is_trivial (const SkPath &path)
 
bool SimplifyDebug (const SkPath &path, SkPath *result SkDEBUGPARAMS(bool skipAssert) SkDEBUGPARAMS(const char *testName))
 
bool Simplify (const SkPath &path, SkPath *result)
 

Function Documentation

◆ bridgeWinding()

static bool bridgeWinding ( SkOpContourHead contourList,
SkPathWriter writer 
)
static

Definition at line 24 of file SkPathOpsSimplify.cpp.

24 {
25 bool unsortable = false;
26 do {
27 SkOpSpan* span = FindSortableTop(contourList);
28 if (!span) {
29 break;
30 }
31 SkOpSegment* current = span->segment();
32 SkOpSpanBase* start = span->next();
33 SkOpSpanBase* end = span;
35 do {
36 if (current->activeWinding(start, end)) {
37 do {
38 if (!unsortable && current->done()) {
39 break;
40 }
41 SkASSERT(unsortable || !current->done());
42 SkOpSpanBase* nextStart = start;
43 SkOpSpanBase* nextEnd = end;
44 SkOpSegment* next = current->findNextWinding(&chase, &nextStart, &nextEnd,
45 &unsortable);
46 if (!next) {
47 break;
48 }
49 #if DEBUG_FLOW
50 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
51 current->debugID(), start->pt().fX, start->pt().fY,
52 end->pt().fX, end->pt().fY);
53 #endif
54 if (!current->addCurveTo(start, end, writer)) {
55 return false;
56 }
57 current = next;
58 start = nextStart;
59 end = nextEnd;
60 } while (!writer->isClosed() && (!unsortable || !start->starter(end)->done()));
61 if (current->activeWinding(start, end) && !writer->isClosed()) {
62 SkOpSpan* spanStart = start->starter(end);
63 if (!spanStart->done()) {
64 if (!current->addCurveTo(start, end, writer)) {
65 return false;
66 }
67 current->markDone(spanStart);
68 }
69 }
70 writer->finishContour();
71 } else {
72 SkOpSpanBase* last;
73 if (!current->markAndChaseDone(start, end, &last)) {
74 return false;
75 }
76 if (last && !last->chased()) {
77 last->setChased(true);
79 *chase.append() = last;
80#if DEBUG_WINDING
81 SkDebugf("%s chase.append id=%d", __FUNCTION__, last->segment()->debugID());
82 if (!last->final()) {
83 SkDebugf(" windSum=%d", last->upCast()->windSum());
84 }
85 SkDebugf("\n");
86#endif
87 }
88 }
89 current = FindChase(&chase, &start, &end);
91 if (!current) {
92 break;
93 }
94 } while (true);
95 } while (true);
96 return true;
97}
static float next(float f)
#define SkASSERT(cond)
Definition: SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
SkOpSegment * FindChase(SkTDArray< SkOpSpanBase * > *chase, SkOpSpanBase **startPtr, SkOpSpanBase **endPtr)
SkOpSpan * FindSortableTop(SkOpContourHead *)
bool done() const
Definition: SkOpSegment.h:200
bool activeWinding(SkOpSpanBase *start, SkOpSpanBase *end)
bool markAndChaseDone(SkOpSpanBase *start, SkOpSpanBase *end, SkOpSpanBase **found)
int debugID() const
Definition: SkOpSegment.h:154
bool addCurveTo(const SkOpSpanBase *start, const SkOpSpanBase *end, SkPathWriter *path) const
SkOpSegment * findNextWinding(SkTDArray< SkOpSpanBase * > *chase, SkOpSpanBase **nextStart, SkOpSpanBase **nextEnd, bool *unsortable)
void markDone(SkOpSpan *)
void setChased(bool chased)
Definition: SkOpSpan.h:326
bool final() const
Definition: SkOpSpan.h:271
SkOpSpan * upCast()
Definition: SkOpSpan.h:383
bool chased() const
Definition: SkOpSpan.h:192
SkOpSegment * segment() const
Definition: SkOpSpan.h:318
int windSum() const
Definition: SkOpSpan.h:555
SkOpSpanBase * next() const
Definition: SkOpSpan.h:495
bool done() const
Definition: SkOpSpan.h:459
static void ShowActiveSpans(SkOpContourHead *contourList)
static bool ChaseContains(const SkTDArray< SkOpSpanBase * > &, const SkOpSpanBase *)
void finishContour()
bool isClosed() const
T * append()
Definition: SkTDArray.h:191
glong glong end

◆ bridgeXor()

static bool bridgeXor ( SkOpContourHead contourList,
SkPathWriter writer 
)
static

Definition at line 100 of file SkPathOpsSimplify.cpp.

100 {
101 bool unsortable = false;
102 int safetyNet = 1000000;
103 do {
104 SkOpSpan* span = FindUndone(contourList);
105 if (!span) {
106 break;
107 }
108 SkOpSegment* current = span->segment();
109 SkOpSpanBase* start = span->next();
110 SkOpSpanBase* end = span;
111 do {
112 if (--safetyNet < 0) {
113 return false;
114 }
115 if (!unsortable && current->done()) {
116 break;
117 }
118 SkASSERT(unsortable || !current->done());
119 SkOpSpanBase* nextStart = start;
120 SkOpSpanBase* nextEnd = end;
121 SkOpSegment* next = current->findNextXor(&nextStart, &nextEnd,
122 &unsortable);
123 if (!next) {
124 break;
125 }
126 #if DEBUG_FLOW
127 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
128 current->debugID(), start->pt().fX, start->pt().fY,
129 end->pt().fX, end->pt().fY);
130 #endif
131 if (!current->addCurveTo(start, end, writer)) {
132 return false;
133 }
134 current = next;
135 start = nextStart;
136 end = nextEnd;
137 } while (!writer->isClosed() && (!unsortable || !start->starter(end)->done()));
138 if (!writer->isClosed()) {
139 SkOpSpan* spanStart = start->starter(end);
140 if (!spanStart->done()) {
141 return false;
142 }
143 }
144 writer->finishContour();
146 } while (true);
147 return true;
148}
SkOpSpan * FindUndone(SkOpContourHead *contourHead)
SkOpSegment * findNextXor(SkOpSpanBase **nextStart, SkOpSpanBase **nextEnd, bool *unsortable)

◆ path_is_trivial()

static bool path_is_trivial ( const SkPath path)
static

Definition at line 150 of file SkPathOpsSimplify.cpp.

150 {
151 SkPath::Iter iter(path, true);
152
153 SkPath::Verb verb;
154 SkPoint points[4];
155
156 class Trivializer {
157 SkPoint prevPt{0,0};
158 SkVector prevVec{0,0};
159 public:
160 void moveTo(const SkPoint& currPt) {
161 prevPt = currPt;
162 prevVec = {0, 0};
163 }
164 bool addTrivialContourPoint(const SkPoint& currPt) {
165 if (currPt == prevPt) {
166 return true;
167 }
168 // There are more numericaly stable ways of determining if many points are co-linear.
169 // However, this mirrors SkPath's Convexicator for consistency.
170 SkVector currVec = currPt - prevPt;
171 if (SkPoint::CrossProduct(prevVec, currVec) != 0) {
172 return false;
173 }
174 prevVec = currVec;
175 prevPt = currPt;
176 return true;
177 }
178 } triv;
179
180 while ((verb = iter.next(points)) != SkPath::kDone_Verb) {
181 switch (verb) {
183 triv.moveTo(points[0]);
184 break;
186 if (!triv.addTrivialContourPoint(points[3])) { return false; }
187 [[fallthrough]];
190 if (!triv.addTrivialContourPoint(points[2])) { return false; }
191 [[fallthrough]];
193 if (!triv.addTrivialContourPoint(points[1])) { return false; }
194 if (!triv.addTrivialContourPoint(points[0])) { return false; }
195 break;
198 break;
199 }
200 }
201 return true;
202}
static const int points[]
@ 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
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
static float CrossProduct(const SkVector &a, const SkVector &b)
Definition: SkPoint_impl.h:532

◆ Simplify()

bool Simplify ( const SkPath path,
SkPath result 
)

Set this path to a set of non-overlapping contours that describe the same area as the original path. The curve order is reduced where possible so that cubics may be turned into quadratics, and quadratics maybe turned into lines.

Returns true if operation was able to produce a result; otherwise, result is unmodified.

Parameters
pathThe path to simplify.
resultThe simplified path. The result may be the input.
Returns
True if simplification succeeded.

Definition at line 283 of file SkPathOpsSimplify.cpp.

283 {
284#if DEBUG_DUMP_VERIFY
285 if (SkPathOpsDebug::gVerifyOp) {
286 if (!SimplifyDebug(path, result SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr))) {
287 ReportSimplifyFail(path);
288 return false;
289 }
290 VerifySimplify(path, *result);
291 return true;
292 }
293#endif
294 return SimplifyDebug(path, result SkDEBUGPARAMS(true) SkDEBUGPARAMS(nullptr));
295}
#define SkDEBUGPARAMS(...)
bool SimplifyDebug(const SkPath &path, SkPath *result SkDEBUGPARAMS(bool skipAssert) SkDEBUGPARAMS(const char *testName))
GAsyncResult * result

◆ SimplifyDebug()

bool SimplifyDebug ( const SkPath path,
SkPath *result   SkDEBUGPARAMSbool skipAssert) SkDEBUGPARAMS(const char *testName 
)

Definition at line 205 of file SkPathOpsSimplify.cpp.

206 {
207 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
208 SkPathFillType fillType = path.isInverseFillType() ? SkPathFillType::kInverseEvenOdd
210
211 if (path.isConvex()) {
212 // If the path is trivially convex, simplify to empty.
213 if (path_is_trivial(path)) {
214 result->reset();
215 } else if (result != &path) {
216 *result = path;
217 }
218 result->setFillType(fillType);
219 return true;
220 }
221 // turn path into list of segments
222 SkSTArenaAlloc<4096> allocator; // FIXME: constant-ize, tune
224 SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour);
225 SkOpGlobalState globalState(contourList, &allocator
227 SkOpCoincidence coincidence(&globalState);
228#if DEBUG_DUMP_VERIFY
229#ifndef SK_DEBUG
230 const char* testName = "release";
231#endif
232 if (SkPathOpsDebug::gDumpOp) {
233 DumpSimplify(path, testName);
234 }
235#endif
236#if DEBUG_SORT
237 SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault;
238#endif
239 SkOpEdgeBuilder builder(path, contourList, &globalState);
240 if (!builder.finish()) {
241 return false;
242 }
243#if DEBUG_DUMP_SEGMENTS
244 contour.dumpSegments();
245#endif
246 if (!SortContourList(&contourList, false, false)) {
247 result->reset();
248 result->setFillType(fillType);
249 return true;
250 }
251 // find all intersections between segments
252 SkOpContour* current = contourList;
253 do {
254 SkOpContour* next = current;
255 while (AddIntersectTs(current, next, &coincidence)
256 && (next = next->next()));
257 } while ((current = current->next()));
258#if DEBUG_VALIDATE
259 globalState.setPhase(SkOpPhase::kWalking);
260#endif
261 bool success = HandleCoincidence(contourList, &coincidence);
262#if DEBUG_COIN
263 globalState.debugAddToGlobalCoinDicts();
264#endif
265 if (!success) {
266 return false;
267 }
268#if DEBUG_DUMP_ALIGNMENT
269 contour.dumpSegments("aligned");
270#endif
271 // construct closed contours
272 result->reset();
273 result->setFillType(fillType);
274 SkPathWriter wrapper(*result);
275 if (builder.xorMask() == kWinding_PathOpsMask ? !bridgeWinding(contourList, &wrapper)
276 : !bridgeXor(contourList, &wrapper)) {
277 return false;
278 }
279 wrapper.assemble(); // if some edges could not be resolved, assemble remaining
280 return true;
281}
bool AddIntersectTs(SkOpContour *test, SkOpContour *next, SkOpCoincidence *coincidence)
bool SortContourList(SkOpContourHead **contourList, bool evenOdd, bool oppEvenOdd)
bool HandleCoincidence(SkOpContourHead *contourList, SkOpCoincidence *coincidence)
static bool bridgeWinding(SkOpContourHead *contourList, SkPathWriter *writer)
static bool bridgeXor(SkOpContourHead *contourList, SkPathWriter *writer)
static bool path_is_trivial(const SkPath &path)
@ kWinding_PathOpsMask
SkPathFillType
Definition: SkPathTypes.h:11
SkOpContour * next()
Definition: SkOpContour.h:266