Flutter Engine
The Flutter Engine
Functions
SkPathOpsCommon.cpp File Reference
#include "src/pathops/SkPathOpsCommon.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkMacros.h"
#include "include/private/base/SkMath.h"
#include "include/private/base/SkTDArray.h"
#include "src/base/SkTSort.h"
#include "src/pathops/SkOpAngle.h"
#include "src/pathops/SkOpCoincidence.h"
#include "src/pathops/SkOpContour.h"
#include "src/pathops/SkOpSegment.h"
#include "src/pathops/SkOpSpan.h"

Go to the source code of this file.

Functions

const SkOpAngleAngleWinding (SkOpSpanBase *start, SkOpSpanBase *end, int *windingPtr, bool *sortablePtr)
 
SkOpSpanFindUndone (SkOpContourHead *contourHead)
 
SkOpSegmentFindChase (SkTDArray< SkOpSpanBase * > *chase, SkOpSpanBase **startPtr, SkOpSpanBase **endPtr)
 
bool SortContourList (SkOpContourHead **contourList, bool evenOdd, bool oppEvenOdd)
 
static void calc_angles (SkOpContourHead *contourList DEBUG_COIN_DECLARE_PARAMS())
 
static bool missing_coincidence (SkOpContourHead *contourList DEBUG_COIN_DECLARE_PARAMS())
 
static bool move_multiples (SkOpContourHead *contourList DEBUG_COIN_DECLARE_PARAMS())
 
static bool move_nearby (SkOpContourHead *contourList DEBUG_COIN_DECLARE_PARAMS())
 
static bool sort_angles (SkOpContourHead *contourList)
 
bool HandleCoincidence (SkOpContourHead *contourList, SkOpCoincidence *coincidence)
 

Function Documentation

◆ AngleWinding()

const SkOpAngle * AngleWinding ( SkOpSpanBase start,
SkOpSpanBase end,
int windingPtr,
bool *  sortablePtr 
)

Definition at line 21 of file SkPathOpsCommon.cpp.

22 {
23 // find first angle, initialize winding to computed fWindSum
24 SkOpSegment* segment = start->segment();
25 const SkOpAngle* angle = segment->spanToAngle(start, end);
26 if (!angle) {
27 *windingPtr = SK_MinS32;
28 return nullptr;
29 }
30 bool computeWinding = false;
31 const SkOpAngle* firstAngle = angle;
32 bool loop = false;
33 bool unorderable = false;
34 int winding = SK_MinS32;
35 do {
36 angle = angle->next();
37 if (!angle) {
38 return nullptr;
39 }
40 unorderable |= angle->unorderable();
41 if ((computeWinding = unorderable || (angle == firstAngle && loop))) {
42 break; // if we get here, there's no winding, loop is unorderable
43 }
44 loop |= angle == firstAngle;
45 segment = angle->segment();
46 winding = segment->windSum(angle);
47 } while (winding == SK_MinS32);
48 // if the angle loop contains an unorderable span, the angle order may be useless
49 // directly compute the winding in this case for each span
50 if (computeWinding) {
51 firstAngle = angle;
52 winding = SK_MinS32;
53 do {
54 SkOpSpanBase* startSpan = angle->start();
55 SkOpSpanBase* endSpan = angle->end();
56 SkOpSpan* lesser = startSpan->starter(endSpan);
57 int testWinding = lesser->windSum();
58 if (testWinding == SK_MinS32) {
59 testWinding = lesser->computeWindSum();
60 }
61 if (testWinding != SK_MinS32) {
62 segment = angle->segment();
63 winding = testWinding;
64 }
65 angle = angle->next();
66 } while (angle != firstAngle);
67 }
68 *sortablePtr = !unorderable;
69 *windingPtr = winding;
70 return angle;
71}
static constexpr int32_t SK_MinS32
Definition: SkMath.h:22
bool unorderable() const
Definition: SkOpAngle.h:104
SkOpSegment * segment() const
Definition: SkOpAngle.cpp:969
SkOpSpanBase * end() const
Definition: SkOpAngle.h:73
SkOpAngle * next() const
Definition: SkOpAngle.h:82
SkOpSpanBase * start() const
Definition: SkOpAngle.h:94
int windSum(const SkOpAngle *angle) const
SkOpAngle * spanToAngle(SkOpSpanBase *start, SkOpSpanBase *end)
Definition: SkOpSegment.h:391
const SkOpSpan * starter(const SkOpSpanBase *end) const
Definition: SkOpSpan.h:347
int windSum() const
Definition: SkOpSpan.h:555
int computeWindSum()
Definition: SkOpSpan.cpp:378
glong glong end

◆ calc_angles()

