Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(188)

Side by Side Diff: src/pathops/SkOpContour.h

Issue 1037573004: cumulative pathops patch (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: fix pathopsinverse gm Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/pathops/SkOpCoincidence.cpp ('k') | src/pathops/SkOpContour.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2013 Google Inc. 2 * Copyright 2013 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 #ifndef SkOpContour_DEFINED 7 #ifndef SkOpContour_DEFINED
8 #define SkOpContour_DEFINED 8 #define SkOpContour_DEFINED
9 9
10 #include "SkOpSegment.h" 10 #include "SkOpSegment.h"
11 #include "SkTArray.h" 11 #include "SkTDArray.h"
12 #include "SkTSort.h"
12 13
13 #if defined(SK_DEBUG) || !FORCE_RELEASE 14 class SkChunkAlloc;
14 #include "SkThread.h"
15 #endif
16
17 class SkIntersections;
18 class SkOpContour;
19 class SkPathWriter; 15 class SkPathWriter;
20 16
21 struct SkCoincidence {
22 SkOpContour* fOther;
23 int fSegments[2];
24 double fTs[2][2];
25 SkPoint fPts[2][2];
26 int fNearly[2];
27 };
28
29 class SkOpContour { 17 class SkOpContour {
30 public: 18 public:
31 SkOpContour() { 19 SkOpContour() {
32 reset(); 20 reset();
33 #if defined(SK_DEBUG) || !FORCE_RELEASE 21 }
34 fID = sk_atomic_inc(&SkPathOpsDebug::gContourID); 22
35 #endif 23 ~SkOpContour() {
24 if (fNext) {
25 fNext->~SkOpContour();
26 }
36 } 27 }
37 28
38 bool operator<(const SkOpContour& rh) const { 29 bool operator<(const SkOpContour& rh) const {
39 return fBounds.fTop == rh.fBounds.fTop 30 return fBounds.fTop == rh.fBounds.fTop
40 ? fBounds.fLeft < rh.fBounds.fLeft 31 ? fBounds.fLeft < rh.fBounds.fLeft
41 : fBounds.fTop < rh.fBounds.fTop; 32 : fBounds.fTop < rh.fBounds.fTop;
42 } 33 }
43 34
44 bool addCoincident(int index, SkOpContour* other, int otherIndex, 35 void addCubic(SkPoint pts[4], SkChunkAlloc* allocator) {
45 const SkIntersections& ts, bool swap); 36 appendSegment(allocator).addCubic(pts, this);
46 void addCoincidentPoints(); 37 }
47 38
48 void addCross(const SkOpContour* crosser) { 39 void addCurve(SkPath::Verb verb, const SkPoint pts[4], SkChunkAlloc* allocat or);
49 #ifdef DEBUG_CROSS 40
50 for (int index = 0; index < fCrosses.count(); ++index) { 41 void addLine(SkPoint pts[2], SkChunkAlloc* allocator) {
51 SkASSERT(fCrosses[index] != crosser); 42 appendSegment(allocator).addLine(pts, this);
52 } 43 }
53 #endif 44
54 fCrosses.push_back(crosser); 45 void addQuad(SkPoint pts[3], SkChunkAlloc* allocator) {
55 } 46 appendSegment(allocator).addQuad(pts, this);
56 47 }
57 void addCubic(const SkPoint pts[4]) { 48
58 fSegments.push_back().addCubic(pts, fOperand, fXor); 49 void align() {
59 fContainsCurves = fContainsCubics = true; 50 SkASSERT(fCount > 0);
60 } 51 SkOpSegment* segment = &fHead;
61 52 do {
62 int addLine(const SkPoint pts[2]) { 53 segment->align();
63 fSegments.push_back().addLine(pts, fOperand, fXor); 54 } while ((segment = segment->next()));
64 return fSegments.count(); 55 }
65 } 56
66 57 SkOpSegment& appendSegment(SkChunkAlloc* allocator) {
67 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) { 58 SkOpSegment* result = fCount++
68 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex); 59 ? SkOpTAllocator<SkOpSegment>::Allocate(allocator) : &fHead;
69 } 60 result->setPrev(fTail);
70 61 if (fTail) {
71 bool addPartialCoincident(int index, SkOpContour* other, int otherIndex, 62 fTail->setNext(result);
72 const SkIntersections& ts, int ptIndex, bool swap); 63 }
73 64 fTail = result;
74 int addQuad(const SkPoint pts[3]) { 65 return *result;
75 fSegments.push_back().addQuad(pts, fOperand, fXor); 66 }
76 fContainsCurves = true; 67
77 return fSegments.count(); 68 SkOpContour* appendContour(SkChunkAlloc* allocator) {
78 } 69 SkOpContour* contour = SkOpTAllocator<SkOpContour>::New(allocator);
79 70 contour->setNext(NULL);
80 int addT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt , double newT) { 71 SkOpContour* prev = this;
81 setContainsIntercepts(); 72 SkOpContour* next;
82 return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT) ; 73 while ((next = prev->next())) {
83 } 74 prev = next;
84 75 }
85 int addSelfT(int segIndex, const SkPoint& pt, double newT) { 76 prev->setNext(contour);
86 setContainsIntercepts(); 77 return contour;
87 return fSegments[segIndex].addSelfT(pt, newT); 78 }
88 } 79
89
90 void align(const SkOpSegment::AlignedSpan& aligned, bool swap, SkCoincidence * coincidence);
91 void alignCoincidence(const SkOpSegment::AlignedSpan& aligned,
92 SkTArray<SkCoincidence, true>* coincidences);
93
94 void alignCoincidence(const SkOpSegment::AlignedSpan& aligned) {
95 alignCoincidence(aligned, &fCoincidences);
96 alignCoincidence(aligned, &fPartialCoincidences);
97 }
98
99 void alignMultiples(SkTDArray<SkOpSegment::AlignedSpan>* aligned) {
100 int segmentCount = fSegments.count();
101 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
102 SkOpSegment& segment = fSegments[sIndex];
103 if (segment.hasMultiples()) {
104 segment.alignMultiples(aligned);
105 }
106 }
107 }
108
109 void alignTPt(int segmentIndex, const SkOpContour* other, int otherIndex,
110 bool swap, int tIndex, SkIntersections* ts, SkPoint* point) co nst;
111
112 const SkPathOpsBounds& bounds() const { 80 const SkPathOpsBounds& bounds() const {
113 return fBounds; 81 return fBounds;
114 } 82 }
115 83
116 bool calcAngles(); 84 void calcAngles(SkChunkAlloc* allocator) {
117 bool calcCoincidentWinding(); 85 SkASSERT(fCount > 0);
118 void calcPartialCoincidentWinding(); 86 SkOpSegment* segment = &fHead;
119 87 do {
120 void checkDuplicates() { 88 segment->calcAngles(allocator);
121 int segmentCount = fSegments.count(); 89 } while ((segment = segment->next()));
122 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { 90 }
123 SkOpSegment& segment = fSegments[sIndex]; 91
124 if (segment.count() > 2) { 92 void complete() {
125 segment.checkDuplicates(); 93 setBounds();
94 }
95
96 int count() const {
97 return fCount;
98 }
99
100 int debugID() const {
101 return PATH_OPS_DEBUG_RELEASE(fID, -1);
102 }
103
104 int debugIndent() const {
105 return PATH_OPS_DEBUG_RELEASE(fIndent, 0);
106 }
107
108 #if DEBUG_ACTIVE_SPANS
109 void debugShowActiveSpans() {
110 SkOpSegment* segment = &fHead;
111 do {
112 segment->debugShowActiveSpans();
113 } while ((segment = segment->next()));
114 }
115 #endif
116
117 const SkOpAngle* debugAngle(int id) const {
118 return PATH_OPS_DEBUG_RELEASE(globalState()->debugAngle(id), NULL);
119 }
120
121 SkOpContour* debugContour(int id) {
122 return PATH_OPS_DEBUG_RELEASE(globalState()->debugContour(id), NULL);
123 }
124
125 const SkOpPtT* debugPtT(int id) const {
126 return PATH_OPS_DEBUG_RELEASE(globalState()->debugPtT(id), NULL);
127 }
128
129 const SkOpSegment* debugSegment(int id) const {
130 return PATH_OPS_DEBUG_RELEASE(globalState()->debugSegment(id), NULL);
131 }
132
133 const SkOpSpanBase* debugSpan(int id) const {
134 return PATH_OPS_DEBUG_RELEASE(globalState()->debugSpan(id), NULL);
135 }
136
137 SkOpGlobalState* globalState() const {
138 return fState;
139 }
140
141 void debugValidate() const {
142 #if DEBUG_VALIDATE
143 const SkOpSegment* segment = &fHead;
144 const SkOpSegment* prior = NULL;
145 do {
146 segment->debugValidate();
147 SkASSERT(segment->prev() == prior);
148 prior = segment;
149 } while ((segment = segment->next()));
150 SkASSERT(prior == fTail);
151 #endif
152 }
153
154 bool done() const {
155 return fDone;
156 }
157
158 void dump();
159 void dumpAll();
160 void dumpAngles() const;
161 void dumpPt(int ) const;
162 void dumpPts() const;
163 void dumpPtsX() const;
164 void dumpSegment(int ) const;
165 void dumpSegments(SkPathOp op) const;
166 void dumpSpan(int ) const;
167 void dumpSpans() const;
168
169 const SkPoint& end() const {
170 return fTail->pts()[SkPathOpsVerbToPoints(fTail->verb())];
171 }
172
173 SkOpSegment* first() {
174 SkASSERT(fCount > 0);
175 return &fHead;
176 }
177
178 const SkOpSegment* first() const {
179 SkASSERT(fCount > 0);
180 return &fHead;
181 }
182
183 void indentDump() {
184 PATH_OPS_DEBUG_CODE(fIndent += 2);
185 }
186
187 void init(SkOpGlobalState* globalState, bool operand, bool isXor) {
188 fState = globalState;
189 fOperand = operand;
190 fXor = isXor;
191 }
192
193 bool isXor() const {
194 return fXor;
195 }
196
197 void missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc* allocat or) {
198 SkASSERT(fCount > 0);
199 SkOpSegment* segment = &fHead;
200 do {
201 if (fState->angleCoincidence()) {
202 segment->checkAngleCoin(coincidences, allocator);
203 } else {
204 segment->missingCoincidence(coincidences, allocator);
126 } 205 }
127 } 206 } while ((segment = segment->next()));
128 } 207 }
129 208
130 bool checkEnds() { 209 bool moveNearby() {
131 if (!fContainsCurves) { 210 SkASSERT(fCount > 0);
132 return true; 211 SkOpSegment* segment = &fHead;
133 } 212 do {
134 int segmentCount = fSegments.count(); 213 if (!segment->moveNearby()) {
135 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
136 SkOpSegment* segment = &fSegments[sIndex];
137 if (segment->verb() == SkPath::kLine_Verb) {
138 continue;
139 }
140 if (segment->done()) {
141 continue; // likely coincident, nothing to do
142 }
143 if (!segment->checkEnds()) {
144 return false; 214 return false;
145 } 215 }
146 } 216 } while ((segment = segment->next()));
147 return true; 217 return true;
148 } 218 }
149 219
150 void checkMultiples() { 220 SkOpContour* next() {
151 int segmentCount = fSegments.count(); 221 return fNext;
152 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { 222 }
153 SkOpSegment& segment = fSegments[sIndex]; 223
154 if (segment.count() > 2) { 224 const SkOpContour* next() const {
155 segment.checkMultiples(); 225 return fNext;
156 fMultiples |= segment.hasMultiples(); 226 }
157 } 227
158 } 228 SkOpSegment* nonVerticalSegment(SkOpSpanBase** start, SkOpSpanBase** end);
159 }
160
161 void checkSmall() {
162 int segmentCount = fSegments.count();
163 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
164 SkOpSegment& segment = fSegments[sIndex];
165 // OPTIMIZATION : skip segments that are done?
166 if (segment.hasSmall()) {
167 segment.checkSmall();
168 }
169 }
170 }
171
172 // if same point has different T values, choose a common T
173 void checkTiny() {
174 int segmentCount = fSegments.count();
175 if (segmentCount <= 2) {
176 return;
177 }
178 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
179 SkOpSegment& segment = fSegments[sIndex];
180 if (segment.hasTiny()) {
181 segment.checkTiny();
182 }
183 }
184 }
185
186 void complete() {
187 setBounds();
188 fContainsIntercepts = false;
189 }
190
191 bool containsCubics() const {
192 return fContainsCubics;
193 }
194
195 bool crosses(const SkOpContour* crosser) const {
196 for (int index = 0; index < fCrosses.count(); ++index) {
197 if (fCrosses[index] == crosser) {
198 return true;
199 }
200 }
201 return false;
202 }
203
204 bool done() const {
205 return fDone;
206 }
207
208 const SkPoint& end() const {
209 const SkOpSegment& segment = fSegments.back();
210 return segment.pts()[SkPathOpsVerbToPoints(segment.verb())];
211 }
212
213 void fixOtherTIndex() {
214 int segmentCount = fSegments.count();
215 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
216 fSegments[sIndex].fixOtherTIndex();
217 }
218 }
219
220 bool hasMultiples() const {
221 return fMultiples;
222 }
223
224 void joinCoincidence() {
225 joinCoincidence(fCoincidences, false);
226 joinCoincidence(fPartialCoincidences, true);
227 }
228
229 SkOpSegment* nonVerticalSegment(int* start, int* end);
230 229
231 bool operand() const { 230 bool operand() const {
232 return fOperand; 231 return fOperand;
233 } 232 }
234 233
234 bool oppXor() const {
235 return fOppXor;
236 }
237
238 void outdentDump() {
239 PATH_OPS_DEBUG_CODE(fIndent -= 2);
240 }
241
242 void remove(SkOpContour* contour) {
243 if (contour == this) {
244 SkASSERT(fCount == 0);
245 return;
246 }
247 SkASSERT(contour->fNext == NULL);
248 SkOpContour* prev = this;
249 SkOpContour* next;
250 while ((next = prev->next()) != contour) {
251 SkASSERT(next);
252 prev = next;
253 }
254 SkASSERT(prev);
255 prev->setNext(NULL);
256 }
257
235 void reset() { 258 void reset() {
236 fSegments.reset(); 259 fTail = NULL;
237 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax); 260 fNext = NULL;
238 fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = fMulti ples = false; 261 fCount = 0;
239 } 262 fDone = false;
240 263 SkDEBUGCODE(fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_Sca larMin));
241 void resolveNearCoincidence(); 264 SkDEBUGCODE(fFirstSorted = -1);
242 265 PATH_OPS_DEBUG_CODE(fIndent = 0);
243 SkTArray<SkOpSegment>& segments() { 266 }
244 return fSegments; 267
245 } 268 void setBounds() {
246 269 SkASSERT(fCount > 0);
247 void setContainsIntercepts() { 270 const SkOpSegment* segment = &fHead;
248 fContainsIntercepts = true; 271 fBounds = segment->bounds();
272 while ((segment = segment->next())) {
273 fBounds.add(segment->bounds());
274 }
275 }
276
277 void setGlobalState(SkOpGlobalState* state) {
278 fState = state;
279 }
280
281 void setNext(SkOpContour* contour) {
282 // SkASSERT(!fNext == !!contour);
283 fNext = contour;
249 } 284 }
250 285
251 void setOperand(bool isOp) { 286 void setOperand(bool isOp) {
252 fOperand = isOp; 287 fOperand = isOp;
253 } 288 }
254 289
255 void setOppXor(bool isOppXor) { 290 void setOppXor(bool isOppXor) {
256 fOppXor = isOppXor; 291 fOppXor = isOppXor;
257 int segmentCount = fSegments.count();
258 for (int test = 0; test < segmentCount; ++test) {
259 fSegments[test].setOppXor(isOppXor);
260 }
261 } 292 }
262 293
263 void setXor(bool isXor) { 294 void setXor(bool isXor) {
264 fXor = isXor; 295 fXor = isXor;
265 } 296 }
266 297
267 void sortAngles(); 298 SkPath::Verb simplifyCubic(SkPoint pts[4]);
268 void sortSegments(); 299
300 void sortAngles() {
301 SkASSERT(fCount > 0);
302 SkOpSegment* segment = &fHead;
303 do {
304 segment->sortAngles();
305 } while ((segment = segment->next()));
306 }
307
308 void sortSegments() {
309 SkOpSegment* segment = &fHead;
310 do {
311 *fSortedSegments.append() = segment;
312 } while ((segment = segment->next()));
313 SkTQSort<SkOpSegment>(fSortedSegments.begin(), fSortedSegments.end() - 1 );
314 fFirstSorted = 0;
315 }
269 316
270 const SkPoint& start() const { 317 const SkPoint& start() const {
271 return fSegments.front().pts()[0]; 318 return fHead.pts()[0];
319 }
320
321 void toPartialBackward(SkPathWriter* path) const {
322 const SkOpSegment* segment = fTail;
323 do {
324 segment->addCurveTo(segment->tail(), segment->head(), path, true);
325 } while ((segment = segment->prev()));
326 }
327
328 void toPartialForward(SkPathWriter* path) const {
329 const SkOpSegment* segment = &fHead;
330 do {
331 segment->addCurveTo(segment->head(), segment->tail(), path, true);
332 } while ((segment = segment->next()));
272 } 333 }
273 334
274 void toPath(SkPathWriter* path) const; 335 void toPath(SkPathWriter* path) const;
275
276 void toPartialBackward(SkPathWriter* path) const {
277 int segmentCount = fSegments.count();
278 for (int test = segmentCount - 1; test >= 0; --test) {
279 fSegments[test].addCurveTo(1, 0, path, true);
280 }
281 }
282
283 void toPartialForward(SkPathWriter* path) const {
284 int segmentCount = fSegments.count();
285 for (int test = 0; test < segmentCount; ++test) {
286 fSegments[test].addCurveTo(0, 1, path, true);
287 }
288 }
289
290 void topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, SkOpSegment ** topStart); 336 void topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, SkOpSegment ** topStart);
291 SkOpSegment* undoneSegment(int* start, int* end); 337 SkOpSegment* undoneSegment(SkOpSpanBase** startPtr, SkOpSpanBase** endPtr);
292
293 int updateSegment(int index, const SkPoint* pts) {
294 SkOpSegment& segment = fSegments[index];
295 segment.updatePts(pts);
296 return SkPathOpsVerbToPoints(segment.verb()) + 1;
297 }
298
299 #if DEBUG_TEST
300 SkTArray<SkOpSegment>& debugSegments() {
301 return fSegments;
302 }
303 #endif
304
305 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
306 void debugShowActiveSpans() {
307 for (int index = 0; index < fSegments.count(); ++index) {
308 fSegments[index].debugShowActiveSpans();
309 }
310 }
311 #endif
312
313 #if DEBUG_SHOW_WINDING
314 int debugShowWindingValues(int totalSegments, int ofInterest);
315 static void debugShowWindingValues(const SkTArray<SkOpContour*, true>& conto urList);
316 #endif
317
318 // available to test routines only
319 void dump() const;
320 void dumpAngles() const;
321 void dumpCoincidence(const SkCoincidence& ) const;
322 void dumpCoincidences() const;
323 void dumpPt(int ) const;
324 void dumpPts() const;
325 void dumpSpan(int ) const;
326 void dumpSpans() const;
327 338
328 private: 339 private:
329 void alignPt(int index, SkPoint* point, int zeroPt) const; 340 SkOpGlobalState* fState;
330 int alignT(bool swap, int tIndex, SkIntersections* ts) const; 341 SkOpSegment fHead;
331 bool calcCommonCoincidentWinding(const SkCoincidence& ); 342 SkOpSegment* fTail;
332 void checkCoincidentPair(const SkCoincidence& oneCoin, int oneIdx, 343 SkOpContour* fNext;
333 const SkCoincidence& twoCoin, int twoIdx, bool part ial); 344 SkTDArray<SkOpSegment*> fSortedSegments; // set by find top segment
334 void joinCoincidence(const SkTArray<SkCoincidence, true>& , bool partial); 345 SkPathOpsBounds fBounds;
335 void setBounds(); 346 int fCount;
336
337 SkTArray<SkOpSegment> fSegments;
338 SkTArray<SkOpSegment*, true> fSortedSegments;
339 int fFirstSorted; 347 int fFirstSorted;
340 SkTArray<SkCoincidence, true> fCoincidences; 348 bool fDone; // set by find top segment
341 SkTArray<SkCoincidence, true> fPartialCoincidences;
342 SkTArray<const SkOpContour*, true> fCrosses;
343 SkPathOpsBounds fBounds;
344 bool fContainsIntercepts; // FIXME: is this used by anybody?
345 bool fContainsCubics;
346 bool fContainsCurves;
347 bool fDone;
348 bool fMultiples; // set if some segment has multiple identical intersection s with other curves
349 bool fOperand; // true for the second argument to a binary operator 349 bool fOperand; // true for the second argument to a binary operator
350 bool fXor; 350 bool fXor; // set if original path had even-odd fill
351 bool fOppXor; 351 bool fOppXor; // set if opposite path had even-odd fill
352 #if defined(SK_DEBUG) || !FORCE_RELEASE 352 PATH_OPS_DEBUG_CODE(int fID);
353 int debugID() const { return fID; } 353 PATH_OPS_DEBUG_CODE(int fIndent);
354 int fID;
355 #else
356 int debugID() const { return -1; }
357 #endif
358 }; 354 };
359 355
360 #endif 356 #endif
OLDNEW
« no previous file with comments | « src/pathops/SkOpCoincidence.cpp ('k') | src/pathops/SkOpContour.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698