blob: 74e1626c6681c74cb487bcc36830cbde3d3fb8c2 [file] [log] [blame]
caryclark@google.com235f56a2012-09-14 14:19:30 +00001/*
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 "Simplify.h"
8
9namespace Op {
10
11#include "Simplify.cpp"
12
13static bool windingIsActive(int winding, int spanWinding, int oppWinding,
14 const ShapeOp op) {
15 return winding * spanWinding <= 0 && abs(winding) <= abs(spanWinding)
16 && (!winding || !spanWinding || winding == -spanWinding);
17}
18
19static void bridgeOp(SkTDArray<Contour*>& contourList, const ShapeOp op,
20 const int aXorMask, const int bXorMask, SkPath& simple) {
21 bool firstContour = true;
22 do {
23 Segment* topStart = findTopContour(contourList);
24 if (!topStart) {
25 break;
26 }
27 // Start at the top. Above the top is outside, below is inside.
28 // follow edges to intersection by changing the index by direction.
29 int index, endIndex;
30 Segment* current = topStart->findTop(index, endIndex);
31 int contourWinding;
32 if (firstContour) {
33 contourWinding = 0;
34 firstContour = false;
35 } else {
36 int sumWinding = current->windSum(SkMin32(index, endIndex));
37 // FIXME: don't I have to adjust windSum to get contourWinding?
38 if (sumWinding == SK_MinS32) {
39 sumWinding = current->computeSum(index, endIndex);
40 }
41 if (sumWinding == SK_MinS32) {
42 contourWinding = innerContourCheck(contourList, current,
43 index, endIndex);
44 } else {
45 contourWinding = sumWinding;
46 int spanWinding = current->spanSign(index, endIndex);
47 bool inner = useInnerWinding(sumWinding - spanWinding, sumWinding);
48 if (inner) {
49 contourWinding -= spanWinding;
50 }
51#if DEBUG_WINDING
52 SkDebugf("%s sumWinding=%d spanWinding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
53 sumWinding, spanWinding, SkSign32(index - endIndex),
54 inner, contourWinding);
55#endif
56 }
57#if DEBUG_WINDING
58 // SkASSERT(current->debugVerifyWinding(index, endIndex, contourWinding));
59 SkDebugf("%s contourWinding=%d\n", __FUNCTION__, contourWinding);
60#endif
61 }
62 SkPoint lastPt;
63 int winding = contourWinding;
64 int spanWinding = current->spanSign(index, endIndex);
65 int oppWinding = current->oppSign(index, endIndex);
66 bool active = windingIsActive(winding, spanWinding, oppWinding, op);
67 SkTDArray<Span*> chaseArray;
68 do {
69 #if DEBUG_WINDING
70 SkDebugf("%s active=%s winding=%d spanWinding=%d\n",
71 __FUNCTION__, active ? "true" : "false",
72 winding, spanWinding);
73 #endif
74 const SkPoint* firstPt = NULL;
75 do {
76 SkASSERT(!current->done());
77 int nextStart = index;
78 int nextEnd = endIndex;
79 Segment* next = current->findNextOp(chaseArray, active,
80 nextStart, nextEnd, winding, spanWinding, op,
81 aXorMask, bXorMask);
82 if (!next) {
83 if (active && firstPt && current->verb() != SkPath::kLine_Verb && *firstPt != lastPt) {
84 lastPt = current->addCurveTo(index, endIndex, simple, true);
85 SkASSERT(*firstPt == lastPt);
86 }
87 break;
88 }
89 if (!firstPt) {
90 firstPt = &current->addMoveTo(index, simple, active);
91 }
92 lastPt = current->addCurveTo(index, endIndex, simple, active);
93 current = next;
94 index = nextStart;
95 endIndex = nextEnd;
96 } while (*firstPt != lastPt && (active || !current->done()));
97 if (firstPt && active) {
98 #if DEBUG_PATH_CONSTRUCTION
99 SkDebugf("%s close\n", __FUNCTION__);
100 #endif
101 simple.close();
102 }
103 current = findChase(chaseArray, index, endIndex, contourWinding);
104 #if DEBUG_ACTIVE_SPANS
105 debugShowActiveSpans(contourList);
106 #endif
107 if (!current) {
108 break;
109 }
110 int lesser = SkMin32(index, endIndex);
111 spanWinding = current->spanSign(index, endIndex);
112 winding = current->windSum(lesser);
113 bool inner = useInnerWinding(winding - spanWinding, winding);
114 #if DEBUG_WINDING
115 SkDebugf("%s id=%d t=%1.9g spanWinding=%d winding=%d sign=%d"
116 " inner=%d result=%d\n",
117 __FUNCTION__, current->debugID(), current->t(lesser),
118 spanWinding, winding, SkSign32(index - endIndex),
119 useInnerWinding(winding - spanWinding, winding),
120 inner ? winding - spanWinding : winding);
121 #endif
122 if (inner) {
123 winding -= spanWinding;
124 }
125 int oppWinding = current->oppSign(index, endIndex);
126 active = windingIsActive(winding, spanWinding, oppWinding, op);
127 } while (true);
128 } while (true);
129}
130
131} // end of Op namespace
132
133
134void operate(const SkPath& one, const SkPath& two, ShapeOp op, SkPath& result) {
135 result.reset();
136 result.setFillType(SkPath::kEvenOdd_FillType);
137 // turn path into list of segments
138 SkTArray<Op::Contour> contours;
139 // FIXME: add self-intersecting cubics' T values to segment
140 Op::EdgeBuilder builder(one, contours);
141 const int aXorMask = builder.xorMask();
142 builder.addOperand(two);
143 const int bXorMask = builder.xorMask();
144 builder.finish();
145 SkTDArray<Op::Contour*> contourList;
146 makeContourList(contours, contourList);
147 Op::Contour** currentPtr = contourList.begin();
148 if (!currentPtr) {
149 return;
150 }
151 Op::Contour** listEnd = contourList.end();
152 // find all intersections between segments
153 do {
154 Op::Contour** nextPtr = currentPtr;
155 Op::Contour* current = *currentPtr++;
156 Op::Contour* next;
157 do {
158 next = *nextPtr++;
159 } while (addIntersectTs(current, next) && nextPtr != listEnd);
160 } while (currentPtr != listEnd);
161 // eat through coincident edges
162 coincidenceCheck(contourList);
163 fixOtherTIndex(contourList);
164 // construct closed contours
165 bridgeOp(contourList, op, aXorMask, bXorMask, result);
166}