static void calc_angles ( SkOpContourHead *contourList   DEBUG_COIN_DECLARE_PARAMS())
static

Definition at line 188 of file SkPathOpsCommon.cpp.

188 {
189 DEBUG_STATIC_SET_PHASE(contourList);
190 SkOpContour* contour = contourList;
191 do {
192 contour->calcAngles();
193 } while ((contour = contour->next()));
194}
#define DEBUG_STATIC_SET_PHASE(obj)

◆ FindChase()

SkOpSegment * FindChase ( SkTDArray< SkOpSpanBase * > *  chase,
SkOpSpanBase **  startPtr,
SkOpSpanBase **  endPtr 
)

Definition at line 87 of file SkPathOpsCommon.cpp.

88 {
89 while (!chase->empty()) {
90 SkOpSpanBase* span = chase->back();
91 chase->pop_back();
92 SkOpSegment* segment = span->segment();
93 *startPtr = span->ptT()->next()->span();
94 bool done = true;
95 *endPtr = nullptr;
96 if (SkOpAngle* last = segment->activeAngle(*startPtr, startPtr, endPtr, &done)) {
97 *startPtr = last->start();
98 *endPtr = last->end();
99 #if TRY_ROTATE
100 *chase->insert(0) = span;
101 #else
102 *chase->append() = span;
103 #endif
104 return last->segment();
105 }
106 if (done) {
107 continue;
108 }
109 // find first angle, initialize winding to computed wind sum
110 int winding;
111 bool sortable;
112 const SkOpAngle* angle = AngleWinding(*startPtr, *endPtr, &winding, &sortable);
113 if (!angle) {
114 return nullptr;
115 }
116 if (winding == SK_MinS32) {
117 continue;
118 }
119 int sumWinding SK_INIT_TO_AVOID_WARNING;
120 if (sortable) {
121 segment = angle->segment();
122 sumWinding = segment->updateWindingReverse(angle);
123 }
124 SkOpSegment* first = nullptr;
125 const SkOpAngle* firstAngle = angle;
126 while ((angle = angle->next()) != firstAngle) {
127 segment = angle->segment();
128 SkOpSpanBase* start = angle->start();
129 SkOpSpanBase* end = angle->end();
130 int maxWinding SK_INIT_TO_AVOID_WARNING;
131 if (sortable) {
132 segment->setUpWinding(start, end, &maxWinding, &sumWinding);
133 }
134 if (!segment->done(angle)) {
135 if (!first && (sortable || start->starter(end)->windSum() != SK_MinS32)) {
136 first = segment;
137 *startPtr = start;
138 *endPtr = end;
139 }
140 // OPTIMIZATION: should this also add to the chase?
141 if (sortable) {
142 // TODO: add error handling
143 SkAssertResult(segment->markAngle(maxWinding, sumWinding, angle, nullptr));
144 }
145 }
146 }
147 if (first) {
148 #if TRY_ROTATE
149 *chase->insert(0) = span;
150 #else
151 *chase->append() = span;
152 #endif
153 return first;
154 }
155 }
156 return nullptr;
157}
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
Definition: DM.cpp:263
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
#define SK_INIT_TO_AVOID_WARNING
Definition: SkMacros.h:58
const SkOpAngle * AngleWinding(SkOpSpanBase *start, SkOpSpanBase *end, int *windingPtr, bool *sortablePtr)
const SkOpSpanBase * span() const
Definition: SkOpSpan.h:154
const SkOpPtT * next() const
Definition: SkOpSpan.h:93
bool done() const
Definition: SkOpSegment.h:200
int updateWindingReverse(const SkOpAngle *angle)
void setUpWinding(SkOpSpanBase *start, SkOpSpanBase *end, int *maxWinding, int *sumWinding)
Definition: SkOpSegment.h:369
SkOpAngle * activeAngle(SkOpSpanBase *start, SkOpSpanBase **startPtr, SkOpSpanBase **endPtr, bool *done)
Definition: SkOpSegment.cpp:54
bool markAngle(int maxWinding, int sumWinding, const SkOpAngle *angle, SkOpSpanBase **result)
SkOpSegment * segment() const
Definition: SkOpSpan.h:318
const SkOpPtT * ptT() const
Definition: SkOpSpan.h:310
const T & back() const
Definition: SkTDArray.h:162
bool empty() const
Definition: SkTDArray.h:135
T * append()
Definition: SkTDArray.h:191
T * insert(int index)
Definition: SkTDArray.h:203
void pop_back()
Definition: SkTDArray.h:223

◆ FindUndone()

SkOpSpan * FindUndone ( SkOpContourHead contourHead)

Definition at line 73 of file SkPathOpsCommon.cpp.

