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

Side by Side Diff: src/pathops/SkPathOpsSimplify.cpp

Issue 1037573004: cumulative pathops patch (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: fix pathopsinverse gm Created 5 years, 8 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/SkPathOpsRect.cpp ('k') | src/pathops/SkPathOpsTCubicSect.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 2012 Google Inc. 2 * Copyright 2012 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 #include "SkAddIntersections.h" 7 #include "SkAddIntersections.h"
8 #include "SkOpCoincidence.h"
8 #include "SkOpEdgeBuilder.h" 9 #include "SkOpEdgeBuilder.h"
9 #include "SkPathOpsCommon.h" 10 #include "SkPathOpsCommon.h"
10 #include "SkPathWriter.h" 11 #include "SkPathWriter.h"
11 12
12 static bool bridgeWinding(SkTArray<SkOpContour*, true>& contourList, SkPathWrite r* simple) { 13 static bool bridgeWinding(SkTDArray<SkOpContour* >& contourList, SkPathWriter* s imple,
14 SkChunkAlloc* allocator) {
13 bool firstContour = true; 15 bool firstContour = true;
14 bool unsortable = false; 16 bool unsortable = false;
15 bool topUnsortable = false; 17 bool topUnsortable = false;
16 bool firstPass = true; 18 bool firstPass = true;
17 SkPoint lastTopLeft; 19 SkPoint lastTopLeft;
18 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin}; 20 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
19 do { 21 do {
20 int index, endIndex; 22 SkOpSpanBase* start;
23 SkOpSpanBase* end;
21 bool topDone; 24 bool topDone;
22 bool onlyVertical = false; 25 bool onlyVertical = false;
23 lastTopLeft = topLeft; 26 lastTopLeft = topLeft;
24 SkOpSegment* current = FindSortableTop(contourList, SkOpAngle::kUnaryWin ding, &firstContour, 27 SkOpSegment* current = FindSortableTop(contourList, firstPass, SkOpAngle ::kUnaryWinding,
25 &index, &endIndex, &topLeft, &topUnsortable, &topDone, &onlyVert ical, firstPass); 28 &firstContour, &start, &end, &topLeft, &topUnsortable, &topDone, &onlyVertical,
29 allocator);
26 if (!current) { 30 if (!current) {
27 if ((!topUnsortable || firstPass) && !topDone) { 31 if ((!topUnsortable || firstPass) && !topDone) {
28 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMi n); 32 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMi n);
33 if (lastTopLeft.fX == SK_ScalarMin && lastTopLeft.fY == SK_Scala rMin) {
34 if (firstPass) {
35 firstPass = false;
36 } else {
37 break;
38 }
39 }
29 topLeft.fX = topLeft.fY = SK_ScalarMin; 40 topLeft.fX = topLeft.fY = SK_ScalarMin;
30 continue; 41 continue;
31 } 42 }
32 break; 43 break;
33 } else if (onlyVertical) { 44 } else if (onlyVertical) {
34 break; 45 break;
35 } 46 }
36 firstPass = !topUnsortable || lastTopLeft != topLeft; 47 firstPass = !topUnsortable || lastTopLeft != topLeft;
37 SkTDArray<SkOpSpan*> chase; 48 SkTDArray<SkOpSpanBase*> chase;
38 do { 49 do {
39 if (current->activeWinding(index, endIndex)) { 50 if (current->activeWinding(start, end)) {
40 do { 51 do {
41 if (!unsortable && current->done()) { 52 if (!unsortable && current->done()) {
42 break; 53 break;
43 } 54 }
44 SkASSERT(unsortable || !current->done()); 55 SkASSERT(unsortable || !current->done());
45 int nextStart = index; 56 SkOpSpanBase* nextStart = start;
46 int nextEnd = endIndex; 57 SkOpSpanBase* nextEnd = end;
47 SkOpSegment* next = current->findNextWinding(&chase, &nextSt art, &nextEnd, 58 SkOpSegment* next = current->findNextWinding(&chase, &nextSt art, &nextEnd,
48 &unsortable); 59 &unsortable);
49 if (!next) { 60 if (!next) {
50 if (!unsortable && simple->hasMove() 61 if (!unsortable && simple->hasMove()
51 && current->verb() != SkPath::kLine_Verb 62 && current->verb() != SkPath::kLine_Verb
52 && !simple->isClosed()) { 63 && !simple->isClosed()) {
53 current->addCurveTo(index, endIndex, simple, true); 64 current->addCurveTo(start, end, simple, true);
54 SkASSERT(simple->isClosed()); 65 #if DEBUG_ACTIVE_SPANS
66 if (!simple->isClosed()) {
67 DebugShowActiveSpans(contourList);
68 }
69 #endif
55 } 70 }
56 break; 71 break;
57 } 72 }
58 #if DEBUG_FLOW 73 #if DEBUG_FLOW
59 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", _ _FUNCTION__, 74 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", _ _FUNCTION__,
60 current->debugID(), current->xyAtT(index).fX, current->xyAtT (index).fY, 75 current->debugID(), start->pt().fX, start->pt().fY,
61 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY); 76 end->pt().fX, end->pt().fY);
62 #endif 77 #endif
63 current->addCurveTo(index, endIndex, simple, true); 78 current->addCurveTo(start, end, simple, true);
64 current = next; 79 current = next;
65 index = nextStart; 80 start = nextStart;
66 endIndex = nextEnd; 81 end = nextEnd;
67 } while (!simple->isClosed() && (!unsortable 82 } while (!simple->isClosed() && (!unsortable || !start->starter( end)->done()));
68 || !current->done(SkMin32(index, endIndex)))); 83 if (current->activeWinding(start, end) && !simple->isClosed()) {
69 if (current->activeWinding(index, endIndex) && !simple->isClosed ()) { 84 SkOpSpan* spanStart = start->starter(end);
70 // SkASSERT(unsortable || simple->isEmpty()); 85 if (!spanStart->done()) {
71 int min = SkMin32(index, endIndex); 86 current->addCurveTo(start, end, simple, true);
72 if (!current->done(min)) { 87 current->markDone(spanStart);
73 current->addCurveTo(index, endIndex, simple, true);
74 current->markDoneUnary(min);
75 } 88 }
76 } 89 }
77 simple->close(); 90 simple->close();
78 } else { 91 } else {
79 SkOpSpan* last = current->markAndChaseDoneUnary(index, endIndex) ; 92 SkOpSpanBase* last = current->markAndChaseDone(start, end);
80 if (last && !last->fChased && !last->fLoop) { 93 if (last && !last->chased()) {
81 last->fChased = true; 94 last->setChased(true);
82 SkASSERT(!SkPathOpsDebug::ChaseContains(chase, last)); 95 SkASSERT(!SkPathOpsDebug::ChaseContains(chase, last));
83 // assert that last isn't already in array 96 // assert that last isn't already in array
84 *chase.append() = last; 97 *chase.append() = last;
85 #if DEBUG_WINDING 98 #if DEBUG_WINDING
86 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FU NCTION__, 99 SkDebugf("%s chase.append id=%d", __FUNCTION__, last->segmen t()->debugID());
87 last->fOther->span(last->fOtherIndex).fOther->debugI D(), last->fWindSum, 100 if (!last->final()) {
88 last->fSmall); 101 SkDebugf(" windSum=%d", last->upCast()->windSum());
102 }
103 SkDebugf("\n");
89 #endif 104 #endif
90 } 105 }
91 } 106 }
92 current = FindChase(&chase, &index, &endIndex); 107 current = FindChase(&chase, &start, &end);
93 #if DEBUG_ACTIVE_SPANS 108 #if DEBUG_ACTIVE_SPANS
94 DebugShowActiveSpans(contourList); 109 DebugShowActiveSpans(contourList);
95 #endif 110 #endif
96 if (!current) { 111 if (!current) {
97 break; 112 break;
98 } 113 }
99 } while (true); 114 } while (true);
100 } while (true); 115 } while (true);
101 return simple->someAssemblyRequired(); 116 return simple->someAssemblyRequired();
102 } 117 }
103 118
104 // returns true if all edges were processed 119 // returns true if all edges were processed
105 static bool bridgeXor(SkTArray<SkOpContour*, true>& contourList, SkPathWriter* s imple) { 120 static bool bridgeXor(SkTDArray<SkOpContour* >& contourList, SkPathWriter* simpl e,
121 SkChunkAlloc* allocator) {
106 SkOpSegment* current; 122 SkOpSegment* current;
107 int start, end; 123 SkOpSpanBase* start;
124 SkOpSpanBase* end;
108 bool unsortable = false; 125 bool unsortable = false;
109 bool closable = true; 126 bool closable = true;
110 while ((current = FindUndone(contourList, &start, &end))) { 127 while ((current = FindUndone(contourList, &start, &end))) {
111 do { 128 do {
112 #if DEBUG_ACTIVE_SPANS 129 #if DEBUG_ACTIVE_SPANS
113 if (!unsortable && current->done()) { 130 if (!unsortable && current->done()) {
114 DebugShowActiveSpans(contourList); 131 DebugShowActiveSpans(contourList);
115 } 132 }
116 #endif 133 #endif
117 SkASSERT(unsortable || !current->done()); 134 SkASSERT(unsortable || !current->done());
118 int nextStart = start; 135 SkOpSpanBase* nextStart = start;
119 int nextEnd = end; 136 SkOpSpanBase* nextEnd = end;
120 SkOpSegment* next = current->findNextXor(&nextStart, &nextEnd, &unso rtable); 137 SkOpSegment* next = current->findNextXor(&nextStart, &nextEnd, &unso rtable);
121 if (!next) { 138 if (!next) {
122 if (!unsortable && simple->hasMove() 139 if (!unsortable && simple->hasMove()
123 && current->verb() != SkPath::kLine_Verb 140 && current->verb() != SkPath::kLine_Verb
124 && !simple->isClosed()) { 141 && !simple->isClosed()) {
125 current->addCurveTo(start, end, simple, true); 142 current->addCurveTo(start, end, simple, true);
126 SkASSERT(simple->isClosed()); 143 #if DEBUG_ACTIVE_SPANS
144 if (!simple->isClosed()) {
145 DebugShowActiveSpans(contourList);
146 }
147 #endif
127 } 148 }
128 break; 149 break;
129 } 150 }
130 #if DEBUG_FLOW 151 #if DEBUG_FLOW
131 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", _ _FUNCTION__, 152 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", _ _FUNCTION__,
132 current->debugID(), current->xyAtT(start).fX, current->xyAtT (start).fY, 153 current->debugID(), start->pt().fX, start->pt().fY,
133 current->xyAtT(end).fX, current->xyAtT(end).fY); 154 end->pt().fX, end->pt().fY);
134 #endif 155 #endif
135 current->addCurveTo(start, end, simple, true); 156 current->addCurveTo(start, end, simple, true);
136 current = next; 157 current = next;
137 start = nextStart; 158 start = nextStart;
138 end = nextEnd; 159 end = nextEnd;
139 } while (!simple->isClosed() && (!unsortable || !current->done(SkMin32(s tart, end)))); 160 } while (!simple->isClosed() && (!unsortable || !start->starter(end)->do ne()));
140 if (!simple->isClosed()) { 161 if (!simple->isClosed()) {
141 SkASSERT(unsortable); 162 SkASSERT(unsortable);
142 int min = SkMin32(start, end); 163 SkOpSpan* spanStart = start->starter(end);
143 if (!current->done(min)) { 164 if (!spanStart->done()) {
144 current->addCurveTo(start, end, simple, true); 165 current->addCurveTo(start, end, simple, true);
145 current->markDone(min, 1); 166 current->markDone(spanStart);
146 } 167 }
147 closable = false; 168 closable = false;
148 } 169 }
149 simple->close(); 170 simple->close();
150 #if DEBUG_ACTIVE_SPANS 171 #if DEBUG_ACTIVE_SPANS
151 DebugShowActiveSpans(contourList); 172 DebugShowActiveSpans(contourList);
152 #endif 173 #endif
153 } 174 }
154 return closable; 175 return closable;
155 } 176 }
156 177
157 // FIXME : add this as a member of SkPath 178 // FIXME : add this as a member of SkPath
158 bool Simplify(const SkPath& path, SkPath* result) { 179 bool Simplify(const SkPath& path, SkPath* result) {
180 SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune
181 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
182 SkPath::FillType fillType = path.isInverseFillType() ? SkPath::kInverseEvenO dd_FillType
183 : SkPath::kEvenOdd_FillType;
184 if (path.isConvex()) {
185 if (result != &path) {
186 *result = path;
187 }
188 result->setFillType(fillType);
189 return true;
190 }
191 // turn path into list of segments
192 SkOpCoincidence coincidence;
193 SkOpContour contour;
194 SkOpGlobalState globalState(&coincidence PATH_OPS_DEBUG_PARAMS(&contour));
159 #if DEBUG_SORT || DEBUG_SWAP_TOP 195 #if DEBUG_SORT || DEBUG_SWAP_TOP
160 SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault; 196 SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault;
161 #endif 197 #endif
162 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness 198 SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState);
163 SkPath::FillType fillType = path.isInverseFillType() ? SkPath::kInverseEvenO dd_FillType 199 if (!builder.finish(&allocator)) {
164 : SkPath::kEvenOdd_FillType;
165
166 // turn path into list of segments
167 SkTArray<SkOpContour> contours;
168 SkOpEdgeBuilder builder(path, contours);
169 if (!builder.finish()) {
170 return false; 200 return false;
171 } 201 }
172 SkTArray<SkOpContour*, true> contourList; 202 #if !FORCE_RELEASE
173 MakeContourList(contours, contourList, false, false); 203 contour.dumpSegments((SkPathOp) -1);
174 SkOpContour** currentPtr = contourList.begin(); 204 #endif
175 result->reset(); 205 result->reset();
176 result->setFillType(fillType); 206 result->setFillType(fillType);
207 SkTDArray<SkOpContour* > contourList;
208 MakeContourList(&contour, contourList, false, false);
209 SkOpContour** currentPtr = contourList.begin();
177 if (!currentPtr) { 210 if (!currentPtr) {
178 return true; 211 return true;
179 } 212 }
180 SkOpContour** listEnd = contourList.end(); 213 if ((*currentPtr)->count() == 0) {
214 SkASSERT((*currentPtr)->next() == NULL);
215 return true;
216 }
217 SkOpContour** listEnd2 = contourList.end();
181 // find all intersections between segments 218 // find all intersections between segments
182 do { 219 do {
183 SkOpContour** nextPtr = currentPtr; 220 SkOpContour** nextPtr = currentPtr;
184 SkOpContour* current = *currentPtr++; 221 SkOpContour* current = *currentPtr++;
185 if (current->containsCubics()) {
186 AddSelfIntersectTs(current);
187 }
188 SkOpContour* next; 222 SkOpContour* next;
189 do { 223 do {
190 next = *nextPtr++; 224 next = *nextPtr++;
191 } while (AddIntersectTs(current, next) && nextPtr != listEnd); 225 } while (AddIntersectTs(current, next, &coincidence, &allocator) && next Ptr != listEnd2);
192 } while (currentPtr != listEnd); 226 } while (currentPtr != listEnd2);
193 if (!HandleCoincidence(&contourList, 0)) { 227 #if DEBUG_VALIDATE
228 globalState.setPhase(SkOpGlobalState::kWalking);
229 #endif
230 if (!HandleCoincidence(&contourList, &coincidence, &allocator, &globalState) ) {
194 return false; 231 return false;
195 } 232 }
196 // construct closed contours 233 // construct closed contours
197 SkPathWriter simple(*result); 234 SkPathWriter wrapper(*result);
198 if (builder.xorMask() == kWinding_PathOpsMask ? bridgeWinding(contourList, & simple) 235 if (builder.xorMask() == kWinding_PathOpsMask ? bridgeWinding(contourList, & wrapper, &allocator)
199 : !bridgeXor(contourList, &simple)) 236 : !bridgeXor(contourList, &wrapper, &allocator))
200 { // if some edges could not be resolved, assemble remaining fragments 237 { // if some edges could not be resolved, assemble remaining fragments
201 SkPath temp; 238 SkPath temp;
202 temp.setFillType(fillType); 239 temp.setFillType(fillType);
203 SkPathWriter assembled(temp); 240 SkPathWriter assembled(temp);
204 Assemble(simple, &assembled); 241 Assemble(wrapper, &assembled);
205 *result = *assembled.nativePath(); 242 *result = *assembled.nativePath();
206 result->setFillType(fillType); 243 result->setFillType(fillType);
207 } 244 }
208 return true; 245 return true;
209 } 246 }
OLDNEW
« no previous file with comments | « src/pathops/SkPathOpsRect.cpp ('k') | src/pathops/SkPathOpsTCubicSect.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698