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 |