1 /* 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 13 class SkIntersections; 14 class SkOpContour; 15 class SkPathWriter; 16 17 struct SkCoincidence { 18 SkOpContour* fOther; 19 int fSegments[2]; 20 double fTs[2][2]; 21 SkPoint fPts[2]; 22 }; 23 24 class SkOpContour { 25 public: 26 SkOpContour() { 27 reset(); 28 #ifdef SK_DEBUG 29 fID = ++SkPathOpsDebug::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 bool 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.push_back(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 bool addPartialCoincident(int index, SkOpContour* other, int otherIndex, 67 const SkIntersections& ts, int ptIndex, bool swap); 68 69 int addQuad(const SkPoint pts[3]) { 70 fSegments.push_back().addQuad(pts, fOperand, fXor); 71 fContainsCurves = true; 72 return fSegments.count(); 73 } 74 75 int addT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt, double newT) { 76 setContainsIntercepts(); 77 return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT); 78 } 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 85 const SkPathOpsBounds& bounds() const { 86 return fBounds; 87 } 88 89 void calcCoincidentWinding(); 90 void calcPartialCoincidentWinding(); 91 92 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 } 102 if (segment->done()) { 103 continue; // likely coincident, nothing to do 104 } 105 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(); 117 } 118 } 119 120 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(); 144 return segment.pts()[SkPathOpsVerbToPoints(segment.verb())]; 145 } 146 147 void fixOtherTIndex() { 148 int segmentCount = fSegments.count(); 149 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { 150 fSegments[sIndex].fixOtherTIndex(); 151 } 152 } 153 154 void joinCoincidence() { 155 joinCoincidence(fCoincidences, false); 156 joinCoincidence(fPartialCoincidences, true); 157 } 158 159 SkOpSegment* nonVerticalSegment(int* start, int* end); 160 161 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(); 196 197 const SkPoint& start() const { 198 return fSegments.front().pts()[0]; 199 } 200 201 void toPath(SkPathWriter* path) const; 202 203 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); 223 return SkPathOpsVerbToPoints(segment.verb()) + 1; 224 } 225 226 #if DEBUG_TEST 227 SkTArray<SkOpSegment>& debugSegments() { 228 return fSegments; 229 } 230 #endif 231 232 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY 233 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); 242 static void debugShowWindingValues(const SkTArray<SkOpContour*, true>& contourList); 243 #endif 244 245 private: 246 void calcCommonCoincidentWinding(const SkCoincidence& ); 247 void joinCoincidence(const SkTArray<SkCoincidence, true>& , bool partial); 248 void setBounds(); 249 250 SkTArray<SkOpSegment> fSegments; 251 SkTArray<SkOpSegment*, true> fSortedSegments; 252 int fFirstSorted; 253 SkTArray<SkCoincidence, true> fCoincidences; 254 SkTArray<SkCoincidence, true> fPartialCoincidences; 255 SkTArray<const SkOpContour*, true> fCrosses; 256 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; 264 #ifdef SK_DEBUG 265 int fID; 266 #endif 267 }; 268 269 #endif 270