73 {
74 SkOpContour* contour = contourHead;
75 do {
76 if (contour->done()) {
77 continue;
78 }
79 SkOpSpan* result = contour->undoneSpan();
80 if (result) {
81 return result;
82 }
83 } while ((contour = contour->next()));
84 return nullptr;
85}
GAsyncResult * result

◆ HandleCoincidence()

bool HandleCoincidence ( SkOpContourHead contourList,
SkOpCoincidence coincidence 
)

Definition at line 238 of file SkPathOpsCommon.cpp.

238 {
239 SkOpGlobalState* globalState = contourList->globalState();
240 // match up points within the coincident runs
241 if (!coincidence->addExpanded(DEBUG_PHASE_ONLY_PARAMS(kIntersecting))) {
242 return false;
243 }
244 // combine t values when multiple intersections occur on some segments but not others
245 if (!move_multiples(contourList DEBUG_PHASE_PARAMS(kWalking))) {
246 return false;
247 }
248 // move t values and points together to eliminate small/tiny gaps
249 if (!move_nearby(contourList DEBUG_COIN_PARAMS())) {
250 return false;
251 }
252 // add coincidence formed by pairing on curve points and endpoints
253 coincidence->correctEnds(DEBUG_PHASE_ONLY_PARAMS(kIntersecting));
254 if (!coincidence->addEndMovedSpans(DEBUG_COIN_ONLY_PARAMS())) {
255 return false;
256 }
257 const int SAFETY_COUNT = 3;
258 int safetyHatch = SAFETY_COUNT;
259 // look for coincidence present in A-B and A-C but missing in B-C
260 do {
261 bool added;
262 if (!coincidence->addMissing(&added DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch))) {
263 return false;
264 }
265 if (!added) {
266 break;
267 }
268 if (!--safetyHatch) {
269 SkASSERT(globalState->debugSkipAssert());
270 return false;
271 }
272 move_nearby(contourList DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch - 1));
273 } while (true);
274 // check to see if, loosely, coincident ranges may be expanded
275 if (coincidence->expand(DEBUG_COIN_ONLY_PARAMS())) {
276 bool added;
277 if (!coincidence->addMissing(&added DEBUG_COIN_PARAMS())) {
278 return false;
279 }
280 if (!coincidence->addExpanded(DEBUG_COIN_ONLY_PARAMS())) {
281 return false;
282 }
283 if (!move_multiples(contourList DEBUG_COIN_PARAMS())) {
284 return false;
285 }
286 move_nearby(contourList DEBUG_COIN_PARAMS());
287 }
288 // the expanded ranges may not align -- add the missing spans
289 if (!coincidence->addExpanded(DEBUG_PHASE_ONLY_PARAMS(kWalking))) {
290 return false;
291 }
292 // mark spans of coincident segments as coincident
293 coincidence->mark(DEBUG_COIN_ONLY_PARAMS());
294 // look for coincidence lines and curves undetected by intersection
295 if (missing_coincidence(contourList DEBUG_COIN_PARAMS())) {
296 (void) coincidence->expand(DEBUG_PHASE_ONLY_PARAMS(kIntersecting));
297 if (!coincidence->addExpanded(DEBUG_COIN_ONLY_PARAMS())) {
298 return false;
299 }
300 if (!coincidence->mark(DEBUG_PHASE_ONLY_PARAMS(kWalking))) {
301 return false;
302 }
303 } else {
304 (void) coincidence->expand(DEBUG_COIN_ONLY_PARAMS());
305 }
306 (void) coincidence->expand(DEBUG_COIN_ONLY_PARAMS());
307
308 SkOpCoincidence overlaps(globalState);
309 safetyHatch = SAFETY_COUNT;
310 do {
311 SkOpCoincidence* pairs = overlaps.isEmpty() ? coincidence : &overlaps;
312 // adjust the winding value to account for coincident edges
313 if (!pairs->apply(DEBUG_ITER_ONLY_PARAMS(SAFETY_COUNT - safetyHatch))) {
314 return false;
315 }
316 // For each coincident pair that overlaps another, when the receivers (the 1st of the pair)
317 // are different, construct a new pair to resolve their mutual span
318 if (!pairs->findOverlaps(&overlaps DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch))) {
319 return false;
320 }
321 if (!--safetyHatch) {
322 SkASSERT(globalState->debugSkipAssert());
323 return false;
324 }
325 } while (!overlaps.isEmpty());
326 calc_angles(contourList DEBUG_COIN_PARAMS());
327 if (!sort_angles(contourList)) {
328 return false;
329 }
330#if DEBUG_COINCIDENCE_VERBOSE
331 coincidence->debugShowCoincidence();
332#endif
333#if DEBUG_COINCIDENCE
334 coincidence->debugValidate();
335#endif
337 return true;
338}
#define SkASSERT(cond)
Definition: SkAssert.h:116
static void calc_angles(SkOpContourHead *contourList DEBUG_COIN_DECLARE_PARAMS())
static bool move_nearby(SkOpContourHead *contourList DEBUG_COIN_DECLARE_PARAMS())
static bool sort_angles(SkOpContourHead *contourList)
static bool missing_coincidence(SkOpContourHead *contourList DEBUG_COIN_DECLARE_PARAMS())
static bool move_multiples(SkOpContourHead *contourList DEBUG_COIN_DECLARE_PARAMS())
#define DEBUG_PHASE_ONLY_PARAMS(phase)
#define DEBUG_PHASE_PARAMS(phase)
#define DEBUG_ITER_PARAMS(iteration)
#define DEBUG_ITER_ONLY_PARAMS(iteration)
#define DEBUG_COIN_ONLY_PARAMS()
#define DEBUG_COIN_PARAMS()
bool addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS())
bool addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS())
bool apply(DEBUG_COIN_DECLARE_ONLY_PARAMS())
void debugShowCoincidence() const
bool addMissing(bool *added DEBUG_COIN_DECLARE_PARAMS())
void correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS())
bool isEmpty() const
bool findOverlaps(SkOpCoincidence *DEBUG_COIN_DECLARE_PARAMS()) const
bool expand(DEBUG_COIN_DECLARE_ONLY_PARAMS())
bool mark(DEBUG_COIN_DECLARE_ONLY_PARAMS())
void debugValidate() const
SkOpGlobalState * globalState() const
Definition: SkOpContour.h:139
static void ShowActiveSpans(SkOpContourHead *contourList)

