blob: 8cedab4cb1ebb0b5e35be9bcf4223c8b1183dea1 [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +00001/*
2 * Copyright 2013 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#ifndef SkOpContour_DEFINED
8#define SkOpContour_DEFINED
9
10#include "SkOpSegment.h"
11#include "SkTArray.h"
12
13class SkIntersections;
14class SkOpContour;
15class SkPathWriter;
16
17struct SkCoincidence {
caryclark@google.com570863f2013-09-16 15:55:01 +000018 SkOpContour* fOther;
caryclark@google.com07393ca2013-04-08 11:47:37 +000019 int fSegments[2];
20 double fTs[2][2];
21 SkPoint fPts[2];
22};
23
24class SkOpContour {
25public:
26 SkOpContour() {
27 reset();
caryclark@google.com570863f2013-09-16 15:55:01 +000028#ifdef SK_DEBUG
29 fID = ++SkPathOpsDebug::gContourID;
caryclark@google.com07393ca2013-04-08 11:47:37 +000030#endif
31 }
32
33 bool operator<(const SkOpContour& rh) const {
34 return fBounds.fTop == rh.fBounds.fTop
35 ? fBounds.fLeft < rh.fBounds.fLeft
36 : fBounds.fTop < rh.fBounds.fTop;
37 }
38
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000039 bool addCoincident(int index, SkOpContour* other, int otherIndex,
caryclark@google.com07393ca2013-04-08 11:47:37 +000040 const SkIntersections& ts, bool swap);
41 void addCoincidentPoints();
42
43 void addCross(const SkOpContour* crosser) {
44#ifdef DEBUG_CROSS
45 for (int index = 0; index < fCrosses.count(); ++index) {
46 SkASSERT(fCrosses[index] != crosser);
47 }
48#endif
caryclark@google.comd892bd82013-06-17 14:10:36 +000049 fCrosses.push_back(crosser);
caryclark@google.com07393ca2013-04-08 11:47:37 +000050 }
51
52 void addCubic(const SkPoint pts[4]) {
53 fSegments.push_back().addCubic(pts, fOperand, fXor);
54 fContainsCurves = fContainsCubics = true;
55 }
56
57 int addLine(const SkPoint pts[2]) {
58 fSegments.push_back().addLine(pts, fOperand, fXor);
59 return fSegments.count();
60 }
61
62 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
63 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
64 }
65
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000066 bool addPartialCoincident(int index, SkOpContour* other, int otherIndex,
caryclark@google.com570863f2013-09-16 15:55:01 +000067 const SkIntersections& ts, int ptIndex, bool swap);
68
caryclark@google.com07393ca2013-04-08 11:47:37 +000069 int addQuad(const SkPoint pts[3]) {
70 fSegments.push_back().addQuad(pts, fOperand, fXor);
71 fContainsCurves = true;
72 return fSegments.count();
73 }
74
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +000075 int addT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt, double newT) {
caryclark@google.com07393ca2013-04-08 11:47:37 +000076 setContainsIntercepts();
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +000077 return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT);
caryclark@google.com07393ca2013-04-08 11:47:37 +000078 }
79
80 int addSelfT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt, double newT) {
81 setContainsIntercepts();
82 return fSegments[segIndex].addSelfT(&other->fSegments[otherIndex], pt, newT);
83 }
84
caryclark@google.com07393ca2013-04-08 11:47:37 +000085 const SkPathOpsBounds& bounds() const {
86 return fBounds;
87 }
88
89 void calcCoincidentWinding();
caryclark@google.com570863f2013-09-16 15:55:01 +000090 void calcPartialCoincidentWinding();
caryclark@google.com07393ca2013-04-08 11:47:37 +000091
caryclark@google.comfa2aeee2013-07-15 13:29:13 +000092 void checkEnds() {
93 if (!fContainsCurves) {
94 return;
95 }
96 int segmentCount = fSegments.count();
97 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
98 SkOpSegment* segment = &fSegments[sIndex];
99 if (segment->verb() == SkPath::kLine_Verb) {
100 continue;
101 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000102 if (segment->done()) {
103 continue; // likely coincident, nothing to do
104 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000105 segment->checkEnds();
106 }
107 }
108
109 // if same point has different T values, choose a common T
110 void checkTiny() {
111 int segmentCount = fSegments.count();
112 if (segmentCount <= 2) {
113 return;
114 }
115 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
116 fSegments[sIndex].checkTiny();
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000117 }
118 }
119
caryclark@google.com07393ca2013-04-08 11:47:37 +0000120 void complete() {
121 setBounds();
122 fContainsIntercepts = false;
123 }
124
125 bool containsCubics() const {
126 return fContainsCubics;
127 }
128
129 bool crosses(const SkOpContour* crosser) const {
130 for (int index = 0; index < fCrosses.count(); ++index) {
131 if (fCrosses[index] == crosser) {
132 return true;
133 }
134 }
135 return false;
136 }
137
138 bool done() const {
139 return fDone;
140 }
141
142 const SkPoint& end() const {
143 const SkOpSegment& segment = fSegments.back();
reed@google.com277c3f82013-05-31 15:17:50 +0000144 return segment.pts()[SkPathOpsVerbToPoints(segment.verb())];
caryclark@google.com07393ca2013-04-08 11:47:37 +0000145 }
146
caryclark@google.com07393ca2013-04-08 11:47:37 +0000147 void fixOtherTIndex() {
148 int segmentCount = fSegments.count();
149 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
150 fSegments[sIndex].fixOtherTIndex();
151 }
152 }
153
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000154 void joinCoincidence() {
155 joinCoincidence(fCoincidences, false);
156 joinCoincidence(fPartialCoincidences, true);
157 }
158
caryclark@google.com07393ca2013-04-08 11:47:37 +0000159 SkOpSegment* nonVerticalSegment(int* start, int* end);
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000160
caryclark@google.com07393ca2013-04-08 11:47:37 +0000161 bool operand() const {
162 return fOperand;
163 }
164
165 void reset() {
166 fSegments.reset();
167 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
168 fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = false;
169 }
170
171 SkTArray<SkOpSegment>& segments() {
172 return fSegments;
173 }
174
175 void setContainsIntercepts() {
176 fContainsIntercepts = true;
177 }
178
179 void setOperand(bool isOp) {
180 fOperand = isOp;
181 }
182
183 void setOppXor(bool isOppXor) {
184 fOppXor = isOppXor;
185 int segmentCount = fSegments.count();
186 for (int test = 0; test < segmentCount; ++test) {
187 fSegments[test].setOppXor(isOppXor);
188 }
189 }
190
191 void setXor(bool isXor) {
192 fXor = isXor;
193 }
194
195 void sortSegments();
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000196
caryclark@google.com07393ca2013-04-08 11:47:37 +0000197 const SkPoint& start() const {
198 return fSegments.front().pts()[0];
199 }
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000200
caryclark@google.com07393ca2013-04-08 11:47:37 +0000201 void toPath(SkPathWriter* path) const;
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000202
caryclark@google.com07393ca2013-04-08 11:47:37 +0000203 void toPartialBackward(SkPathWriter* path) const {
204 int segmentCount = fSegments.count();
205 for (int test = segmentCount - 1; test >= 0; --test) {
206 fSegments[test].addCurveTo(1, 0, path, true);
207 }
208 }
209
210 void toPartialForward(SkPathWriter* path) const {
211 int segmentCount = fSegments.count();
212 for (int test = 0; test < segmentCount; ++test) {
213 fSegments[test].addCurveTo(0, 1, path, true);
214 }
215 }
216
217 void topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, SkOpSegment** topStart);
218 SkOpSegment* undoneSegment(int* start, int* end);
219
220 int updateSegment(int index, const SkPoint* pts) {
221 SkOpSegment& segment = fSegments[index];
222 segment.updatePts(pts);
reed@google.com277c3f82013-05-31 15:17:50 +0000223 return SkPathOpsVerbToPoints(segment.verb()) + 1;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000224 }
225
226#if DEBUG_TEST
227 SkTArray<SkOpSegment>& debugSegments() {
228 return fSegments;
229 }
230#endif
231
caryclark@google.coma5e55922013-05-07 18:51:31 +0000232#if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
caryclark@google.com07393ca2013-04-08 11:47:37 +0000233 void debugShowActiveSpans() {
234 for (int index = 0; index < fSegments.count(); ++index) {
235 fSegments[index].debugShowActiveSpans();
236 }
237 }
238#endif
239
240#if DEBUG_SHOW_WINDING
241 int debugShowWindingValues(int totalSegments, int ofInterest);
caryclark@google.comd892bd82013-06-17 14:10:36 +0000242 static void debugShowWindingValues(const SkTArray<SkOpContour*, true>& contourList);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000243#endif
244
245private:
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000246 void calcCommonCoincidentWinding(const SkCoincidence& );
247 void joinCoincidence(const SkTArray<SkCoincidence, true>& , bool partial);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000248 void setBounds();
249
250 SkTArray<SkOpSegment> fSegments;
caryclark@google.comd892bd82013-06-17 14:10:36 +0000251 SkTArray<SkOpSegment*, true> fSortedSegments;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000252 int fFirstSorted;
caryclark@google.comd892bd82013-06-17 14:10:36 +0000253 SkTArray<SkCoincidence, true> fCoincidences;
caryclark@google.com570863f2013-09-16 15:55:01 +0000254 SkTArray<SkCoincidence, true> fPartialCoincidences;
caryclark@google.comd892bd82013-06-17 14:10:36 +0000255 SkTArray<const SkOpContour*, true> fCrosses;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000256 SkPathOpsBounds fBounds;
257 bool fContainsIntercepts; // FIXME: is this used by anybody?
258 bool fContainsCubics;
259 bool fContainsCurves;
260 bool fDone;
261 bool fOperand; // true for the second argument to a binary operator
262 bool fXor;
263 bool fOppXor;
caryclark@google.com570863f2013-09-16 15:55:01 +0000264#ifdef SK_DEBUG
caryclark@google.com07393ca2013-04-08 11:47:37 +0000265 int fID;
266#endif
267};
268
269#endif