| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 #ifndef SkOpSegment_DEFINE | 7 #ifndef SkOpSegment_DEFINE |
| 8 #define SkOpSegment_DEFINE | 8 #define SkOpSegment_DEFINE |
| 9 | 9 |
| 10 #include "SkOpAngle.h" | 10 #include "SkOpAngle.h" |
| 11 #include "SkOpSpan.h" | 11 #include "SkOpSpan.h" |
| 12 #include "SkOpTAllocator.h" |
| 12 #include "SkPathOpsBounds.h" | 13 #include "SkPathOpsBounds.h" |
| 13 #include "SkPathOpsCurve.h" | 14 #include "SkPathOpsCurve.h" |
| 14 #include "SkTArray.h" | 15 |
| 15 #include "SkTDArray.h" | 16 class SkOpCoincidence; |
| 16 | 17 class SkOpContour; |
| 17 #if defined(SK_DEBUG) || !FORCE_RELEASE | |
| 18 #include "SkThread.h" | |
| 19 #endif | |
| 20 | |
| 21 struct SkCoincidence; | |
| 22 class SkPathWriter; | 18 class SkPathWriter; |
| 23 | 19 |
| 24 class SkOpSegment { | 20 class SkOpSegment { |
| 25 public: | 21 public: |
| 26 SkOpSegment() { | 22 enum AllowAlias { |
| 27 #if defined(SK_DEBUG) || !FORCE_RELEASE | 23 kAllowAlias, |
| 28 fID = sk_atomic_inc(&SkPathOpsDebug::gSegmentID); | 24 kNoAlias |
| 29 #endif | 25 }; |
| 30 } | |
| 31 | 26 |
| 32 bool operator<(const SkOpSegment& rh) const { | 27 bool operator<(const SkOpSegment& rh) const { |
| 33 return fBounds.fTop < rh.fBounds.fTop; | 28 return fBounds.fTop < rh.fBounds.fTop; |
| 34 } | 29 } |
| 35 | 30 |
| 36 struct AlignedSpan { | 31 SkOpAngle* activeAngle(SkOpSpanBase* start, SkOpSpanBase** startPtr, SkOpSpa
nBase** endPtr, |
| 37 double fOldT; | 32 bool* done, bool* sortable); |
| 38 double fT; | 33 SkOpAngle* activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** startPtr, |
| 39 SkPoint fOldPt; | 34 SkOpSpanBase** endPtr, bool* done, bool*
sortable); |
| 40 SkPoint fPt; | 35 SkOpAngle* activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** startPtr, |
| 41 const SkOpSegment* fSegment; | 36 SkOpSpanBase** endPtr, bool* done, bool*
sortable); |
| 42 const SkOpSegment* fOther1; | 37 bool activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask, int xor
SuMask, |
| 43 const SkOpSegment* fOther2; | 38 SkPathOp op); |
| 44 }; | 39 bool activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, SkOpSpanBas
e* end, SkPathOp op, |
| 40 int* sumMiWinding, int* sumSuWinding); |
| 41 |
| 42 SkPoint activeLeftTop(SkOpSpanBase** firstT); |
| 43 |
| 44 bool activeWinding(SkOpSpanBase* start, SkOpSpanBase* end); |
| 45 bool activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sumWinding); |
| 46 |
| 47 void addCubic(SkPoint pts[4], SkOpContour* parent) { |
| 48 init(pts, parent, SkPath::kCubic_Verb); |
| 49 fBounds.setCubicBounds(pts); |
| 50 } |
| 51 |
| 52 void addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end, SkPathWr
iter* path, |
| 53 bool active) const; |
| 54 |
| 55 SkOpAngle* addEndSpan(SkChunkAlloc* allocator) { |
| 56 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator); |
| 57 angle->set(&fTail, fTail.prev()); |
| 58 fTail.setFromAngle(angle); |
| 59 return angle; |
| 60 } |
| 61 |
| 62 void addLine(SkPoint pts[2], SkOpContour* parent) { |
| 63 init(pts, parent, SkPath::kLine_Verb); |
| 64 fBounds.set(pts, 2); |
| 65 } |
| 66 |
| 67 SkOpPtT* addMissing(double t, SkOpSegment* opp, SkChunkAlloc* ); |
| 68 SkOpAngle* addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle** , SkChu
nkAlloc* ); |
| 69 SkOpAngle* addSingletonAngles(int step, SkChunkAlloc* ); |
| 70 SkOpAngle* addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle** , SkChunk
Alloc* ); |
| 71 |
| 72 SkOpAngle* addStartSpan(SkChunkAlloc* allocator) { |
| 73 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator); |
| 74 angle->set(&fHead, fHead.next()); |
| 75 fHead.setToAngle(angle); |
| 76 return angle; |
| 77 } |
| 78 |
| 79 void addQuad(SkPoint pts[3], SkOpContour* parent) { |
| 80 init(pts, parent, SkPath::kQuad_Verb); |
| 81 fBounds.setQuadBounds(pts); |
| 82 } |
| 83 |
| 84 SkOpPtT* addT(double t, AllowAlias , SkChunkAlloc* ); |
| 85 |
| 86 void align(); |
| 87 static bool BetweenTs(const SkOpSpanBase* lesser, double testT, const SkOpSp
anBase* greater); |
| 45 | 88 |
| 46 const SkPathOpsBounds& bounds() const { | 89 const SkPathOpsBounds& bounds() const { |
| 47 return fBounds; | 90 return fBounds; |
| 48 } | 91 } |
| 49 | 92 |
| 50 // OPTIMIZE | 93 void bumpCount() { |
| 51 // when the edges are initially walked, they don't automatically get the pri
or and next | 94 ++fCount; |
| 52 // edges assigned to positions t=0 and t=1. Doing that would remove the need
for this check, | 95 } |
| 53 // and would additionally remove the need for similar checks in condition ed
ges. It would | 96 |
| 54 // also allow intersection code to assume end of segment intersections (mayb
e?) | 97 void calcAngles(SkChunkAlloc*); |
| 55 bool complete() const { | 98 void checkAngleCoin(SkOpCoincidence* coincidences, SkChunkAlloc* allocator); |
| 56 int count = fTs.count(); | 99 void checkNearCoincidence(SkOpAngle* ); |
| 57 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1; | 100 bool clockwise(const SkOpSpanBase* start, const SkOpSpanBase* end, bool* swa
p) const; |
| 101 static void ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle, |
| 102 SkOpAngle::IncludeType ); |
| 103 static void ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* next
Angle, |
| 104 SkOpAngle::IncludeType ); |
| 105 int computeSum(SkOpSpanBase* start, SkOpSpanBase* end, SkOpAngle::IncludeTyp
e includeType); |
| 106 |
| 107 SkOpContour* contour() const { |
| 108 return fContour; |
| 58 } | 109 } |
| 59 | 110 |
| 60 int count() const { | 111 int count() const { |
| 61 return fTs.count(); | 112 return fCount; |
| 62 } | 113 } |
| 114 |
| 115 SkOpSpan* crossedSpanY(const SkPoint& basePt, double mid, bool opp, bool cur
rent, |
| 116 SkScalar* bestY, double* hitT, bool* hitSomething, b
ool* vertical); |
| 117 |
| 118 void debugAddAngle(double startT, double endT, SkChunkAlloc*); |
| 119 const SkOpAngle* debugAngle(int id) const; |
| 120 SkOpContour* debugContour(int id); |
| 121 |
| 122 int debugID() const { |
| 123 return PATH_OPS_DEBUG_RELEASE(fID, -1); |
| 124 } |
| 125 |
| 126 #if DEBUG_SWAP_TOP |
| 127 int debugInflections(const SkOpSpanBase* start, const SkOpSpanBase* end) con
st; |
| 128 #endif |
| 129 |
| 130 SkOpAngle* debugLastAngle(); |
| 131 const SkOpPtT* debugPtT(int id) const; |
| 132 void debugReset(); |
| 133 const SkOpSegment* debugSegment(int id) const; |
| 134 |
| 135 #if DEBUG_ACTIVE_SPANS |
| 136 void debugShowActiveSpans() const; |
| 137 #endif |
| 138 #if DEBUG_MARK_DONE |
| 139 void debugShowNewWinding(const char* fun, const SkOpSpan* span, int winding)
; |
| 140 void debugShowNewWinding(const char* fun, const SkOpSpan* span, int winding,
int oppWinding); |
| 141 #endif |
| 142 |
| 143 const SkOpSpanBase* debugSpan(int id) const; |
| 144 void debugValidate() const; |
| 145 void detach(const SkOpSpan* ); |
| 146 double distSq(double t, SkOpAngle* opp); |
| 63 | 147 |
| 64 bool done() const { | 148 bool done() const { |
| 65 SkASSERT(fDoneSpans <= fTs.count()); | 149 SkASSERT(fDoneCount <= fCount); |
| 66 return fDoneSpans == fTs.count(); | 150 return fDoneCount == fCount; |
| 67 } | |
| 68 | |
| 69 bool done(int min) const { | |
| 70 return fTs[min].fDone; | |
| 71 } | 151 } |
| 72 | 152 |
| 73 bool done(const SkOpAngle* angle) const { | 153 bool done(const SkOpAngle* angle) const { |
| 74 return done(SkMin32(angle->start(), angle->end())); | 154 return angle->start()->starter(angle->end())->done(); |
| 75 } | 155 } |
| 76 | 156 |
| 77 SkDPoint dPtAtT(double mid) const { | 157 SkDPoint dPtAtT(double mid) const { |
| 78 return (*CurveDPointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid); | 158 return (*CurveDPointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid); |
| 79 } | 159 } |
| 80 | 160 |
| 81 SkVector dxdy(int index) const { | 161 SkDVector dSlopeAtT(double mid) const { |
| 82 return (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fTs[index].f
T); | 162 return (*CurveDSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid); |
| 83 } | 163 } |
| 84 | 164 |
| 85 SkScalar dy(int index) const { | 165 void dump() const; |
| 86 return dxdy(index).fY; | 166 void dumpAll() const; |
| 87 } | 167 void dumpAngles() const; |
| 88 | 168 void dumpCoin() const; |
| 89 bool hasMultiples() const { | 169 void dumpPts() const; |
| 90 return fMultiples; | 170 |
| 91 } | 171 SkOpSegment* findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** next
Start, |
| 92 | 172 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp
op, |
| 93 bool hasSmall() const { | 173 int xorMiMask, int xorSuMask); |
| 94 return fSmall; | 174 SkOpSegment* findNextWinding(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase**
nextStart, |
| 95 } | 175 SkOpSpanBase** nextEnd, bool* unsortable); |
| 96 | 176 SkOpSegment* findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, b
ool* unsortable); |
| 97 bool hasTiny() const { | 177 SkOpSegment* findTop(bool firstPass, SkOpSpanBase** startPtr, SkOpSpanBase**
endPtr, |
| 98 return fTiny; | 178 bool* unsortable, SkChunkAlloc* ); |
| 99 } | 179 SkOpGlobalState* globalState() const; |
| 100 | 180 |
| 101 bool intersected() const { | 181 const SkOpSpan* head() const { |
| 102 return fTs.count() > 0; | 182 return &fHead; |
| 103 } | 183 } |
| 104 | 184 |
| 105 bool isCanceled(int tIndex) const { | 185 SkOpSpan* head() { |
| 106 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0; | 186 return &fHead; |
| 107 } | 187 } |
| 108 | 188 |
| 109 bool isConnected(int startIndex, int endIndex) const { | 189 void init(SkPoint pts[], SkOpContour* parent, SkPath::Verb verb); |
| 110 return fTs[startIndex].fWindSum != SK_MinS32 || fTs[endIndex].fWindSum !
= SK_MinS32; | 190 void initWinding(SkOpSpanBase* start, SkOpSpanBase* end, |
| 111 } | 191 SkOpAngle::IncludeType angleIncludeType); |
| 192 bool initWinding(SkOpSpanBase* start, SkOpSpanBase* end, double tHit, int wi
nding, |
| 193 SkScalar hitDx, int oppWind, SkScalar hitOppDx); |
| 194 |
| 195 SkOpSpan* insert(SkOpSpan* prev, SkChunkAlloc* allocator) { |
| 196 SkOpSpan* result = SkOpTAllocator<SkOpSpan>::Allocate(allocator); |
| 197 SkOpSpanBase* next = prev->next(); |
| 198 result->setPrev(prev); |
| 199 prev->setNext(result); |
| 200 SkDEBUGCODE(result->ptT()->fT = 0); |
| 201 result->setNext(next); |
| 202 if (next) { |
| 203 next->setPrev(result); |
| 204 } |
| 205 return result; |
| 206 } |
| 207 |
| 208 bool isClose(double t, const SkOpSegment* opp) const; |
| 112 | 209 |
| 113 bool isHorizontal() const { | 210 bool isHorizontal() const { |
| 114 return fBounds.fTop == fBounds.fBottom; | 211 return fBounds.fTop == fBounds.fBottom; |
| 115 } | 212 } |
| 116 | 213 |
| 214 SkOpSegment* isSimple(SkOpSpanBase** end, int* step) { |
| 215 return nextChase(end, step, NULL, NULL); |
| 216 } |
| 217 |
| 117 bool isVertical() const { | 218 bool isVertical() const { |
| 118 return fBounds.fLeft == fBounds.fRight; | 219 return fBounds.fLeft == fBounds.fRight; |
| 119 } | 220 } |
| 120 | 221 |
| 121 bool isVertical(int start, int end) const { | 222 bool isVertical(SkOpSpanBase* start, SkOpSpanBase* end) const { |
| 122 return (*CurveIsVertical[SkPathOpsVerbToPoints(fVerb)])(fPts, start, end
); | 223 return (*CurveIsVertical[SkPathOpsVerbToPoints(fVerb)])(fPts, start->t()
, end->t()); |
| 123 } | 224 } |
| 124 | 225 |
| 125 bool operand() const { | 226 bool isXor() const; |
| 126 return fOperand; | 227 |
| 127 } | 228 const SkPoint& lastPt() const { |
| 128 | 229 return fPts[SkPathOpsVerbToPoints(fVerb)]; |
| 129 int oppSign(const SkOpAngle* angle) const { | 230 } |
| 130 SkASSERT(angle->segment() == this); | 231 |
| 131 return oppSign(angle->start(), angle->end()); | 232 SkOpSpanBase* markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end); |
| 132 } | 233 bool markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding
, |
| 133 | 234 SkOpSpanBase** lastPtr); |
| 134 int oppSign(int startIndex, int endIndex) const { | 235 bool markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding
, |
| 135 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue : fTs[en
dIndex].fOppValue; | 236 int oppWinding, SkOpSpanBase** lastPtr); |
| 136 #if DEBUG_WIND_BUMP | 237 SkOpSpanBase* markAngle(int maxWinding, int sumWinding, const SkOpAngle* ang
le); |
| 137 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result); | 238 SkOpSpanBase* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, i
nt oppSumWinding, |
| 138 #endif | 239 const SkOpAngle* angle); |
| 240 void markDone(SkOpSpan* ); |
| 241 bool markWinding(SkOpSpan* , int winding); |
| 242 bool markWinding(SkOpSpan* , int winding, int oppWinding); |
| 243 bool match(const SkOpPtT* span, const SkOpSegment* parent, double t, const S
kPoint& pt) const; |
| 244 void missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc* allocat
or); |
| 245 bool monotonicInY(const SkOpSpanBase* start, const SkOpSpanBase* end) const; |
| 246 bool moveNearby(); |
| 247 |
| 248 SkOpSegment* next() const { |
| 249 return fNext; |
| 250 } |
| 251 |
| 252 static bool NextCandidate(SkOpSpanBase* span, SkOpSpanBase** start, SkOpSpan
Base** end); |
| 253 SkOpSegment* nextChase(SkOpSpanBase** , int* step, SkOpSpan** , SkOpSpanBase
** last) const; |
| 254 bool operand() const; |
| 255 |
| 256 static int OppSign(const SkOpSpanBase* start, const SkOpSpanBase* end) { |
| 257 int result = start->t() < end->t() ? -start->upCast()->oppValue() |
| 258 : end->upCast()->oppValue(); |
| 139 return result; | 259 return result; |
| 140 } | 260 } |
| 141 | 261 |
| 142 int oppSum(int tIndex) const { | 262 bool oppXor() const; |
| 143 return fTs[tIndex].fOppSum; | 263 |
| 144 } | 264 const SkOpSegment* prev() const { |
| 145 | 265 return fPrev; |
| 146 int oppSum(const SkOpAngle* angle) const { | 266 } |
| 147 int lesser = SkMin32(angle->start(), angle->end()); | |
| 148 return fTs[lesser].fOppSum; | |
| 149 } | |
| 150 | |
| 151 int oppValue(int tIndex) const { | |
| 152 return fTs[tIndex].fOppValue; | |
| 153 } | |
| 154 | |
| 155 int oppValue(const SkOpAngle* angle) const { | |
| 156 int lesser = SkMin32(angle->start(), angle->end()); | |
| 157 return fTs[lesser].fOppValue; | |
| 158 } | |
| 159 | |
| 160 #if DEBUG_VALIDATE | |
| 161 bool oppXor() const { | |
| 162 return fOppXor; | |
| 163 } | |
| 164 #endif | |
| 165 | 267 |
| 166 SkPoint ptAtT(double mid) const { | 268 SkPoint ptAtT(double mid) const { |
| 167 return (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid); | 269 return (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid); |
| 168 } | 270 } |
| 169 | 271 |
| 170 const SkPoint* pts() const { | 272 const SkPoint* pts() const { |
| 171 return fPts; | 273 return fPts; |
| 172 } | 274 } |
| 173 | 275 |
| 174 void reset() { | 276 bool ptsDisjoint(const SkOpPtT& span, const SkOpPtT& test) const { |
| 175 init(NULL, (SkPath::Verb) -1, false, false); | 277 return ptsDisjoint(span.fT, span.fPt, test.fT, test.fPt); |
| 176 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax); | |
| 177 fTs.reset(); | |
| 178 } | 278 } |
| 179 | 279 |
| 180 bool reversePoints(const SkPoint& p1, const SkPoint& p2) const; | 280 bool ptsDisjoint(const SkOpPtT& span, double t, const SkPoint& pt) const { |
| 181 | 281 return ptsDisjoint(span.fT, span.fPt, t, pt); |
| 182 void setOppXor(bool isOppXor) { | |
| 183 fOppXor = isOppXor; | |
| 184 } | 282 } |
| 185 | 283 |
| 186 void setUpWinding(int index, int endIndex, int* maxWinding, int* sumWinding)
{ | 284 bool ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt
2) const; |
| 187 int deltaSum = spanSign(index, endIndex); | 285 |
| 286 void resetVisited() { |
| 287 fVisited = false; |
| 288 } |
| 289 |
| 290 void setContour(SkOpContour* contour) { |
| 291 fContour = contour; |
| 292 } |
| 293 |
| 294 void setNext(SkOpSegment* next) { |
| 295 fNext = next; |
| 296 } |
| 297 |
| 298 void setPrev(SkOpSegment* prev) { |
| 299 fPrev = prev; |
| 300 } |
| 301 |
| 302 bool setVisited() { |
| 303 if (fVisited) { |
| 304 return false; |
| 305 } |
| 306 return (fVisited = true); |
| 307 } |
| 308 |
| 309 void setUpWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* maxWinding, i
nt* sumWinding) { |
| 310 int deltaSum = SpanSign(start, end); |
| 188 *maxWinding = *sumWinding; | 311 *maxWinding = *sumWinding; |
| 189 *sumWinding -= deltaSum; | 312 *sumWinding -= deltaSum; |
| 190 } | 313 } |
| 191 | 314 |
| 192 const SkOpSpan& span(int tIndex) const { | 315 void setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding
, |
| 193 return fTs[tIndex]; | 316 int* maxWinding, int* sumWinding); |
| 194 } | 317 void setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding
, int* sumSuWinding, |
| 318 int* maxWinding, int* sumWinding, int* oppMaxWinding, int
* oppSumWinding); |
| 319 void sortAngles(); |
| 195 | 320 |
| 196 const SkOpAngle* spanToAngle(int tStart, int tEnd) const { | 321 static int SpanSign(const SkOpSpanBase* start, const SkOpSpanBase* end) { |
| 197 SkASSERT(tStart != tEnd); | 322 int result = start->t() < end->t() ? -start->upCast()->windValue() |
| 198 const SkOpSpan& span = fTs[tStart]; | 323 : end->upCast()->windValue(); |
| 199 return tStart < tEnd ? span.fToAngle : span.fFromAngle; | |
| 200 } | |
| 201 | |
| 202 // FIXME: create some sort of macro or template that avoids casting | |
| 203 SkOpAngle* spanToAngle(int tStart, int tEnd) { | |
| 204 const SkOpAngle* cAngle = (const_cast<const SkOpSegment*>(this))->spanTo
Angle(tStart, tEnd); | |
| 205 return const_cast<SkOpAngle*>(cAngle); | |
| 206 } | |
| 207 | |
| 208 int spanSign(const SkOpAngle* angle) const { | |
| 209 SkASSERT(angle->segment() == this); | |
| 210 return spanSign(angle->start(), angle->end()); | |
| 211 } | |
| 212 | |
| 213 int spanSign(int startIndex, int endIndex) const { | |
| 214 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue : fTs[e
ndIndex].fWindValue; | |
| 215 #if DEBUG_WIND_BUMP | |
| 216 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result); | |
| 217 #endif | |
| 218 return result; | 324 return result; |
| 219 } | 325 } |
| 220 | 326 |
| 221 double t(int tIndex) const { | 327 SkOpAngle* spanToAngle(SkOpSpanBase* start, SkOpSpanBase* end) { |
| 222 return fTs[tIndex].fT; | 328 SkASSERT(start != end); |
| 329 return start->t() < end->t() ? start->upCast()->toAngle() : start->fromA
ngle(); |
| 223 } | 330 } |
| 224 | 331 |
| 225 double tAtMid(int start, int end, double mid) const { | 332 bool subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end, SkPoint e
dge[4]) const; |
| 226 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid; | 333 bool subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end, SkDCubic*
result) const; |
| 334 void subDivideBounds(const SkOpSpanBase* start, const SkOpSpanBase* end, |
| 335 SkPathOpsBounds* bounds) const; |
| 336 |
| 337 const SkOpSpanBase* tail() const { |
| 338 return &fTail; |
| 227 } | 339 } |
| 228 | 340 |
| 229 void updatePts(const SkPoint pts[]) { | 341 SkOpSpanBase* tail() { |
| 230 fPts = pts; | 342 return &fTail; |
| 231 } | 343 } |
| 232 | 344 |
| 345 static double TAtMid(const SkOpSpanBase* start, const SkOpSpanBase* end, dou
ble mid) { |
| 346 return start->t() * (1 - mid) + end->t() * mid; |
| 347 } |
| 348 |
| 349 void undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end); |
| 350 int updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) con
st; |
| 351 int updateOppWinding(const SkOpAngle* angle) const; |
| 352 int updateOppWindingReverse(const SkOpAngle* angle) const; |
| 353 int updateWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const; |
| 354 int updateWinding(const SkOpAngle* angle) const; |
| 355 int updateWindingReverse(const SkOpAngle* angle) const; |
| 356 |
| 357 static bool UseInnerWinding(int outerWinding, int innerWinding); |
| 358 |
| 233 SkPath::Verb verb() const { | 359 SkPath::Verb verb() const { |
| 234 return fVerb; | 360 return fVerb; |
| 235 } | 361 } |
| 236 | 362 |
| 237 int windSum(int tIndex) const { | 363 int windingAtT(double tHit, const SkOpSpan* span, bool crossOpp, SkScalar* d
x) const; |
| 238 return fTs[tIndex].fWindSum; | 364 int windSum(const SkOpAngle* angle) const; |
| 365 |
| 366 SkPoint* writablePt(bool end) { |
| 367 return &fPts[end ? SkPathOpsVerbToPoints(fVerb) : 0]; |
| 239 } | 368 } |
| 240 | 369 |
| 241 int windValue(int tIndex) const { | |
| 242 return fTs[tIndex].fWindValue; | |
| 243 } | |
| 244 | |
| 245 #if defined(SK_DEBUG) || DEBUG_WINDING | |
| 246 SkScalar xAtT(int index) const { | |
| 247 return xAtT(&fTs[index]); | |
| 248 } | |
| 249 #endif | |
| 250 | |
| 251 #if DEBUG_VALIDATE | |
| 252 bool _xor() const { // FIXME: used only by SkOpAngle::debugValidateLoop() | |
| 253 return fXor; | |
| 254 } | |
| 255 #endif | |
| 256 | |
| 257 const SkPoint& xyAtT(const SkOpSpan* span) const { | |
| 258 return span->fPt; | |
| 259 } | |
| 260 | |
| 261 const SkPoint& xyAtT(int index) const { | |
| 262 return xyAtT(&fTs[index]); | |
| 263 } | |
| 264 | |
| 265 #if defined(SK_DEBUG) || DEBUG_WINDING | |
| 266 SkScalar yAtT(int index) const { | |
| 267 return yAtT(&fTs[index]); | |
| 268 } | |
| 269 #endif | |
| 270 | |
| 271 const SkOpAngle* activeAngle(int index, int* start, int* end, bool* done, | |
| 272 bool* sortable) const; | |
| 273 SkPoint activeLeftTop(int* firstT) const; | |
| 274 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathO
p op); | |
| 275 bool activeWinding(int index, int endIndex); | |
| 276 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd); | |
| 277 void addCurveTo(int start, int end, SkPathWriter* path, bool active) const; | |
| 278 void addEndSpan(int endIndex); | |
| 279 void addLine(const SkPoint pts[2], bool operand, bool evenOdd); | |
| 280 void addOtherT(int index, double otherT, int otherIndex); | |
| 281 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd); | |
| 282 void addSimpleAngle(int endIndex); | |
| 283 int addSelfT(const SkPoint& pt, double newT); | |
| 284 void addStartSpan(int endIndex); | |
| 285 int addT(SkOpSegment* other, const SkPoint& pt, double newT); | |
| 286 void addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* o
ther); | |
| 287 bool addTCoincident(const SkPoint& startPt, const SkPoint& endPt, double end
T, | |
| 288 SkOpSegment* other); | |
| 289 const SkOpSpan* addTPair(double t, SkOpSegment* other, double otherT, bool b
orrowWind, | |
| 290 const SkPoint& pt); | |
| 291 const SkOpSpan* addTPair(double t, SkOpSegment* other, double otherT, bool b
orrowWind, | |
| 292 const SkPoint& pt, const SkPoint& oPt); | |
| 293 void alignMultiples(SkTDArray<AlignedSpan>* aligned); | |
| 294 bool alignSpan(int index, double thisT, const SkPoint& thisPt); | |
| 295 void alignSpanState(int start, int end); | |
| 296 bool betweenTs(int lesser, double testT, int greater) const; | |
| 297 void blindCancel(const SkCoincidence& coincidence, SkOpSegment* other); | |
| 298 void blindCoincident(const SkCoincidence& coincidence, SkOpSegment* other); | |
| 299 bool calcAngles(); | |
| 300 double calcMissingTEnd(const SkOpSegment* ref, double loEnd, double min, dou
ble max, | |
| 301 double hiEnd, const SkOpSegment* other, int thisEnd); | |
| 302 double calcMissingTStart(const SkOpSegment* ref, double loEnd, double min, d
ouble max, | |
| 303 double hiEnd, const SkOpSegment* other, int thisEnd
); | |
| 304 void checkDuplicates(); | |
| 305 bool checkEnds(); | |
| 306 void checkMultiples(); | |
| 307 void checkSmall(); | |
| 308 bool checkSmall(int index) const; | |
| 309 void checkTiny(); | |
| 310 int computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeT
ype); | |
| 311 bool containsPt(const SkPoint& , int index, int endIndex) const; | |
| 312 int crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT, bool*
hitSomething, | |
| 313 double mid, bool opp, bool current) const; | |
| 314 bool findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* other, int
oStart, int oEnd, | |
| 315 int step, SkPoint* startPt, SkPoint* endPt, double*
endT) const; | |
| 316 SkOpSegment* findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* ne
xtEnd, | |
| 317 bool* unsortable, SkPathOp op, int xorMiMask, int xo
rSuMask); | |
| 318 SkOpSegment* findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart, in
t* nextEnd, | |
| 319 bool* unsortable); | |
| 320 SkOpSegment* findNextXor(int* nextStart, int* nextEnd, bool* unsortable); | |
| 321 int findExactT(double t, const SkOpSegment* ) const; | |
| 322 int findOtherT(double t, const SkOpSegment* ) const; | |
| 323 int findT(double t, const SkPoint& , const SkOpSegment* ) const; | |
| 324 SkOpSegment* findTop(int* tIndex, int* endIndex, bool* unsortable, bool firs
tPass); | |
| 325 void fixOtherTIndex(); | |
| 326 bool inconsistentAngle(int maxWinding, int sumWinding, int oppMaxWinding, in
t oppSumWinding, | |
| 327 const SkOpAngle* angle) const; | |
| 328 void initWinding(int start, int end, SkOpAngle::IncludeType angleIncludeType
); | |
| 329 bool initWinding(int start, int end, double tHit, int winding, SkScalar hitD
x, int oppWind, | |
| 330 SkScalar hitOppDx); | |
| 331 bool isMissing(double startT, const SkPoint& pt) const; | |
| 332 bool isTiny(const SkOpAngle* angle) const; | |
| 333 bool joinCoincidence(SkOpSegment* other, double otherT, const SkPoint& other
Pt, int step, | |
| 334 bool cancel); | |
| 335 SkOpSpan* markAndChaseDoneBinary(int index, int endIndex); | |
| 336 SkOpSpan* markAndChaseDoneUnary(int index, int endIndex); | |
| 337 bool markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding
, | |
| 338 SkOpSpan** lastPtr); | |
| 339 SkOpSpan* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int o
ppSumWinding, | |
| 340 const SkOpAngle* angle); | |
| 341 void markDone(int index, int winding); | |
| 342 void markDoneBinary(int index); | |
| 343 void markDoneFinal(int index); | |
| 344 void markDoneUnary(int index); | |
| 345 bool nextCandidate(int* start, int* end) const; | |
| 346 int nextSpan(int from, int step) const; | |
| 347 void pinT(const SkPoint& pt, double* t); | |
| 348 void setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWin
ding, | |
| 349 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWin
ding); | |
| 350 void sortAngles(); | |
| 351 bool subDivide(int start, int end, SkPoint edge[4]) const; | |
| 352 bool subDivide(int start, int end, SkDCubic* result) const; | |
| 353 void undoneSpan(int* start, int* end); | |
| 354 int updateOppWindingReverse(const SkOpAngle* angle) const; | |
| 355 int updateWindingReverse(const SkOpAngle* angle) const; | |
| 356 static bool UseInnerWinding(int outerWinding, int innerWinding); | |
| 357 static bool UseInnerWindingReverse(int outerWinding, int innerWinding); | |
| 358 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const; | |
| 359 int windSum(const SkOpAngle* angle) const; | |
| 360 // available for testing only | |
| 361 #if defined(SK_DEBUG) || !FORCE_RELEASE | |
| 362 int debugID() const { | |
| 363 return fID; | |
| 364 } | |
| 365 #else | |
| 366 int debugID() const { | |
| 367 return -1; | |
| 368 } | |
| 369 #endif | |
| 370 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY | |
| 371 void debugShowActiveSpans() const; | |
| 372 #endif | |
| 373 #if DEBUG_CONCIDENT | |
| 374 void debugShowTs(const char* prefix) const; | |
| 375 #endif | |
| 376 #if DEBUG_SHOW_WINDING | |
| 377 int debugShowWindingValues(int slotCount, int ofInterest) const; | |
| 378 #endif | |
| 379 const SkTDArray<SkOpSpan>& debugSpans() const; | |
| 380 void debugValidate() const; | |
| 381 // available to testing only | |
| 382 const SkOpAngle* debugLastAngle() const; | |
| 383 void dumpAngles() const; | |
| 384 void dumpContour(int firstID, int lastID) const; | |
| 385 void dumpPts() const; | |
| 386 void dumpSpans() const; | |
| 387 | |
| 388 private: | 370 private: |
| 389 struct MissingSpan { | 371 SkOpSpan fHead; // the head span always has its t set to zero |
| 390 double fT; | 372 SkOpSpanBase fTail; // the tail span always has its t set to one |
| 391 double fEndT; | 373 SkOpContour* fContour; |
| 392 SkOpSegment* fSegment; | 374 SkOpSegment* fNext; // forward-only linked list used by contour to walk the
segments |
| 393 SkOpSegment* fOther; | 375 const SkOpSegment* fPrev; |
| 394 double fOtherT; | 376 SkPoint* fPts; // pointer into array of points owned by edge builder that m
ay be tweaked |
| 395 SkPoint fPt; | 377 SkPathOpsBounds fBounds; // tight bounds |
| 396 }; | 378 int fCount; // number of spans (one for a non-intersecting segment) |
| 397 | 379 int fDoneCount; // number of processed spans (zero initially) |
| 398 const SkOpAngle* activeAngleInner(int index, int* start, int* end, bool* don
e, | |
| 399 bool* sortable) const; | |
| 400 const SkOpAngle* activeAngleOther(int index, int* start, int* end, bool* don
e, | |
| 401 bool* sortable) const; | |
| 402 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathO
p op, | |
| 403 int* sumMiWinding, int* sumSuWinding); | |
| 404 bool activeWinding(int index, int endIndex, int* sumWinding); | |
| 405 void addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt, SkOpSeg
ment* other); | |
| 406 void addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt, SkOpSegme
nt* other); | |
| 407 SkOpAngle* addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle** ); | |
| 408 SkOpAngle* addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle** ); | |
| 409 SkOpAngle* addSingletonAngles(int step); | |
| 410 void alignRange(int lower, int upper, const SkOpSegment* other, int oLower,
int oUpper); | |
| 411 void alignSpan(const SkPoint& newPt, double newT, const SkOpSegment* other,
double otherT, | |
| 412 const SkOpSegment* other2, SkOpSpan* oSpan, SkTDArray<Aligned
Span>* ); | |
| 413 bool betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) cons
t; | |
| 414 void bumpCoincidentBlind(bool binary, int index, int last); | |
| 415 bool bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* index, | |
| 416 SkTArray<SkPoint, true>* outsideTs); | |
| 417 void bumpCoincidentOBlind(int index, int last); | |
| 418 bool bumpCoincidentOther(const SkOpSpan& oTest, int* index, | |
| 419 SkTArray<SkPoint, true>* outsideTs, const SkPoint&
endPt); | |
| 420 bool bumpSpan(SkOpSpan* span, int windDelta, int oppDelta); | |
| 421 bool calcLoopSpanCount(const SkOpSpan& thisSpan, int* smallCounts); | |
| 422 bool checkForSmall(const SkOpSpan* span, const SkPoint& pt, double newT, | |
| 423 int* less, int* more) const; | |
| 424 void checkLinks(const SkOpSpan* , | |
| 425 SkTArray<MissingSpan, true>* missingSpans) const; | |
| 426 static void CheckOneLink(const SkOpSpan* test, const SkOpSpan* oSpan, | |
| 427 const SkOpSpan* oFirst, const SkOpSpan* oLast, | |
| 428 const SkOpSpan** missingPtr, | |
| 429 SkTArray<MissingSpan, true>* missingSpans); | |
| 430 int checkSetAngle(int tIndex) const; | |
| 431 void checkSmallCoincidence(const SkOpSpan& span, SkTArray<MissingSpan, true>
* ); | |
| 432 bool coincidentSmall(const SkPoint& pt, double t, const SkOpSegment* other)
const; | |
| 433 bool clockwise(int tStart, int tEnd, bool* swap) const; | |
| 434 static void ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle, | |
| 435 SkOpAngle::IncludeType ); | |
| 436 static void ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* next
Angle, | |
| 437 SkOpAngle::IncludeType ); | |
| 438 bool containsT(double t, const SkOpSegment* other, double otherT) const; | |
| 439 bool decrementSpan(SkOpSpan* span); | |
| 440 int findEndSpan(int endIndex) const; | |
| 441 int findStartSpan(int startIndex) const; | |
| 442 int firstActive(int tIndex) const; | |
| 443 const SkOpSpan& firstSpan(const SkOpSpan& thisSpan) const; | |
| 444 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd
); | |
| 445 bool inCoincidentSpan(double t, const SkOpSegment* other) const; | |
| 446 bool inconsistentWinding(const SkOpAngle* , int maxWinding, int oppMaxWindin
g) const; | |
| 447 bool inconsistentWinding(int min, int maxWinding, int oppMaxWinding) const; | |
| 448 bool inconsistentWinding(const char* funName, int tIndex, int winding, int o
ppWinding) const; | |
| 449 bool inLoop(const SkOpAngle* baseAngle, int spanCount, int* indexPtr) const; | |
| 450 #if OLD_CHASE | |
| 451 bool isSimple(int end) const; | |
| 452 #else | |
| 453 SkOpSegment* isSimple(int* end, int* step); | |
| 454 #endif | |
| 455 bool isTiny(int index) const; | |
| 456 const SkOpSpan& lastSpan(const SkOpSpan& thisSpan) const; | |
| 457 void matchWindingValue(int tIndex, double t, bool borrowWind); | |
| 458 SkOpSpan* markAndChaseDone(int index, int endIndex, int winding); | |
| 459 SkOpSpan* markAndChaseDoneBinary(const SkOpAngle* angle, int winding, int op
pWinding); | |
| 460 bool markAndChaseWinding(const SkOpAngle* angle, int winding, SkOpSpan** las
tPtr); | |
| 461 bool markAndChaseWinding(int index, int endIndex, int winding, SkOpSpan** la
stPtr); | |
| 462 bool markAndChaseWinding(int index, int endIndex, int winding, int oppWindin
g, | |
| 463 SkOpSpan** lastPtr); | |
| 464 SkOpSpan* markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle); | |
| 465 void markDoneBinary(int index, int winding, int oppWinding); | |
| 466 SkOpSpan* markAndChaseDoneUnary(const SkOpAngle* angle, int winding); | |
| 467 void markOneDone(const char* funName, int tIndex, int winding); | |
| 468 void markOneDoneBinary(const char* funName, int tIndex); | |
| 469 void markOneDoneBinary(const char* funName, int tIndex, int winding, int opp
Winding); | |
| 470 void markOneDoneFinal(const char* funName, int tIndex); | |
| 471 void markOneDoneUnary(const char* funName, int tIndex); | |
| 472 bool markOneWinding(const char* funName, int tIndex, int winding, SkOpSpan**
lastPtr); | |
| 473 bool markOneWinding(const char* funName, int tIndex, int winding, int oppWin
ding, | |
| 474 SkOpSpan** lastPtr); | |
| 475 bool markWinding(int index, int winding); | |
| 476 bool markWinding(int index, int winding, int oppWinding); | |
| 477 bool monotonicInY(int tStart, int tEnd) const; | |
| 478 | |
| 479 bool multipleEnds() const { return fTs[count() - 2].fT == 1; } | |
| 480 bool multipleStarts() const { return fTs[1].fT == 0; } | |
| 481 | |
| 482 SkOpSegment* nextChase(int* index, int* step, int* min, SkOpSpan** last) con
st; | |
| 483 int nextExactSpan(int from, int step) const; | |
| 484 void resetSpanFlags(); | |
| 485 bool serpentine(int tStart, int tEnd) const; | |
| 486 void setCoincidentRange(const SkPoint& startPt, const SkPoint& endPt, SkOpS
egment* other); | |
| 487 void setFromAngle(int endIndex, SkOpAngle* ); | |
| 488 void setSpanFlags(const SkPoint& pt, double newT, SkOpSpan* span); | |
| 489 void setToAngle(int endIndex, SkOpAngle* ); | |
| 490 void setUpWindings(int index, int endIndex, int* sumMiWinding, | |
| 491 int* maxWinding, int* sumWinding); | |
| 492 void subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const; | |
| 493 static void TrackOutsidePair(SkTArray<SkPoint, true>* outsideTs, const SkPoi
nt& endPt, | |
| 494 const SkPoint& startPt); | |
| 495 static void TrackOutside(SkTArray<SkPoint, true>* outsideTs, const SkPoint&
startPt); | |
| 496 int updateOppWinding(int index, int endIndex) const; | |
| 497 int updateOppWinding(const SkOpAngle* angle) const; | |
| 498 int updateWinding(int index, int endIndex) const; | |
| 499 int updateWinding(const SkOpAngle* angle) const; | |
| 500 int updateWindingReverse(int index, int endIndex) const; | |
| 501 SkOpSpan* verifyOneWinding(const char* funName, int tIndex); | |
| 502 SkOpSpan* verifyOneWindingU(const char* funName, int tIndex); | |
| 503 | |
| 504 SkScalar xAtT(const SkOpSpan* span) const { | |
| 505 return xyAtT(span).fX; | |
| 506 } | |
| 507 | |
| 508 SkScalar yAtT(const SkOpSpan* span) const { | |
| 509 return xyAtT(span).fY; | |
| 510 } | |
| 511 | |
| 512 void zeroSpan(SkOpSpan* span); | |
| 513 | |
| 514 #if DEBUG_SWAP_TOP | |
| 515 bool controlsContainedByEnds(int tStart, int tEnd) const; | |
| 516 #endif | |
| 517 void debugAddAngle(int start, int end); | |
| 518 #if DEBUG_CONCIDENT | |
| 519 void debugAddTPair(double t, const SkOpSegment& other, double otherT) const; | |
| 520 #endif | |
| 521 #if DEBUG_ANGLE | |
| 522 void debugCheckPointsEqualish(int tStart, int tEnd) const; | |
| 523 #endif | |
| 524 #if DEBUG_SWAP_TOP | |
| 525 int debugInflections(int index, int endIndex) const; | |
| 526 #endif | |
| 527 #if DEBUG_MARK_DONE || DEBUG_UNSORTABLE | |
| 528 void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding)
; | |
| 529 void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding,
int oppWinding); | |
| 530 #endif | |
| 531 #if DEBUG_WINDING | |
| 532 static char as_digit(int value) { | |
| 533 return value < 0 ? '?' : value <= 9 ? '0' + value : '+'; | |
| 534 } | |
| 535 #endif | |
| 536 // available to testing only | |
| 537 void debugConstruct(); | |
| 538 void debugConstructCubic(SkPoint shortQuad[4]); | |
| 539 void debugConstructLine(SkPoint shortQuad[2]); | |
| 540 void debugConstructQuad(SkPoint shortQuad[3]); | |
| 541 void debugReset(); | |
| 542 void dumpDPts() const; | |
| 543 void dumpHexPts() const; | |
| 544 void dumpSpan(int index) const; | |
| 545 | |
| 546 const SkPoint* fPts; | |
| 547 SkPathOpsBounds fBounds; | |
| 548 // FIXME: can't convert to SkTArray because it uses insert | |
| 549 SkTDArray<SkOpSpan> fTs; // 2+ (always includes t=0 t=1) -- at least (numbe
r of spans) + 1 | |
| 550 SkOpAngleSet fAngles; // empty or 2+ -- (number of non-zero spans) * 2 | |
| 551 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized v
alue | |
| 552 int fDoneSpans; // quick check that segment is finished | |
| 553 // OPTIMIZATION: force the following to be byte-sized | |
| 554 SkPath::Verb fVerb; | 380 SkPath::Verb fVerb; |
| 555 bool fLoop; // set if cubic intersects itself | 381 bool fVisited; // used by missing coincidence check |
| 556 bool fMultiples; // set if curve intersects multiple other curves at one in
terior point | 382 PATH_OPS_DEBUG_CODE(int fID); |
| 557 bool fOperand; | |
| 558 bool fXor; // set if original contour had even-odd fill | |
| 559 bool fOppXor; // set if opposite operand had even-odd fill | |
| 560 bool fSmall; // set if some span is small | |
| 561 bool fTiny; // set if some span is tiny | |
| 562 #if defined(SK_DEBUG) || !FORCE_RELEASE | |
| 563 int fID; | |
| 564 #endif | |
| 565 | |
| 566 friend class PathOpsSegmentTester; | |
| 567 }; | 383 }; |
| 568 | 384 |
| 569 #endif | 385 #endif |
| OLD | NEW |