◆ missing_coincidence()

static bool missing_coincidence ( SkOpContourHead *contourList   DEBUG_COIN_DECLARE_PARAMS())
static

Definition at line 196 of file SkPathOpsCommon.cpp.

196 {
197 DEBUG_STATIC_SET_PHASE(contourList);
198 SkOpContour* contour = contourList;
199 bool result = false;
200 do {
201 result |= contour->missingCoincidence();
202 } while ((contour = contour->next()));
203 return result;
204}

◆ move_multiples()

static bool move_multiples ( SkOpContourHead *contourList   DEBUG_COIN_DECLARE_PARAMS())
static

Definition at line 206 of file SkPathOpsCommon.cpp.

206 {
207 DEBUG_STATIC_SET_PHASE(contourList);
208 SkOpContour* contour = contourList;
209 do {
210 if (!contour->moveMultiples()) {
211 return false;
212 }
213 } while ((contour = contour->next()));
214 return true;
215}

◆ move_nearby()

static bool move_nearby ( SkOpContourHead *contourList   DEBUG_COIN_DECLARE_PARAMS())
static

Definition at line 217 of file SkPathOpsCommon.cpp.

217 {
218 DEBUG_STATIC_SET_PHASE(contourList);
219 SkOpContour* contour = contourList;
220 do {
221 if (!contour->moveNearby()) {
222 return false;
223 }
224 } while ((contour = contour->next()));
225 return true;
226}

◆ sort_angles()

static bool sort_angles ( SkOpContourHead contourList)
static

Definition at line 228 of file SkPathOpsCommon.cpp.

228 {
229 SkOpContour* contour = contourList;
230 do {
231 if (!contour->sortAngles()) {
232 return false;
233 }
234 } while ((contour = contour->next()));
235 return true;
236}

◆ SortContourList()

bool SortContourList ( SkOpContourHead **  contourList,
bool  evenOdd,
bool  oppEvenOdd 
)

Definition at line 159 of file SkPathOpsCommon.cpp.

159 {
161 SkOpContour* contour = *contourList;
162 do {
163 if (contour->count()) {
164 contour->setOppXor(contour->operand() ? evenOdd : oppEvenOdd);
165 *list.append() = contour;
166 }
167 } while ((contour = contour->next()));
168 int count = list.size();
169 if (!count) {
170 return false;
171 }
172 if (count > 1) {
173 SkTQSort<SkOpContour>(list.begin(), list.end());
174 }
175 contour = list[0];
176 SkOpContourHead* contourHead = static_cast<SkOpContourHead*>(contour);
177 contour->globalState()->setContourHead(contourHead);
178 *contourList = contourHead;
179 for (int index = 1; index < count; ++index) {
180 SkOpContour* next = list[index];
181 contour->setNext(next);
182 contour = next;
183 }
184 contour->setNext(nullptr);
185 return true;
186}
int count
Definition: FontMgrTest.cpp:50
static float next(float f)
T * end()
Definition: SkTDArray.h:152
int size() const
Definition: SkTDArray.h:138
T * begin()
Definition: SkTDArray.h:150