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

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

Issue 2128633003: pathops coincidence and security rewrite (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: require resulting t to be between 0 and 1 Created 4 years, 5 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
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 "SkOpCoincidence.h"
9 #include "SkOpEdgeBuilder.h" 9 #include "SkOpEdgeBuilder.h"
10 #include "SkPathOpsCommon.h" 10 #include "SkPathOpsCommon.h"
11 #include "SkPathWriter.h" 11 #include "SkPathWriter.h"
12 12
13 static bool bridgeWinding(SkOpContourHead* contourList, SkPathWriter* simple, 13 static bool bridgeWinding(SkOpContourHead* contourList, SkPathWriter* simple, bo ol* closable) {
14 SkChunkAlloc* allocator, bool* closable) {
15 bool unsortable = false; 14 bool unsortable = false;
16 do { 15 do {
17 SkOpSpan* span = FindSortableTop(contourList); 16 SkOpSpan* span = FindSortableTop(contourList);
18 if (!span) { 17 if (!span) {
19 break; 18 break;
20 } 19 }
21 SkOpSegment* current = span->segment(); 20 SkOpSegment* current = span->segment();
22 SkOpSpanBase* start = span->next(); 21 SkOpSpanBase* start = span->next();
23 SkOpSpanBase* end = span; 22 SkOpSpanBase* end = span;
24 SkTDArray<SkOpSpanBase*> chase; 23 SkTDArray<SkOpSpanBase*> chase;
25 do { 24 do {
26 if (current->activeWinding(start, end)) { 25 if (current->activeWinding(start, end)) {
27 do { 26 do {
28 if (!unsortable && current->done()) { 27 if (!unsortable && current->done()) {
29 break; 28 break;
30 } 29 }
31 SkASSERT(unsortable || !current->done()); 30 SkASSERT(unsortable || !current->done());
32 SkOpSpanBase* nextStart = start; 31 SkOpSpanBase* nextStart = start;
33 SkOpSpanBase* nextEnd = end; 32 SkOpSpanBase* nextEnd = end;
34 SkOpSegment* next = current->findNextWinding(&chase, &nextSt art, &nextEnd, 33 SkOpSegment* next = current->findNextWinding(&chase, &nextSt art, &nextEnd,
35 &unsortable); 34 &unsortable);
36 if (!next) { 35 if (!next) {
37 if (!unsortable && simple->hasMove() 36 if (!unsortable && simple->hasMove()
38 && current->verb() != SkPath::kLine_Verb 37 && current->verb() != SkPath::kLine_Verb
39 && !simple->isClosed()) { 38 && !simple->isClosed()) {
40 if (!current->addCurveTo(start, end, simple)) { 39 if (!current->addCurveTo(start, end, simple)) {
41 return false; 40 return false;
42 } 41 }
43 #if DEBUG_ACTIVE_SPANS
44 if (!simple->isClosed()) { 42 if (!simple->isClosed()) {
45 DebugShowActiveSpans(contourList); 43 SkPathOpsDebug::ShowActiveSpans(contourList);
46 } 44 }
47 #endif
48 } 45 }
49 break; 46 break;
50 } 47 }
51 #if DEBUG_FLOW 48 #if DEBUG_FLOW
52 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", _ _FUNCTION__, 49 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", _ _FUNCTION__,
53 current->debugID(), start->pt().fX, start->pt().fY, 50 current->debugID(), start->pt().fX, start->pt().fY,
54 end->pt().fX, end->pt().fY); 51 end->pt().fX, end->pt().fY);
55 #endif 52 #endif
56 if (!current->addCurveTo(start, end, simple)) { 53 if (!current->addCurveTo(start, end, simple)) {
57 return false; 54 return false;
(...skipping 21 matching lines...) Expand all
79 #if DEBUG_WINDING 76 #if DEBUG_WINDING
80 SkDebugf("%s chase.append id=%d", __FUNCTION__, last->segmen t()->debugID()); 77 SkDebugf("%s chase.append id=%d", __FUNCTION__, last->segmen t()->debugID());
81 if (!last->final()) { 78 if (!last->final()) {
82 SkDebugf(" windSum=%d", last->upCast()->windSum()); 79 SkDebugf(" windSum=%d", last->upCast()->windSum());
83 } 80 }
84 SkDebugf("\n"); 81 SkDebugf("\n");
85 #endif 82 #endif
86 } 83 }
87 } 84 }
88 current = FindChase(&chase, &start, &end); 85 current = FindChase(&chase, &start, &end);
89 #if DEBUG_ACTIVE_SPANS 86 SkPathOpsDebug::ShowActiveSpans(contourList);
90 DebugShowActiveSpans(contourList);
91 #endif
92 if (!current) { 87 if (!current) {
93 break; 88 break;
94 } 89 }
95 } while (true); 90 } while (true);
96 } while (true); 91 } while (true);
97 *closable = !simple->someAssemblyRequired(); 92 *closable = !simple->someAssemblyRequired();
98 return true; 93 return true;
99 } 94 }
100 95
101 // returns true if all edges were processed 96 // returns true if all edges were processed
102 static bool bridgeXor(SkOpContourHead* contourList, SkPathWriter* simple, 97 static bool bridgeXor(SkOpContourHead* contourList, SkPathWriter* simple, bool* closable) {
103 SkChunkAlloc* allocator, bool* closable) {
104 SkOpSegment* current; 98 SkOpSegment* current;
105 SkOpSpanBase* start; 99 SkOpSpanBase* start;
106 SkOpSpanBase* end; 100 SkOpSpanBase* end;
107 bool unsortable = false; 101 bool unsortable = false;
108 *closable = true; 102 *closable = true;
109 while ((current = FindUndone(contourList, &start, &end))) { 103 while ((current = FindUndone(contourList, &start, &end))) {
110 do { 104 do {
111 #if DEBUG_ACTIVE_SPANS
112 if (!unsortable && current->done()) { 105 if (!unsortable && current->done()) {
113 DebugShowActiveSpans(contourList); 106 SkPathOpsDebug::ShowActiveSpans(contourList);
114 } 107 }
115 #endif
116 SkASSERT(unsortable || !current->done()); 108 SkASSERT(unsortable || !current->done());
117 SkOpSpanBase* nextStart = start; 109 SkOpSpanBase* nextStart = start;
118 SkOpSpanBase* nextEnd = end; 110 SkOpSpanBase* nextEnd = end;
119 SkOpSegment* next = current->findNextXor(&nextStart, &nextEnd, &unso rtable); 111 SkOpSegment* next = current->findNextXor(&nextStart, &nextEnd, &unso rtable);
120 if (!next) { 112 if (!next) {
121 if (!unsortable && simple->hasMove() 113 if (!unsortable && simple->hasMove()
122 && current->verb() != SkPath::kLine_Verb 114 && current->verb() != SkPath::kLine_Verb
123 && !simple->isClosed()) { 115 && !simple->isClosed()) {
124 if (!current->addCurveTo(start, end, simple)) { 116 if (!current->addCurveTo(start, end, simple)) {
125 return false; 117 return false;
126 } 118 }
127 #if DEBUG_ACTIVE_SPANS
128 if (!simple->isClosed()) { 119 if (!simple->isClosed()) {
129 DebugShowActiveSpans(contourList); 120 SkPathOpsDebug::ShowActiveSpans(contourList);
130 } 121 }
131 #endif
132 } 122 }
133 break; 123 break;
134 } 124 }
135 #if DEBUG_FLOW 125 #if DEBUG_FLOW
136 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", _ _FUNCTION__, 126 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", _ _FUNCTION__,
137 current->debugID(), start->pt().fX, start->pt().fY, 127 current->debugID(), start->pt().fX, start->pt().fY,
138 end->pt().fX, end->pt().fY); 128 end->pt().fX, end->pt().fY);
139 #endif 129 #endif
140 if (!current->addCurveTo(start, end, simple)) { 130 if (!current->addCurveTo(start, end, simple)) {
141 return false; 131 return false;
142 } 132 }
143 current = next; 133 current = next;
144 start = nextStart; 134 start = nextStart;
145 end = nextEnd; 135 end = nextEnd;
146 } while (!simple->isClosed() && (!unsortable || !start->starter(end)->do ne())); 136 } while (!simple->isClosed() && (!unsortable || !start->starter(end)->do ne()));
147 if (!simple->isClosed()) { 137 if (!simple->isClosed()) {
148 SkASSERT(unsortable); 138 SkASSERT(unsortable);
149 SkOpSpan* spanStart = start->starter(end); 139 SkOpSpan* spanStart = start->starter(end);
150 if (!spanStart->done()) { 140 if (!spanStart->done()) {
151 if (!current->addCurveTo(start, end, simple)) { 141 if (!current->addCurveTo(start, end, simple)) {
152 return false; 142 return false;
153 } 143 }
154 current->markDone(spanStart); 144 current->markDone(spanStart);
155 } 145 }
156 *closable = false; 146 *closable = false;
157 } 147 }
158 simple->close(); 148 simple->close();
159 #if DEBUG_ACTIVE_SPANS 149 SkPathOpsDebug::ShowActiveSpans(contourList);
160 DebugShowActiveSpans(contourList);
161 #endif
162 } 150 }
163 return true; 151 return true;
164 } 152 }
165 153
166 // FIXME : add this as a member of SkPath 154 // FIXME : add this as a member of SkPath
167 bool Simplify(const SkPath& path, SkPath* result) { 155 bool SimplifyDebug(const SkPath& path, SkPath* result
168 SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune 156 SkDEBUGPARAMS(bool skipAssert) SkDEBUGPARAMS(const char* testName)) {
169 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness 157 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
170 SkPath::FillType fillType = path.isInverseFillType() ? SkPath::kInverseEvenO dd_FillType 158 SkPath::FillType fillType = path.isInverseFillType() ? SkPath::kInverseEvenO dd_FillType
171 : SkPath::kEvenOdd_FillType; 159 : SkPath::kEvenOdd_FillType;
172 if (path.isConvex()) { 160 if (path.isConvex()) {
173 if (result != &path) { 161 if (result != &path) {
174 *result = path; 162 *result = path;
175 } 163 }
176 result->setFillType(fillType); 164 result->setFillType(fillType);
177 return true; 165 return true;
178 } 166 }
179 // turn path into list of segments 167 // turn path into list of segments
180 SkOpCoincidence coincidence; 168 SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune
181 SkOpContour contour; 169 SkOpContour contour;
182 SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour); 170 SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour);
183 SkOpGlobalState globalState(&coincidence, contourList SkDEBUGPARAMS(false) 171 SkOpGlobalState globalState(contourList, &allocator
184 SkDEBUGPARAMS(nullptr)); 172 SkDEBUGPARAMS(skipAssert) SkDEBUGPARAMS(testName));
173 SkOpCoincidence coincidence(&globalState);
174 SkScalar scaleFactor = ScaleFactor(path);
175 SkPath scaledPath;
176 const SkPath* workingPath;
177 if (scaleFactor > SK_Scalar1) {
178 ScalePath(path, 1.f / scaleFactor, &scaledPath);
179 workingPath = &scaledPath;
180 } else {
181 workingPath = &path;
182 }
185 #if DEBUG_SORT 183 #if DEBUG_SORT
186 SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault; 184 SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault;
187 #endif 185 #endif
188 SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState); 186 SkOpEdgeBuilder builder(*workingPath, &contour, &globalState);
189 if (!builder.finish(&allocator)) { 187 if (!builder.finish()) {
190 return false; 188 return false;
191 } 189 }
192 #if DEBUG_DUMP_SEGMENTS 190 #if DEBUG_DUMP_SEGMENTS
193 contour.dumpSegments(); 191 contour.dumpSegments();
194 #endif 192 #endif
195 if (!SortContourList(&contourList, false, false)) { 193 if (!SortContourList(&contourList, false, false)) {
196 result->reset(); 194 result->reset();
197 result->setFillType(fillType); 195 result->setFillType(fillType);
198 return true; 196 return true;
199 } 197 }
200 // find all intersections between segments 198 // find all intersections between segments
201 SkOpContour* current = contourList; 199 SkOpContour* current = contourList;
202 do { 200 do {
203 SkOpContour* next = current; 201 SkOpContour* next = current;
204 while (AddIntersectTs(current, next, &coincidence, &allocator) 202 while (AddIntersectTs(current, next, &coincidence)
205 && (next = next->next())); 203 && (next = next->next()));
206 } while ((current = current->next())); 204 } while ((current = current->next()));
207 #if DEBUG_VALIDATE 205 #if DEBUG_VALIDATE
208 globalState.setPhase(SkOpGlobalState::kWalking); 206 globalState.setPhase(SkOpGlobalState::kWalking);
209 #endif 207 #endif
210 if (!HandleCoincidence(contourList, &coincidence, &allocator)) { 208 if (!HandleCoincidence(contourList, &coincidence)) {
211 return false; 209 return false;
212 } 210 }
213 #if DEBUG_DUMP_ALIGNMENT 211 #if DEBUG_DUMP_ALIGNMENT
214 contour.dumpSegments("aligned"); 212 contour.dumpSegments("aligned");
215 #endif 213 #endif
216 // construct closed contours 214 // construct closed contours
217 result->reset(); 215 result->reset();
218 result->setFillType(fillType); 216 result->setFillType(fillType);
219 SkPathWriter wrapper(*result); 217 SkPathWriter wrapper(*result);
220 bool closable SK_INIT_TO_AVOID_WARNING; 218 bool closable SK_INIT_TO_AVOID_WARNING;
221 if (builder.xorMask() == kWinding_PathOpsMask 219 if (builder.xorMask() == kWinding_PathOpsMask
222 ? !bridgeWinding(contourList, &wrapper, &allocator, &closable) 220 ? !bridgeWinding(contourList, &wrapper, &closable)
223 : !bridgeXor(contourList, &wrapper, &allocator, &closable)) { 221 : !bridgeXor(contourList, &wrapper, &closable)) {
224 return false; 222 return false;
225 } 223 }
226 if (!closable) 224 if (!closable)
227 { // if some edges could not be resolved, assemble remaining fragments 225 { // if some edges could not be resolved, assemble remaining fragments
228 SkPath temp; 226 SkPath temp;
229 temp.setFillType(fillType); 227 temp.setFillType(fillType);
230 SkPathWriter assembled(temp); 228 SkPathWriter assembled(temp);
231 Assemble(wrapper, &assembled); 229 Assemble(wrapper, &assembled);
232 *result = *assembled.nativePath(); 230 *result = *assembled.nativePath();
233 result->setFillType(fillType); 231 result->setFillType(fillType);
234 } 232 }
233 if (scaleFactor > 1) {
234 ScalePath(*result, scaleFactor, result);
235 }
235 return true; 236 return true;
236 } 237 }
237 238
239 bool Simplify(const SkPath& path, SkPath* result) {
240 return SimplifyDebug(path, result SkDEBUGPARAMS(true) SkDEBUGPARAMS(nullptr ));
241 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698