blob: c57fbac6cae9bb2511ba5e1aa485658c51120917 [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 {
18 SkOpContour* fContours[2];
19 int fSegments[2];
20 double fTs[2][2];
21 SkPoint fPts[2];
22};
23
24class SkOpContour {
25public:
26 SkOpContour() {
27 reset();
28#if DEBUG_DUMP
29 fID = ++gContourID;
30#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
39 void addCoincident(int index, SkOpContour* other, int otherIndex,
40 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
49 *fCrosses.append() = crosser;
50 }
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
66 int addQuad(const SkPoint pts[3]) {
67 fSegments.push_back().addQuad(pts, fOperand, fXor);
68 fContainsCurves = true;
69 return fSegments.count();
70 }
71
72 int addT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt, double newT) {
73 setContainsIntercepts();
74 return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT);
75 }
76
77 int addSelfT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt, double newT) {
78 setContainsIntercepts();
79 return fSegments[segIndex].addSelfT(&other->fSegments[otherIndex], pt, newT);
80 }
81
82 int addUnsortableT(int segIndex, SkOpContour* other, int otherIndex, bool start,
83 const SkPoint& pt, double newT) {
84 return fSegments[segIndex].addUnsortableT(&other->fSegments[otherIndex], start, pt, newT);
85 }
86
87 const SkPathOpsBounds& bounds() const {
88 return fBounds;
89 }
90
91 void calcCoincidentWinding();
92
93 void complete() {
94 setBounds();
95 fContainsIntercepts = false;
96 }
97
98 bool containsCubics() const {
99 return fContainsCubics;
100 }
101
102 bool crosses(const SkOpContour* crosser) const {
103 for (int index = 0; index < fCrosses.count(); ++index) {
104 if (fCrosses[index] == crosser) {
105 return true;
106 }
107 }
108 return false;
109 }
110
111 bool done() const {
112 return fDone;
113 }
114
115 const SkPoint& end() const {
116 const SkOpSegment& segment = fSegments.back();
reed@google.com277c3f82013-05-31 15:17:50 +0000117 return segment.pts()[SkPathOpsVerbToPoints(segment.verb())];
caryclark@google.com07393ca2013-04-08 11:47:37 +0000118 }
119
120 void findTooCloseToCall() {
121 int segmentCount = fSegments.count();
122 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
123 fSegments[sIndex].findTooCloseToCall();
124 }
125 }
126
127 void fixOtherTIndex() {
128 int segmentCount = fSegments.count();
129 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
130 fSegments[sIndex].fixOtherTIndex();
131 }
132 }
133
134 SkOpSegment* nonVerticalSegment(int* start, int* end);
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000135
caryclark@google.com07393ca2013-04-08 11:47:37 +0000136 bool operand() const {
137 return fOperand;
138 }
139
140 void reset() {
141 fSegments.reset();
142 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
143 fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = false;
144 }
145
146 SkTArray<SkOpSegment>& segments() {
147 return fSegments;
148 }
149
150 void setContainsIntercepts() {
151 fContainsIntercepts = true;
152 }
153
154 void setOperand(bool isOp) {
155 fOperand = isOp;
156 }
157
158 void setOppXor(bool isOppXor) {
159 fOppXor = isOppXor;
160 int segmentCount = fSegments.count();
161 for (int test = 0; test < segmentCount; ++test) {
162 fSegments[test].setOppXor(isOppXor);
163 }
164 }
165
166 void setXor(bool isXor) {
167 fXor = isXor;
168 }
169
170 void sortSegments();
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000171
caryclark@google.com07393ca2013-04-08 11:47:37 +0000172 const SkPoint& start() const {
173 return fSegments.front().pts()[0];
174 }
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000175
caryclark@google.com07393ca2013-04-08 11:47:37 +0000176 void toPath(SkPathWriter* path) const;
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000177
caryclark@google.com07393ca2013-04-08 11:47:37 +0000178 void toPartialBackward(SkPathWriter* path) const {
179 int segmentCount = fSegments.count();
180 for (int test = segmentCount - 1; test >= 0; --test) {
181 fSegments[test].addCurveTo(1, 0, path, true);
182 }
183 }
184
185 void toPartialForward(SkPathWriter* path) const {
186 int segmentCount = fSegments.count();
187 for (int test = 0; test < segmentCount; ++test) {
188 fSegments[test].addCurveTo(0, 1, path, true);
189 }
190 }
191
192 void topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, SkOpSegment** topStart);
193 SkOpSegment* undoneSegment(int* start, int* end);
194
195 int updateSegment(int index, const SkPoint* pts) {
196 SkOpSegment& segment = fSegments[index];
197 segment.updatePts(pts);
reed@google.com277c3f82013-05-31 15:17:50 +0000198 return SkPathOpsVerbToPoints(segment.verb()) + 1;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000199 }
200
201#if DEBUG_TEST
202 SkTArray<SkOpSegment>& debugSegments() {
203 return fSegments;
204 }
205#endif
206
caryclark@google.coma5e55922013-05-07 18:51:31 +0000207#if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
caryclark@google.com07393ca2013-04-08 11:47:37 +0000208 void debugShowActiveSpans() {
209 for (int index = 0; index < fSegments.count(); ++index) {
210 fSegments[index].debugShowActiveSpans();
211 }
212 }
213#endif
214
215#if DEBUG_SHOW_WINDING
216 int debugShowWindingValues(int totalSegments, int ofInterest);
217 static void debugShowWindingValues(const SkTDArray<SkOpContour*>& contourList);
218#endif
219
220private:
221 void setBounds();
222
223 SkTArray<SkOpSegment> fSegments;
224 SkTDArray<SkOpSegment*> fSortedSegments;
225 int fFirstSorted;
226 SkTDArray<SkCoincidence> fCoincidences;
227 SkTDArray<const SkOpContour*> fCrosses;
228 SkPathOpsBounds fBounds;
229 bool fContainsIntercepts; // FIXME: is this used by anybody?
230 bool fContainsCubics;
231 bool fContainsCurves;
232 bool fDone;
233 bool fOperand; // true for the second argument to a binary operator
234 bool fXor;
235 bool fOppXor;
236#if DEBUG_DUMP
237 int fID;
238#endif
239};
240
241#endif