2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
7 #ifndef SkOpContour_DEFINED
8 #define SkOpContour_DEFINED
10 #include "SkOpSegment.h"
13 class SkIntersections;
17 struct SkCoincidence {
29 fID = ++SkPathOpsDebug::gContourID;
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;
39 bool addCoincident(int index, SkOpContour* other, int otherIndex,
40 const SkIntersections& ts, bool swap);
41 void addCoincidentPoints();
43 void addCross(const SkOpContour* crosser) {
45 for (int index = 0; index < fCrosses.count(); ++index) {
46 SkASSERT(fCrosses[index] != crosser);
49 fCrosses.push_back(crosser);
52 void addCubic(const SkPoint pts[4]) {
53 fSegments.push_back().addCubic(pts, fOperand, fXor);
54 fContainsCurves = fContainsCubics = true;
57 int addLine(const SkPoint pts[2]) {
58 fSegments.push_back().addLine(pts, fOperand, fXor);
59 return fSegments.count();
62 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
63 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
66 bool addPartialCoincident(int index, SkOpContour* other, int otherIndex,
67 const SkIntersections& ts, int ptIndex, bool swap);
69 int addQuad(const SkPoint pts[3]) {
70 fSegments.push_back().addQuad(pts, fOperand, fXor);
71 fContainsCurves = true;
72 return fSegments.count();
75 int addT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt, double newT,
77 setContainsIntercepts();
78 return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT, isNear);
81 int addSelfT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt, double newT) {
82 setContainsIntercepts();
83 return fSegments[segIndex].addSelfT(&other->fSegments[otherIndex], pt, newT);
86 const SkPathOpsBounds& bounds() const {
90 void calcCoincidentWinding();
91 void calcPartialCoincidentWinding();
94 if (!fContainsCurves) {
97 int segmentCount = fSegments.count();
98 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
99 SkOpSegment* segment = &fSegments[sIndex];
100 if (segment->verb() == SkPath::kLine_Verb) {
103 if (segment->done()) {
104 continue; // likely coincident, nothing to do
106 segment->checkEnds();
110 // if same point has different T values, choose a common T
112 int segmentCount = fSegments.count();
113 if (segmentCount <= 2) {
116 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
117 fSegments[sIndex].checkTiny();
123 fContainsIntercepts = false;
126 bool containsCubics() const {
127 return fContainsCubics;
130 bool crosses(const SkOpContour* crosser) const {
131 for (int index = 0; index < fCrosses.count(); ++index) {
132 if (fCrosses[index] == crosser) {
143 const SkPoint& end() const {
144 const SkOpSegment& segment = fSegments.back();
145 return segment.pts()[SkPathOpsVerbToPoints(segment.verb())];
148 void fixOtherTIndex() {
149 int segmentCount = fSegments.count();
150 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
151 fSegments[sIndex].fixOtherTIndex();
155 void joinCoincidence() {
156 joinCoincidence(fCoincidences, false);
157 joinCoincidence(fPartialCoincidences, true);
160 SkOpSegment* nonVerticalSegment(int* start, int* end);
162 bool operand() const {
168 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
169 fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = false;
172 SkTArray<SkOpSegment>& segments() {
176 void setContainsIntercepts() {
177 fContainsIntercepts = true;
180 void setOperand(bool isOp) {
184 void setOppXor(bool isOppXor) {
186 int segmentCount = fSegments.count();
187 for (int test = 0; test < segmentCount; ++test) {
188 fSegments[test].setOppXor(isOppXor);
192 void setXor(bool isXor) {
198 const SkPoint& start() const {
199 return fSegments.front().pts()[0];
202 void toPath(SkPathWriter* path) const;
204 void toPartialBackward(SkPathWriter* path) const {
205 int segmentCount = fSegments.count();
206 for (int test = segmentCount - 1; test >= 0; --test) {
207 fSegments[test].addCurveTo(1, 0, path, true);
211 void toPartialForward(SkPathWriter* path) const {
212 int segmentCount = fSegments.count();
213 for (int test = 0; test < segmentCount; ++test) {
214 fSegments[test].addCurveTo(0, 1, path, true);
218 void topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, SkOpSegment** topStart);
219 SkOpSegment* undoneSegment(int* start, int* end);
221 int updateSegment(int index, const SkPoint* pts) {
222 SkOpSegment& segment = fSegments[index];
223 segment.updatePts(pts);
224 return SkPathOpsVerbToPoints(segment.verb()) + 1;
228 SkTArray<SkOpSegment>& debugSegments() {
233 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
234 void debugShowActiveSpans() {
235 for (int index = 0; index < fSegments.count(); ++index) {
236 fSegments[index].debugShowActiveSpans();
241 #if DEBUG_SHOW_WINDING
242 int debugShowWindingValues(int totalSegments, int ofInterest);
243 static void debugShowWindingValues(const SkTArray<SkOpContour*, true>& contourList);
247 void calcCommonCoincidentWinding(const SkCoincidence& );
248 void joinCoincidence(const SkTArray<SkCoincidence, true>& , bool partial);
251 SkTArray<SkOpSegment> fSegments;
252 SkTArray<SkOpSegment*, true> fSortedSegments;
254 SkTArray<SkCoincidence, true> fCoincidences;
255 SkTArray<SkCoincidence, true> fPartialCoincidences;
256 SkTArray<const SkOpContour*, true> fCrosses;
257 SkPathOpsBounds fBounds;
258 bool fContainsIntercepts; // FIXME: is this used by anybody?
259 bool fContainsCubics;
260 bool fContainsCurves;
262 bool fOperand; // true for the second argument to a binary operator