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

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

Issue 13094010: Add implementation of path ops (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Created 7 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 | Annotate | Revision Log
« no previous file with comments | « src/pathops/SkPathOpsCommon.cpp ('k') | src/pathops/SkPathOpsSimplify.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7 #include "SkAddIntersections.h"
8 #include "SkOpEdgeBuilder.h"
9 #include "SkPathOpsCommon.h"
10 #include "SkPathWriter.h"
11
12 // FIXME: this and find chase should be merge together, along with
13 // other code that walks winding in angles
14 // OPTIMIZATION: Probably, the walked winding should be rolled into the angle st ructure
15 // so it isn't duplicated by walkers like this one
16 static SkOpSegment* findChaseOp(SkTDArray<SkOpSpan*>& chase, int& nextStart, int & nextEnd) {
17 while (chase.count()) {
18 SkOpSpan* span;
19 chase.pop(&span);
20 const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex);
21 SkOpSegment* segment = backPtr.fOther;
22 nextStart = backPtr.fOtherIndex;
23 SkTDArray<SkOpAngle> angles;
24 int done = 0;
25 if (segment->activeAngle(nextStart, done, angles)) {
26 SkOpAngle* last = angles.end() - 1;
27 nextStart = last->start();
28 nextEnd = last->end();
29 #if TRY_ROTATE
30 *chase.insert(0) = span;
31 #else
32 *chase.append() = span;
33 #endif
34 return last->segment();
35 }
36 if (done == angles.count()) {
37 continue;
38 }
39 SkTDArray<SkOpAngle*> sorted;
40 bool sortable = SkOpSegment::SortAngles(angles, sorted);
41 int angleCount = sorted.count();
42 #if DEBUG_SORT
43 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0);
44 #endif
45 if (!sortable) {
46 continue;
47 }
48 // find first angle, initialize winding to computed fWindSum
49 int firstIndex = -1;
50 const SkOpAngle* angle;
51 do {
52 angle = sorted[++firstIndex];
53 segment = angle->segment();
54 } while (segment->windSum(angle) == SK_MinS32);
55 #if DEBUG_SORT
56 segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
57 #endif
58 int sumMiWinding = segment->updateWindingReverse(angle);
59 int sumSuWinding = segment->updateOppWindingReverse(angle);
60 if (segment->operand()) {
61 SkTSwap<int>(sumMiWinding, sumSuWinding);
62 }
63 int nextIndex = firstIndex + 1;
64 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
65 SkOpSegment* first = NULL;
66 do {
67 SkASSERT(nextIndex != firstIndex);
68 if (nextIndex == angleCount) {
69 nextIndex = 0;
70 }
71 angle = sorted[nextIndex];
72 segment = angle->segment();
73 int start = angle->start();
74 int end = angle->end();
75 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
76 segment->setUpWindings(start, end, sumMiWinding, sumSuWinding,
77 maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
78 if (!segment->done(angle)) {
79 if (!first) {
80 first = segment;
81 nextStart = start;
82 nextEnd = end;
83 }
84 (void) segment->markAngle(maxWinding, sumWinding, oppMaxWinding,
85 oppSumWinding, true, angle);
86 }
87 } while (++nextIndex != lastIndex);
88 if (first) {
89 #if TRY_ROTATE
90 *chase.insert(0) = span;
91 #else
92 *chase.append() = span;
93 #endif
94 return first;
95 }
96 }
97 return NULL;
98 }
99
100 /*
101 static bool windingIsActive(int winding, int oppWinding, int spanWinding, int op pSpanWinding,
102 bool windingIsOp, PathOp op) {
103 bool active = windingIsActive(winding, spanWinding);
104 if (!active) {
105 return false;
106 }
107 if (oppSpanWinding && windingIsActive(oppWinding, oppSpanWinding)) {
108 switch (op) {
109 case kIntersect_Op:
110 case kUnion_Op:
111 return true;
112 case kDifference_Op: {
113 int absSpan = abs(spanWinding);
114 int absOpp = abs(oppSpanWinding);
115 return windingIsOp ? absSpan < absOpp : absSpan > absOpp;
116 }
117 case kXor_Op:
118 return spanWinding != oppSpanWinding;
119 default:
120 SkASSERT(0);
121 }
122 }
123 bool opActive = oppWinding != 0;
124 return gOpLookup[op][opActive][windingIsOp];
125 }
126 */
127
128 static bool bridgeOp(SkTDArray<SkOpContour*>& contourList, const SkPathOp op,
129 const int xorMask, const int xorOpMask, SkPathWriter& simple) {
130 bool firstContour = true;
131 bool unsortable = false;
132 bool topUnsortable = false;
133 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
134 do {
135 int index, endIndex;
136 bool done;
137 SkOpSegment* current = FindSortableTop(contourList, firstContour, index, endIndex, topLeft,
138 topUnsortable, done, true);
139 if (!current) {
140 if (topUnsortable || !done) {
141 topUnsortable = false;
142 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMi n);
143 topLeft.fX = topLeft.fY = SK_ScalarMin;
144 continue;
145 }
146 break;
147 }
148 SkTDArray<SkOpSpan*> chaseArray;
149 do {
150 if (current->activeOp(index, endIndex, xorMask, xorOpMask, op)) {
151 do {
152 #if DEBUG_ACTIVE_SPANS
153 if (!unsortable && current->done()) {
154 DebugShowActiveSpans(contourList);
155 }
156 #endif
157 SkASSERT(unsortable || !current->done());
158 int nextStart = index;
159 int nextEnd = endIndex;
160 SkOpSegment* next = current->findNextOp(chaseArray, nextStar t, nextEnd,
161 unsortable, op, xorMask, xorOpMask);
162 if (!next) {
163 if (!unsortable && simple.hasMove()
164 && current->verb() != SkPath::kLine_Verb
165 && !simple.isClosed()) {
166 current->addCurveTo(index, endIndex, simple, true);
167 SkASSERT(simple.isClosed());
168 }
169 break;
170 }
171 #if DEBUG_FLOW
172 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", _ _FUNCTION__,
173 current->debugID(), current->xyAtT(index).fX, current->xyAtT (index).fY,
174 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
175 #endif
176 current->addCurveTo(index, endIndex, simple, true);
177 current = next;
178 index = nextStart;
179 endIndex = nextEnd;
180 } while (!simple.isClosed() && ((!unsortable)
181 || !current->done(SkMin32(index, endIndex))));
182 if (current->activeWinding(index, endIndex) && !simple.isClosed( )) {
183 SkASSERT(unsortable);
184 int min = SkMin32(index, endIndex);
185 if (!current->done(min)) {
186 current->addCurveTo(index, endIndex, simple, true);
187 current->markDoneBinary(min);
188 }
189 }
190 simple.close();
191 } else {
192 SkOpSpan* last = current->markAndChaseDoneBinary(index, endIndex );
193 if (last && !last->fLoop) {
194 *chaseArray.append() = last;
195 }
196 }
197 current = findChaseOp(chaseArray, index, endIndex);
198 #if DEBUG_ACTIVE_SPANS
199 DebugShowActiveSpans(contourList);
200 #endif
201 if (!current) {
202 break;
203 }
204 } while (true);
205 } while (true);
206 return simple.someAssemblyRequired();
207 }
208
209 void Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) {
210 #if DEBUG_SORT || DEBUG_SWAP_TOP
211 gDebugSortCount = gDebugSortCountDefault;
212 #endif
213 result->reset();
214 result->setFillType(SkPath::kEvenOdd_FillType);
215 // turn path into list of segments
216 SkTArray<SkOpContour> contours;
217 // FIXME: add self-intersecting cubics' T values to segment
218 SkOpEdgeBuilder builder(one, contours);
219 const int xorMask = builder.xorMask();
220 builder.addOperand(two);
221 builder.finish();
222 const int xorOpMask = builder.xorMask();
223 SkTDArray<SkOpContour*> contourList;
224 MakeContourList(contours, contourList, xorMask == kEvenOdd_PathOpsMask,
225 xorOpMask == kEvenOdd_PathOpsMask);
226 SkOpContour** currentPtr = contourList.begin();
227 if (!currentPtr) {
228 return;
229 }
230 SkOpContour** listEnd = contourList.end();
231 // find all intersections between segments
232 do {
233 SkOpContour** nextPtr = currentPtr;
234 SkOpContour* current = *currentPtr++;
235 if (current->containsCubics()) {
236 AddSelfIntersectTs(current);
237 }
238 SkOpContour* next;
239 do {
240 next = *nextPtr++;
241 } while (AddIntersectTs(current, next) && nextPtr != listEnd);
242 } while (currentPtr != listEnd);
243 // eat through coincident edges
244
245 int total = 0;
246 int index;
247 for (index = 0; index < contourList.count(); ++index) {
248 total += contourList[index]->segments().count();
249 }
250 #if DEBUG_SHOW_WINDING
251 SkOpContour::debugShowWindingValues(contourList);
252 #endif
253 CoincidenceCheck(contourList, total);
254 #if DEBUG_SHOW_WINDING
255 SkOpContour::debugShowWindingValues(contourList);
256 #endif
257 FixOtherTIndex(contourList);
258 SortSegments(contourList);
259 #if DEBUG_ACTIVE_SPANS
260 DebugShowActiveSpans(contourList);
261 #endif
262 // construct closed contours
263 SkPathWriter wrapper(*result);
264 bridgeOp(contourList, op, xorMask, xorOpMask, wrapper);
265 { // if some edges could not be resolved, assemble remaining fragments
266 SkPath temp;
267 temp.setFillType(SkPath::kEvenOdd_FillType);
268 SkPathWriter assembled(temp);
269 Assemble(wrapper, assembled);
270 *result = *assembled.nativePath();
271 }
272 }
OLDNEW
« no previous file with comments | « src/pathops/SkPathOpsCommon.cpp ('k') | src/pathops/SkPathOpsSimplify.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698