Chromium Code Reviews

Side by Side Diff: src/pathops/SkOpSegment.cpp

Issue 2128633003: pathops coincidence and security rewrite (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: require resulting t to be between 0 and 1 Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
OLDNEW
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 #include "SkOpCoincidence.h" 7 #include "SkOpCoincidence.h"
8 #include "SkOpContour.h" 8 #include "SkOpContour.h"
9 #include "SkOpSegment.h" 9 #include "SkOpSegment.h"
10 #include "SkPathWriter.h" 10 #include "SkPathWriter.h"
11 11
12 #define FAIL_IF(cond) do { if (cond) return false; } while (false)
13
12 /* 14 /*
13 After computing raw intersections, post process all segments to: 15 After computing raw intersections, post process all segments to:
14 - find small collections of points that can be collapsed to a single point 16 - find small collections of points that can be collapsed to a single point
15 - find missing intersections to resolve differences caused by different algorith ms 17 - find missing intersections to resolve differences caused by different algorith ms
16 18
17 Consider segments containing tiny or small intervals. Consider coincident segmen ts 19 Consider segments containing tiny or small intervals. Consider coincident segmen ts
18 because coincidence finds intersections through distance measurement that non-co incident 20 because coincidence finds intersections through distance measurement that non-co incident
19 intersection tests cannot. 21 intersection tests cannot.
20 */ 22 */
21 23
(...skipping 130 matching lines...)
152 154
153 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sum Winding) { 155 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sum Winding) {
154 int maxWinding; 156 int maxWinding;
155 setUpWinding(start, end, &maxWinding, sumWinding); 157 setUpWinding(start, end, &maxWinding, sumWinding);
156 bool from = maxWinding != 0; 158 bool from = maxWinding != 0;
157 bool to = *sumWinding != 0; 159 bool to = *sumWinding != 0;
158 bool result = gUnaryActiveEdge[from][to]; 160 bool result = gUnaryActiveEdge[from][to];
159 return result; 161 return result;
160 } 162 }
161 163
162 void SkOpSegment::addAlignIntersection(SkOpPtT& endPtT, SkPoint& oldPt,
163 SkOpContourHead* contourList, SkChunkAlloc* allocator) {
164 const SkPoint& newPt = endPtT.fPt;
165 if (newPt == oldPt) {
166 return;
167 }
168 SkPoint line[2] = { newPt, oldPt };
169 SkPathOpsBounds lineBounds;
170 lineBounds.setBounds(line, 2);
171 SkDLine aLine;
172 aLine.set(line);
173 SkOpContour* current = contourList;
174 do {
175 if (!SkPathOpsBounds::Intersects(current->bounds(), lineBounds)) {
176 continue;
177 }
178 SkOpSegment* segment = current->first();
179 do {
180 if (!SkPathOpsBounds::Intersects(segment->bounds(), lineBounds)) {
181 continue;
182 }
183 if (newPt == segment->fPts[0]) {
184 continue;
185 }
186 if (newPt == segment->fPts[SkPathOpsVerbToPoints(segment->fVerb)]) {
187 continue;
188 }
189 if (oldPt == segment->fPts[0]) {
190 continue;
191 }
192 if (oldPt == segment->fPts[SkPathOpsVerbToPoints(segment->fVerb)]) {
193 continue;
194 }
195 if (endPtT.contains(segment)) {
196 continue;
197 }
198 SkIntersections i;
199 switch (segment->fVerb) {
200 case SkPath::kLine_Verb: {
201 SkDLine bLine;
202 bLine.set(segment->fPts);
203 i.intersect(bLine, aLine);
204 } break;
205 case SkPath::kQuad_Verb: {
206 SkDQuad bQuad;
207 bQuad.set(segment->fPts);
208 i.intersect(bQuad, aLine);
209 } break;
210 case SkPath::kConic_Verb: {
211 SkDConic bConic;
212 bConic.set(segment->fPts, segment->fWeight);
213 i.intersect(bConic, aLine);
214 } break;
215 case SkPath::kCubic_Verb: {
216 SkDCubic bCubic;
217 bCubic.set(segment->fPts);
218 i.intersect(bCubic, aLine);
219 } break;
220 default:
221 SkASSERT(0);
222 }
223 if (i.used()) {
224 SkASSERT(i.used() == 1);
225 SkASSERT(!zero_or_one(i[0][0]));
226 SkOpSpanBase* checkSpan = fHead.next();
227 while (!checkSpan->final()) {
228 if (checkSpan->contains(segment)) {
229 goto nextSegment;
230 }
231 checkSpan = checkSpan->upCast()->next();
232 }
233 SkOpPtT* ptT = segment->addT(i[0][0], SkOpSegment::kAllowAlias, allocator);
234 ptT->fPt = newPt;
235 endPtT.addOpp(ptT);
236 }
237 nextSegment:
238 ;
239 } while ((segment = segment->next()));
240 } while ((current = current->next()));
241 }
242
243 bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end, 164 bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
244 SkPathWriter* path) const { 165 SkPathWriter* path) const {
245 if (start->starter(end)->alreadyAdded()) { 166 if (start->starter(end)->alreadyAdded()) {
167 SkDEBUGF(("same curve added twice aborted pathops\n"));
246 return false; 168 return false;
247 } 169 }
248 SkOpCurve edge; 170 SkOpCurve edge;
249 const SkPoint* ePtr; 171 const SkPoint* ePtr;
250 SkScalar eWeight; 172 SkScalar eWeight;
251 if ((start == &fHead && end == &fTail) || (start == &fTail && end == &fHead) ) { 173 if ((start == &fHead && end == &fTail) || (start == &fTail && end == &fHead) ) {
252 ePtr = fPts; 174 ePtr = fPts;
253 eWeight = fWeight; 175 eWeight = fWeight;
254 } else { 176 } else {
255 // OPTIMIZE? if not active, skip remainder and return xyAtT(end) 177 // OPTIMIZE? if not active, skip remainder and return xyAtT(end)
(...skipping 35 matching lines...)
291 case SkPath::kCubic_Verb: 213 case SkPath::kCubic_Verb:
292 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]); 214 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]);
293 break; 215 break;
294 default: 216 default:
295 SkASSERT(0); 217 SkASSERT(0);
296 } 218 }
297 } 219 }
298 return true; 220 return true;
299 } 221 }
300 222
301 SkOpPtT* SkOpSegment::addMissing(double t, SkOpSegment* opp, SkChunkAlloc* alloc ator) { 223 const SkOpPtT* SkOpSegment::existing(double t, const SkOpSegment* opp) const {
302 SkOpSpanBase* existing = nullptr; 224 const SkOpSpanBase* test = &fHead;
303 SkOpSpanBase* test = &fHead; 225 const SkOpPtT* testPtT;
304 double testT; 226 SkPoint pt = this->ptAtT(t);
305 do { 227 do {
306 if ((testT = test->ptT()->fT) >= t) { 228 testPtT = test->ptT();
307 if (testT == t) { 229 if (testPtT->fT == t) {
308 existing = test;
309 }
310 break; 230 break;
311 } 231 }
232 if (!this->match(testPtT, this, t, pt, opp ? kAllowAliasMatch : kNoAlias Match)) {
233 if (t < testPtT->fT) {
234 return nullptr;
235 }
236 continue;
237 }
238 if (!opp) {
239 return testPtT;
240 }
241 const SkOpPtT* loop = testPtT->next();
242 while (loop != testPtT) {
243 if (loop->segment() == this && loop->fT == t && loop->fPt == pt) {
244 goto foundMatch;
245 }
246 loop = loop->next();
247 }
248 return nullptr;
312 } while ((test = test->upCast()->next())); 249 } while ((test = test->upCast()->next()));
313 SkOpPtT* result; 250 foundMatch:
314 if (existing && existing->contains(opp)) { 251 return opp && !test->contains(opp) ? nullptr : testPtT;
315 result = existing->ptT();
316 } else {
317 result = this->addT(t, SkOpSegment::kNoAlias, allocator);
318 }
319 SkASSERT(result);
320 return result;
321 } 252 }
322 253
323 SkOpPtT* SkOpSegment::addT(double t, AllowAlias allowAlias, SkChunkAlloc* alloca tor) { 254 // break the span so that the coincident part does not change the angle of the r emainder
255 bool SkOpSegment::addExpanded(double newT, const SkOpSpanBase* test, bool* start Over) {
256 if (this->contains(newT)) {
257 return true;
258 }
259 SkOpPtT* newPtT = this->addT(newT, kAllowAliasMatch, startOver);
260 if (!newPtT) {
261 return false;
262 }
263 newPtT->fPt = this->ptAtT(newT);
264 // const cast away to change linked list; pt/t values stays unchanged
265 SkOpSpanBase* writableTest = const_cast<SkOpSpanBase*>(test);
266 if (writableTest->ptT()->addOpp(newPtT)) {
267 writableTest->checkForCollapsedCoincidence();
268 }
269 return true;
270 }
271
272 // Please keep this in sync with debugAddT()
273 SkOpPtT* SkOpSegment::addT(double t, AliasMatch allowAlias, bool* allocated) {
324 debugValidate(); 274 debugValidate();
325 SkPoint pt = this->ptAtT(t); 275 SkPoint pt = this->ptAtT(t);
326 SkOpSpanBase* span = &fHead; 276 SkOpSpanBase* span = &fHead;
327 do { 277 do {
328 SkOpPtT* result = span->ptT(); 278 SkOpPtT* result = span->ptT();
329 SkOpPtT* loop; 279 SkOpPtT* loop;
330 bool duplicatePt; 280 bool duplicatePt;
331 if (t == result->fT) { 281 if (t == result->fT) {
332 goto bumpSpan; 282 goto bumpSpan;
333 } 283 }
334 if (this->match(result, this, t, pt)) { 284 if (this->match(result, this, t, pt, allowAlias)) {
335 // see if any existing alias matches segment, pt, and t 285 // see if any existing alias matches segment, pt, and t
336 loop = result->next(); 286 loop = result->next();
337 duplicatePt = false; 287 duplicatePt = false;
338 while (loop != result) { 288 while (loop != result) {
339 bool ptMatch = loop->fPt == pt; 289 bool ptMatch = loop->fPt == pt;
340 if (loop->segment() == this && loop->fT == t && ptMatch) { 290 if (loop->segment() == this && loop->fT == t && ptMatch) {
341 goto bumpSpan; 291 goto bumpSpan;
342 } 292 }
343 duplicatePt |= ptMatch; 293 duplicatePt |= ptMatch;
344 loop = loop->next(); 294 loop = loop->next();
345 } 295 }
346 if (kNoAlias == allowAlias) { 296 if (kNoAliasMatch == allowAlias) {
347 bumpSpan: 297 bumpSpan:
348 span->bumpSpanAdds(); 298 span->bumpSpanAdds();
349 return result; 299 return result;
350 } 300 }
351 SkOpPtT* alias = SkOpTAllocator<SkOpPtT>::Allocate(allocator); 301 SkOpPtT* alias = SkOpTAllocator<SkOpPtT>::Allocate(this->globalState ()->allocator());
352 alias->init(result->span(), t, pt, duplicatePt); 302 alias->init(result->span(), t, pt, duplicatePt);
353 result->insert(alias); 303 result->insert(alias);
354 result->span()->unaligned(); 304 result->span()->unaligned();
355 this->debugValidate(); 305 this->debugValidate();
356 #if DEBUG_ADD_T 306 #if DEBUG_ADD_T
357 SkDebugf("%s alias t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t, 307 SkDebugf("%s alias t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
358 alias->segment()->debugID(), alias->span()->debugID()); 308 alias->segment()->debugID(), alias->span()->debugID());
359 #endif 309 #endif
360 span->bumpSpanAdds(); 310 span->bumpSpanAdds();
311 if (allocated) {
312 *allocated = true;
313 }
361 return alias; 314 return alias;
362 } 315 }
363 if (t < result->fT) { 316 if (t < result->fT) {
364 SkOpSpan* prev = result->span()->prev(); 317 SkOpSpan* prev = result->span()->prev();
365 if (!prev) { 318 if (!prev) {
366 return nullptr; 319 return nullptr;
367 } 320 }
368 SkOpSpan* span = insert(prev, allocator); 321 SkOpSpan* span = insert(prev);
369 span->init(this, prev, t, pt); 322 span->init(this, prev, t, pt);
370 this->debugValidate(); 323 this->debugValidate();
371 #if DEBUG_ADD_T 324 #if DEBUG_ADD_T
372 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t, 325 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
373 span->segment()->debugID(), span->debugID()); 326 span->segment()->debugID(), span->debugID());
374 #endif 327 #endif
375 span->bumpSpanAdds(); 328 span->bumpSpanAdds();
329 if (allocated) {
330 *allocated = true;
331 }
376 return span->ptT(); 332 return span->ptT();
377 } 333 }
378 SkASSERT(span != &fTail); 334 SkASSERT(span != &fTail);
379 } while ((span = span->upCast()->next())); 335 } while ((span = span->upCast()->next()));
380 SkASSERT(0); 336 SkASSERT(0);
381 return nullptr; 337 return nullptr;
382 } 338 }
383 339
384 // choose a solitary t and pt value; remove aliases; align the opposite ends 340 void SkOpSegment::calcAngles() {
385 void SkOpSegment::align() {
386 debugValidate();
387 SkOpSpanBase* span = &fHead;
388 if (!span->aligned()) {
389 span->alignEnd(0, fPts[0]);
390 }
391 while ((span = span->upCast()->next())) {
392 if (span == &fTail) {
393 break;
394 }
395 span->align();
396 }
397 if (!span->aligned()) {
398 span->alignEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]);
399 }
400 if (this->collapsed()) {
401 SkOpSpan* span = &fHead;
402 do {
403 span->setWindValue(0);
404 span->setOppValue(0);
405 this->markDone(span);
406 } while ((span = span->next()->upCastable()));
407 }
408 debugValidate();
409 }
410
411 void SkOpSegment::calcAngles(SkChunkAlloc* allocator) {
412 bool activePrior = !fHead.isCanceled(); 341 bool activePrior = !fHead.isCanceled();
413 if (activePrior && !fHead.simple()) { 342 if (activePrior && !fHead.simple()) {
414 addStartSpan(allocator); 343 addStartSpan();
415 } 344 }
416 SkOpSpan* prior = &fHead; 345 SkOpSpan* prior = &fHead;
417 SkOpSpanBase* spanBase = fHead.next(); 346 SkOpSpanBase* spanBase = fHead.next();
418 while (spanBase != &fTail) { 347 while (spanBase != &fTail) {
419 if (activePrior) { 348 if (activePrior) {
420 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocato r); 349 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(
350 this->globalState()->allocator());
421 priorAngle->set(spanBase, prior); 351 priorAngle->set(spanBase, prior);
422 spanBase->setFromAngle(priorAngle); 352 spanBase->setFromAngle(priorAngle);
423 } 353 }
424 SkOpSpan* span = spanBase->upCast(); 354 SkOpSpan* span = spanBase->upCast();
425 bool active = !span->isCanceled(); 355 bool active = !span->isCanceled();
426 SkOpSpanBase* next = span->next(); 356 SkOpSpanBase* next = span->next();
427 if (active) { 357 if (active) {
428 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator); 358 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(
359 this->globalState()->allocator());
429 angle->set(span, next); 360 angle->set(span, next);
430 span->setToAngle(angle); 361 span->setToAngle(angle);
431 } 362 }
432 activePrior = active; 363 activePrior = active;
433 prior = span; 364 prior = span;
434 spanBase = next; 365 spanBase = next;
435 } 366 }
436 if (activePrior && !fTail.simple()) { 367 if (activePrior && !fTail.simple()) {
437 addEndSpan(allocator); 368 addEndSpan();
438 } 369 }
439 } 370 }
440 371
372 // Please keep this in sync with debugClearAll()
373 void SkOpSegment::clearAll() {
374 SkOpSpan* span = &fHead;
375 do {
376 this->clearOne(span);
377 } while ((span = span->next()->upCastable()));
378 this->globalState()->coincidence()->release(this);
379 }
380
381 // Please keep this in sync with debugClearOne()
382 void SkOpSegment::clearOne(SkOpSpan* span) {
383 span->setWindValue(0);
384 span->setOppValue(0);
385 this->markDone(span);
386 }
387
388 // Quads and conics collapse if the end points are the same, because
389 // the curve doesn't enclose an area.
441 bool SkOpSegment::collapsed() const { 390 bool SkOpSegment::collapsed() const {
442 return fVerb == SkPath::kLine_Verb && fHead.pt() == fTail.pt(); 391 // FIXME: cubics can have also collapsed -- need to check if the
392 // control points are on a line with the end points
393 return fVerb < SkPath::kCubic_Verb && fHead.pt() == fTail.pt();
443 } 394 }
444 395
445 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle , 396 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle ,
446 SkOpAngle::IncludeType includeType) { 397 SkOpAngle::IncludeType includeType) {
447 SkOpSegment* baseSegment = baseAngle->segment(); 398 SkOpSegment* baseSegment = baseAngle->segment();
448 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); 399 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
449 int sumSuWinding; 400 int sumSuWinding;
450 bool binary = includeType >= SkOpAngle::kBinarySingle; 401 bool binary = includeType >= SkOpAngle::kBinarySingle;
451 if (binary) { 402 if (binary) {
452 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle); 403 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
(...skipping 111 matching lines...)
564 } 515 }
565 if (baseAngle) { 516 if (baseAngle) {
566 ComputeOneSumReverse(baseAngle, angle, includeType); 517 ComputeOneSumReverse(baseAngle, angle, includeType);
567 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : n ullptr; 518 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : n ullptr;
568 } 519 }
569 } while (prior != firstAngle); 520 } while (prior != firstAngle);
570 } 521 }
571 return start->starter(end)->windSum(); 522 return start->starter(end)->windSum();
572 } 523 }
573 524
525 bool SkOpSegment::contains(double newT) const {
526 const SkOpSpanBase* spanBase = &fHead;
527 do {
528 if (spanBase->ptT()->contains(this, newT)) {
529 return true;
530 }
531 if (spanBase == &fTail) {
532 break;
533 }
534 spanBase = spanBase->upCast()->next();
535 } while (true);
536 return false;
537 }
538
574 void SkOpSegment::release(const SkOpSpan* span) { 539 void SkOpSegment::release(const SkOpSpan* span) {
575 if (span->done()) { 540 if (span->done()) {
576 --fDoneCount; 541 --fDoneCount;
577 } 542 }
578 --fCount; 543 --fCount;
579 SkASSERT(fCount >= fDoneCount); 544 SkASSERT(this->globalState()->debugSkipAssert() || fCount >= fDoneCount);
580 } 545 }
581 546
582 double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const { 547 double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const {
583 SkDPoint testPt = this->dPtAtT(t); 548 SkDPoint testPt = this->dPtAtT(t);
584 SkDLine testPerp = {{ testPt, testPt }}; 549 SkDLine testPerp = {{ testPt, testPt }};
585 SkDVector slope = this->dSlopeAtT(t); 550 SkDVector slope = this->dSlopeAtT(t);
586 testPerp[1].fX += slope.fY; 551 testPerp[1].fX += slope.fY;
587 testPerp[1].fY -= slope.fX; 552 testPerp[1].fY -= slope.fX;
588 SkIntersections i; 553 SkIntersections i;
589 const SkOpSegment* oppSegment = oppAngle->segment(); 554 const SkOpSegment* oppSegment = oppAngle->segment();
590 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weig ht(), testPerp, &i); 555 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weig ht(), testPerp, &i);
591 double closestDistSq = SK_ScalarInfinity; 556 double closestDistSq = SK_ScalarInfinity;
592 for (int index = 0; index < i.used(); ++index) { 557 for (int index = 0; index < i.used(); ++index) {
593 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) { 558 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
594 continue; 559 continue;
595 } 560 }
596 double testDistSq = testPt.distanceSquared(i.pt(index)); 561 double testDistSq = testPt.distanceSquared(i.pt(index));
597 if (closestDistSq > testDistSq) { 562 if (closestDistSq > testDistSq) {
598 closestDistSq = testDistSq; 563 closestDistSq = testDistSq;
599 } 564 }
600 } 565 }
601 return closestDistSq; 566 return closestDistSq;
602 } 567 }
603 568
604 void SkOpSegment::findCollapsed() {
605 if (fHead.contains(&fTail)) {
606 markAllDone();
607 // move start and end to the same point
608 fHead.alignEnd(0, fHead.pt());
609 fTail.setAligned();
610 }
611 }
612
613 /* 569 /*
614 The M and S variable name parts stand for the operators. 570 The M and S variable name parts stand for the operators.
615 Mi stands for Minuend (see wiki subtraction, analogous to difference) 571 Mi stands for Minuend (see wiki subtraction, analogous to difference)
616 Su stands for Subtrahend 572 Su stands for Subtrahend
617 The Opp variable name part designates that the value is for the Opposite operat or. 573 The Opp variable name part designates that the value is for the Opposite operat or.
618 Opposite values result from combining coincident spans. 574 Opposite values result from combining coincident spans.
619 */ 575 */
620 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBa se** nextStart, 576 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBa se** nextStart,
621 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, in t xorSuMask) { 577 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, in t xorSuMask) {
622 SkOpSpanBase* start = *nextStart; 578 SkOpSpanBase* start = *nextStart;
(...skipping 257 matching lines...)
880 *nextEnd = foundAngle->end(); 836 *nextEnd = foundAngle->end();
881 nextSegment = foundAngle->segment(); 837 nextSegment = foundAngle->segment();
882 #if DEBUG_WINDING 838 #if DEBUG_WINDING
883 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 839 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
884 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn d); 840 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn d);
885 #endif 841 #endif
886 return nextSegment; 842 return nextSegment;
887 } 843 }
888 844
889 SkOpGlobalState* SkOpSegment::globalState() const { 845 SkOpGlobalState* SkOpSegment::globalState() const {
890 return contour()->globalState(); 846 return contour()->globalState();
891 } 847 }
892 848
893 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkP ath::Verb verb) { 849 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkP ath::Verb verb) {
894 fContour = contour; 850 fContour = contour;
895 fNext = nullptr; 851 fNext = nullptr;
896 fOriginal[0] = pts[0];
897 fOriginal[1] = pts[SkPathOpsVerbToPoints(verb)];
898 fPts = pts; 852 fPts = pts;
899 fWeight = weight; 853 fWeight = weight;
900 fVerb = verb; 854 fVerb = verb;
901 fCount = 0; 855 fCount = 0;
902 fDoneCount = 0; 856 fDoneCount = 0;
903 fVisited = false; 857 fVisited = false;
904 SkOpSpan* zeroSpan = &fHead; 858 SkOpSpan* zeroSpan = &fHead;
905 zeroSpan->init(this, nullptr, 0, fPts[0]); 859 zeroSpan->init(this, nullptr, 0, fPts[0]);
906 SkOpSpanBase* oneSpan = &fTail; 860 SkOpSpanBase* oneSpan = &fTail;
907 zeroSpan->setNext(oneSpan); 861 zeroSpan->setNext(oneSpan);
(...skipping 180 matching lines...)
1088 #if DEBUG_MARK_DONE 1042 #if DEBUG_MARK_DONE
1089 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding); 1043 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1090 #endif 1044 #endif
1091 span->setWindSum(winding); 1045 span->setWindSum(winding);
1092 span->setOppSum(oppWinding); 1046 span->setOppSum(oppWinding);
1093 debugValidate(); 1047 debugValidate();
1094 return true; 1048 return true;
1095 } 1049 }
1096 1050
1097 bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, doub le testT, 1051 bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, doub le testT,
1098 const SkPoint& testPt) const { 1052 const SkPoint& testPt, AliasMatch aliasMatch) const {
1099 const SkOpSegment* baseParent = base->segment(); 1053 SkASSERT(this == base->segment());
1100 if (this == baseParent && this == testParent && precisely_equal(base->fT, te stT)) { 1054 if (this == testParent) {
1101 return true; 1055 if (precisely_equal(base->fT, testT)) {
1056 return true;
1057 }
1102 } 1058 }
1103 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) { 1059 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1104 return false; 1060 return false;
1105 } 1061 }
1106 return !this->ptsDisjoint(base->fT, base->fPt, testT, testPt); 1062 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
1107 } 1063 }
1108 1064
1109 static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) { 1065 static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1110 if (last) { 1066 if (last) {
1111 *last = endSpan; 1067 *last = endSpan;
1112 } 1068 }
1113 return nullptr; 1069 return nullptr;
1114 } 1070 }
1115 1071
1116 SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpS pan** minPtr, 1072 SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpS pan** minPtr,
(...skipping 54 matching lines...)
1171 return set_last(last, endSpan); 1127 return set_last(last, endSpan);
1172 } 1128 }
1173 *startPtr = foundSpan; 1129 *startPtr = foundSpan;
1174 *stepPtr = foundStep; 1130 *stepPtr = foundStep;
1175 if (minPtr) { 1131 if (minPtr) {
1176 *minPtr = foundMin; 1132 *minPtr = foundMin;
1177 } 1133 }
1178 return other; 1134 return other;
1179 } 1135 }
1180 1136
1181 static void clear_visited(SkOpSpanBase* span) { 1137 // Please keep this in sync with DebugClearVisited()
1138 void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
1182 // reset visited flag back to false 1139 // reset visited flag back to false
1183 do { 1140 do {
1184 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT; 1141 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1185 while ((ptT = ptT->next()) != stopPtT) { 1142 while ((ptT = ptT->next()) != stopPtT) {
1186 SkOpSegment* opp = ptT->segment(); 1143 SkOpSegment* opp = ptT->segment();
1187 opp->resetVisited(); 1144 opp->resetVisited();
1188 } 1145 }
1189 } while (!span->final() && (span = span->upCast()->next())); 1146 } while (!span->final() && (span = span->upCast()->next()));
1190 } 1147 }
1191 1148
1149 // Please keep this in sync with debugMissingCoincidence()
1192 // look for pairs of undetected coincident curves 1150 // look for pairs of undetected coincident curves
1193 // assumes that segments going in have visited flag clear 1151 // assumes that segments going in have visited flag clear
1194 // curve/curve intersection should now do a pretty good job of finding coinciden t runs so 1152 // Even though pairs of curves correct detect coincident runs, a run may be miss ed
1195 // this may be only be necessary for line/curve pairs -- so skip unless this is a line and the 1153 // if the coincidence is a product of multiple intersections. For instance, give n
1196 // the opp is not a line 1154 // curves A, B, and C:
1197 bool SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc * allocator) { 1155 // A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1198 if (this->verb() != SkPath::kLine_Verb) { 1156 // the end of C that the intersection is replaced with the end of C.
1199 return false; 1157 // Even though A-B correctly do not detect an intersection at point 2,
1200 } 1158 // the resulting run from point 1 to point 2 is coincident on A and B.
1159 bool SkOpSegment::missingCoincidence() {
1201 if (this->done()) { 1160 if (this->done()) {
1202 return false; 1161 return false;
1203 } 1162 }
1204 SkOpSpan* prior = nullptr; 1163 SkOpSpan* prior = nullptr;
1205 SkOpSpanBase* spanBase = &fHead; 1164 SkOpSpanBase* spanBase = &fHead;
1165 bool result = false;
1206 do { 1166 do {
1207 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT; 1167 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
1208 SkASSERT(ptT->span() == spanBase); 1168 SkASSERT(ptT->span() == spanBase);
1209 while ((ptT = ptT->next()) != spanStopPtT) { 1169 while ((ptT = ptT->next()) != spanStopPtT) {
1210 if (ptT->deleted()) { 1170 if (ptT->deleted()) {
1211 continue; 1171 continue;
1212 } 1172 }
1213 SkOpSegment* opp = ptT->span()->segment(); 1173 SkOpSegment* opp = ptT->span()->segment();
1214 // if (opp->verb() == SkPath::kLine_Verb) {
1215 // continue;
1216 // }
1217 if (opp->done()) { 1174 if (opp->done()) {
1218 continue; 1175 continue;
1219 } 1176 }
1220 // when opp is encounted the 1st time, continue; on 2nd encounter, l ook for coincidence 1177 // when opp is encounted the 1st time, continue; on 2nd encounter, l ook for coincidence
1221 if (!opp->visited()) { 1178 if (!opp->visited()) {
1222 continue; 1179 continue;
1223 } 1180 }
1224 if (spanBase == &fHead) { 1181 if (spanBase == &fHead) {
1225 continue; 1182 continue;
1226 } 1183 }
1184 if (ptT->segment() == this) {
1185 continue;
1186 }
1227 SkOpSpan* span = spanBase->upCastable(); 1187 SkOpSpan* span = spanBase->upCastable();
1228 // FIXME?: this assumes that if the opposite segment is coincident t hen no more 1188 // FIXME?: this assumes that if the opposite segment is coincident t hen no more
1229 // coincidence needs to be detected. This may not be true. 1189 // coincidence needs to be detected. This may not be true.
1230 if (span && span->containsCoincidence(opp)) { 1190 if (span && span->containsCoincidence(opp)) {
1231 continue;
1232 }
1233 if (spanBase->segment() == opp) {
1234 continue; 1191 continue;
1235 } 1192 }
1236 if (spanBase->containsCoinEnd(opp)) { 1193 if (spanBase->containsCoinEnd(opp)) {
1237 continue; 1194 continue;
1238 } 1195 }
1239 SkOpPtT* priorPtT = nullptr, * priorStopPtT; 1196 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
1240 // find prior span containing opp segment 1197 // find prior span containing opp segment
1241 SkOpSegment* priorOpp = nullptr; 1198 SkOpSegment* priorOpp = nullptr;
1242 SkOpSpan* priorTest = spanBase->prev(); 1199 SkOpSpan* priorTest = spanBase->prev();
1243 while (!priorOpp && priorTest) { 1200 while (!priorOpp && priorTest) {
1244 priorStopPtT = priorPtT = priorTest->ptT(); 1201 priorStopPtT = priorPtT = priorTest->ptT();
1245 while ((priorPtT = priorPtT->next()) != priorStopPtT) { 1202 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
1246 if (priorPtT->deleted()) { 1203 if (priorPtT->deleted()) {
1247 continue; 1204 continue;
1248 } 1205 }
(...skipping 12 matching lines...)
1261 if (priorPtT == ptT) { 1218 if (priorPtT == ptT) {
1262 continue; 1219 continue;
1263 } 1220 }
1264 SkOpPtT* oppStart = prior->ptT(); 1221 SkOpPtT* oppStart = prior->ptT();
1265 SkOpPtT* oppEnd = spanBase->ptT(); 1222 SkOpPtT* oppEnd = spanBase->ptT();
1266 bool swapped = priorPtT->fT > ptT->fT; 1223 bool swapped = priorPtT->fT > ptT->fT;
1267 if (swapped) { 1224 if (swapped) {
1268 SkTSwap(priorPtT, ptT); 1225 SkTSwap(priorPtT, ptT);
1269 SkTSwap(oppStart, oppEnd); 1226 SkTSwap(oppStart, oppEnd);
1270 } 1227 }
1271 bool flipped = oppStart->fT > oppEnd->fT; 1228 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1272 bool coincident = false; 1229 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1273 if (coincidences->contains(priorPtT, ptT, oppStart, oppEnd, flipped) ) { 1230 SkOpPtT* rootPtT = ptT->span()->ptT();
1231 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1232 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1233 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, root OppEnd)) {
1274 goto swapBack; 1234 goto swapBack;
1275 } 1235 }
1276 if (opp->verb() == SkPath::kLine_Verb) { 1236 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
1277 coincident = (SkDPoint::ApproximatelyEqual(priorPtT->fPt, oppSta rt->fPt) ||
1278 SkDPoint::ApproximatelyEqual(priorPtT->fPt, oppEnd->fPt) ) &&
1279 (SkDPoint::ApproximatelyEqual(ptT->fPt, oppStart->fPt) | |
1280 SkDPoint::ApproximatelyEqual(ptT->fPt, oppEnd->fPt));
1281 }
1282 if (!coincident) {
1283 coincident = testForCoincidence(priorPtT, ptT, prior, spanBase, opp, 5000);
1284 }
1285 if (coincident) {
1286 // mark coincidence 1237 // mark coincidence
1287 if (!coincidences->extend(priorPtT, ptT, oppStart, oppEnd) 1238 #if DEBUG_COINCIDENCE_VERBOSE
1288 && !coincidences->extend(oppStart, oppEnd, priorPtT, ptT )) { 1239 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1289 coincidences->add(priorPtT, ptT, oppStart, oppEnd, allocator ); 1240 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStar t->debugID(),
1241 rootOppEnd->debugID());
1242 #endif
1243 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, r ootOppEnd)) {
1244 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootO ppEnd);
1290 } 1245 }
1291 clear_visited(&fHead); 1246 #if DEBUG_COINCIDENCE
1292 return true; 1247 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppSt art, rootOppEnd));
1248 #endif
1249 result = true;
1293 } 1250 }
1294 swapBack: 1251 swapBack:
1295 if (swapped) { 1252 if (swapped) {
1296 SkTSwap(priorPtT, ptT); 1253 SkTSwap(priorPtT, ptT);
1297 } 1254 }
1298 } 1255 }
1299 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next( ))); 1256 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next( )));
1300 clear_visited(&fHead); 1257 ClearVisited(&fHead);
1301 return false; 1258 return result;
1302 } 1259 }
1303 1260
1261 // please keep this in sync with debugMoveMultiples()
1304 // if a span has more than one intersection, merge the other segments' span as n eeded 1262 // if a span has more than one intersection, merge the other segments' span as n eeded
1305 bool SkOpSegment::moveMultiples() { 1263 bool SkOpSegment::moveMultiples() {
1306 debugValidate(); 1264 debugValidate();
1307 SkOpSpanBase* test = &fHead; 1265 SkOpSpanBase* test = &fHead;
1308 do { 1266 do {
1309 int addCount = test->spanAddsCount(); 1267 int addCount = test->spanAddsCount();
1310 if (addCount < 1) { 1268 FAIL_IF(addCount < 1);
1311 return false;
1312 }
1313 if (addCount == 1) { 1269 if (addCount == 1) {
1314 continue; 1270 continue;
1315 } 1271 }
1316 SkOpPtT* startPtT = test->ptT(); 1272 SkOpPtT* startPtT = test->ptT();
1317 SkOpPtT* testPtT = startPtT; 1273 SkOpPtT* testPtT = startPtT;
1318 do { // iterate through all spans associated with start 1274 do { // iterate through all spans associated with start
1319 SkOpSpanBase* oppSpan = testPtT->span(); 1275 SkOpSpanBase* oppSpan = testPtT->span();
1320 if (oppSpan->spanAddsCount() == addCount) { 1276 if (oppSpan->spanAddsCount() == addCount) {
1321 continue; 1277 continue;
1322 } 1278 }
(...skipping 62 matching lines...)
1385 if (oppTest == &oppSegment->fTail || oppTest == &oppSegment- >fHead) { 1341 if (oppTest == &oppSegment->fTail || oppTest == &oppSegment- >fHead) {
1386 SkASSERT(oppSpan != &oppSegment->fHead); // don't expect collapse 1342 SkASSERT(oppSpan != &oppSegment->fHead); // don't expect collapse
1387 SkASSERT(oppSpan != &oppSegment->fTail); 1343 SkASSERT(oppSpan != &oppSegment->fTail);
1388 oppTest->merge(oppSpan->upCast()); 1344 oppTest->merge(oppSpan->upCast());
1389 } else { 1345 } else {
1390 oppSpan->merge(oppTest->upCast()); 1346 oppSpan->merge(oppTest->upCast());
1391 } 1347 }
1392 oppSegment->debugValidate(); 1348 oppSegment->debugValidate();
1393 goto checkNextSpan; 1349 goto checkNextSpan;
1394 } 1350 }
1395 tryNextSpan: 1351 tryNextSpan:
1396 ; 1352 ;
1397 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()) ); 1353 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()) );
1398 } while ((testPtT = testPtT->next()) != startPtT); 1354 } while ((testPtT = testPtT->next()) != startPtT);
1399 checkNextSpan: 1355 checkNextSpan:
1400 ; 1356 ;
1401 } while ((test = test->final() ? nullptr : test->upCast()->next())); 1357 } while ((test = test->final() ? nullptr : test->upCast()->next()));
1402 debugValidate(); 1358 debugValidate();
1403 return true; 1359 return true;
1404 } 1360 }
1405 1361
1362 // adjacent spans may have points close by
1363 bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* c heckSpan) const {
1364 const SkOpPtT* refHead = refSpan->ptT();
1365 const SkOpPtT* checkHead = checkSpan->ptT();
1366 // if the first pt pair from adjacent spans are far apart, assume that all are f ar enough apart
1367 if (!SkDPoint::RoughlyEqual(refHead->fPt, checkHead->fPt)) {
1368 #if DEBUG_COINCIDENCE
1369 // verify that no combination of points are close
1370 const SkOpPtT* dBugRef = refHead;
1371 do {
1372 const SkOpPtT* dBugCheck = checkHead;
1373 do {
1374 SkASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck-> fPt));
1375 dBugCheck = dBugCheck->next();
1376 } while (dBugCheck != checkHead);
1377 dBugRef = dBugRef->next();
1378 } while (dBugRef != refHead);
1379 #endif
1380 return false;
1381 }
1382 // check only unique points
1383 SkScalar distSqBest = SK_ScalarMax;
1384 const SkOpPtT* refBest = nullptr;
1385 const SkOpPtT* checkBest = nullptr;
1386 const SkOpPtT* ref = refHead;
1387 do {
1388 if (ref->deleted()) {
1389 continue;
1390 }
1391 while (ref->ptAlreadySeen(refHead)) {
1392 ref = ref->next();
1393 if (ref == refHead) {
1394 goto doneCheckingDistance;
1395 }
1396 }
1397 const SkOpPtT* check = checkHead;
1398 const SkOpSegment* refSeg = ref->segment();
1399 do {
1400 if (check->deleted()) {
1401 continue;
1402 }
1403 while (check->ptAlreadySeen(checkHead)) {
1404 check = check->next();
1405 if (check == checkHead) {
1406 goto nextRef;
1407 }
1408 }
1409 SkScalar distSq = ref->fPt.distanceToSqd(check->fPt);
1410 if (distSqBest > distSq && (refSeg != check->segment()
1411 || !refSeg->ptsDisjoint(*ref, *check))) {
1412 distSqBest = distSq;
1413 refBest = ref;
1414 checkBest = check;
1415 }
1416 } while ((check = check->next()) != checkHead);
1417 nextRef:
1418 ;
1419 } while ((ref = ref->next()) != refHead);
1420 doneCheckingDistance:
1421 return checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
1422 checkBest->fPt, kAllowAliasMatch);
1423 }
1424
1425 // Please keep this function in sync with debugMoveNearby()
1406 // Move nearby t values and pts so they all hang off the same span. Alignment ha ppens later. 1426 // Move nearby t values and pts so they all hang off the same span. Alignment ha ppens later.
1407 void SkOpSegment::moveNearby() { 1427 void SkOpSegment::moveNearby() {
1408 debugValidate(); 1428 debugValidate();
1409 SkOpSpanBase* spanS = &fHead; 1429 // release undeleted spans pointing to this seg that are linked to the prima ry span
1430 SkOpSpanBase* spanBase = &fHead;
1410 do { 1431 do {
1411 SkOpSpanBase* test = spanS->upCast()->next(); 1432 SkOpPtT* ptT = spanBase->ptT();
1412 SkOpSpanBase* next; 1433 const SkOpPtT* headPtT = ptT;
1413 if (spanS->contains(test)) { 1434 while ((ptT = ptT->next()) != headPtT) {
1414 if (!test->final()) { 1435 SkOpSpanBase* test = ptT->span();
1415 test->upCast()->release(spanS->ptT()); 1436 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1416 continue; 1437 && test->ptT() == ptT) {
1417 } else if (spanS != &fHead) { 1438 if (test->final()) {
1418 spanS->upCast()->release(test->ptT()); 1439 if (spanBase == &fHead) {
1419 spanS = test; 1440 this->clearAll();
1420 continue; 1441 return;
1442 }
1443 spanBase->upCast()->release(ptT);
1444 } else if (test->prev()) {
1445 test->upCast()->release(headPtT);
1446 }
1447 break;
1421 } 1448 }
1422 } 1449 }
1423 do { // iterate through all spans associated with start 1450 spanBase = spanBase->upCast()->next();
1424 SkOpPtT* startBase = spanS->ptT(); 1451 } while (!spanBase->final());
1425 next = test->final() ? nullptr : test->upCast()->next(); 1452
1426 do { 1453 // This loop looks for adjacent spans which are near by
1427 SkOpPtT* testBase = test->ptT(); 1454 spanBase = &fHead;
1428 do { 1455 do { // iterate through all spans associated with start
1429 if (startBase == testBase) { 1456 SkOpSpanBase* test = spanBase->upCast()->next();
1430 goto checkNextSpan; 1457 if (this->spansNearby(spanBase, test)) {
1431 } 1458 if (test->final()) {
1432 if (testBase->duplicate()) { 1459 if (spanBase->prev()) {
1433 continue; 1460 test->merge(spanBase->upCast());
1434 } 1461 } else {
1435 if (this->match(startBase, testBase->segment(), testBase->fT , testBase->fPt)) { 1462 this->clearAll();
1436 if (test == &this->fTail) { 1463 return;
1437 if (spanS == &fHead) { 1464 }
1438 debugValidate(); 1465 } else {
1439 return; // if this span has collapsed, remove i t from parent 1466 spanBase->merge(test->upCast());
1440 } 1467 }
1441 this->fTail.merge(spanS->upCast()); 1468 }
1442 debugValidate(); 1469 spanBase = test;
1443 return; 1470 } while (!spanBase->final());
1444 }
1445 spanS->merge(test->upCast());
1446 goto checkNextSpan;
1447 }
1448 } while ((testBase = testBase->next()) != test->ptT());
1449 } while ((startBase = startBase->next()) != spanS->ptT());
1450 checkNextSpan:
1451 ;
1452 } while ((test = next));
1453 spanS = spanS->upCast()->next();
1454 } while (!spanS->final());
1455 debugValidate(); 1471 debugValidate();
1456 } 1472 }
1457 1473
1458 bool SkOpSegment::operand() const { 1474 bool SkOpSegment::operand() const {
1459 return fContour->operand(); 1475 return fContour->operand();
1460 } 1476 }
1461 1477
1462 bool SkOpSegment::oppXor() const { 1478 bool SkOpSegment::oppXor() const {
1463 return fContour->oppXor(); 1479 return fContour->oppXor();
1464 } 1480 }
(...skipping 207 matching lines...)
1672 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edg e->fQuad[2], 1688 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edg e->fQuad[2],
1673 startT, endT, &edge->fConic.fWeight); 1689 startT, endT, &edge->fConic.fWeight);
1674 } else { 1690 } else {
1675 SkASSERT(fVerb == SkPath::kCubic_Verb); 1691 SkASSERT(fVerb == SkPath::kCubic_Verb);
1676 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT , &edge->fCubic[1]); 1692 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT , &edge->fCubic[1]);
1677 } 1693 }
1678 return true; 1694 return true;
1679 } 1695 }
1680 1696
1681 bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT , 1697 bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT ,
1682 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegme nt* opp, 1698 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegme nt* opp) const {
1683 SkScalar flatnessLimit) const {
1684 // average t, find mid pt 1699 // average t, find mid pt
1685 double midT = (prior->t() + spanBase->t()) / 2; 1700 double midT = (prior->t() + spanBase->t()) / 2;
1686 SkPoint midPt = this->ptAtT(midT); 1701 SkPoint midPt = this->ptAtT(midT);
1687 bool coincident = true; 1702 bool coincident = true;
1688 // if the mid pt is not near either end pt, project perpendicular through op p seg 1703 // if the mid pt is not near either end pt, project perpendicular through op p seg
1689 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt) 1704 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1690 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) { 1705 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
1706 if (priorPtT->span() == ptT->span()) {
1707 return false;
1708 }
1691 coincident = false; 1709 coincident = false;
1692 SkIntersections i; 1710 SkIntersections i;
1693 SkVector dxdy = (*CurveSlopeAtT[fVerb])(this->pts(), this->weight(), mid T); 1711 SkDCurve curvePart;
1694 SkDLine ray = {{{midPt.fX, midPt.fY}, 1712 this->subDivide(prior, spanBase, &curvePart);
1695 {(double) midPt.fX + dxdy.fY, (double) midPt.fY - dxdy.fX}}}; 1713 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1696 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), ray, &i); 1714 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1715 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt .fY - dxdy.fX}}};
1716 SkDCurve oppPart;
1717 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1718 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
1697 // measure distance and see if it's small enough to denote coincidence 1719 // measure distance and see if it's small enough to denote coincidence
1698 for (int index = 0; index < i.used(); ++index) { 1720 for (int index = 0; index < i.used(); ++index) {
1721 if (!between(0, i[0][index], 1)) {
1722 continue;
1723 }
1699 SkDPoint oppPt = i.pt(index); 1724 SkDPoint oppPt = i.pt(index);
1700 if (oppPt.approximatelyEqual(midPt)) { 1725 if (oppPt.approximatelyEqual(midPt)) {
1701 SkVector oppDxdy = (*CurveSlopeAtT[opp->verb()])(opp->pts(), 1726 // the coincidence can occur at almost any angle
1702 opp->weight(), i[index][0]); 1727 coincident = true;
1703 oppDxdy.normalize();
1704 dxdy.normalize();
1705 SkScalar flatness = SkScalarAbs(dxdy.cross(oppDxdy) / FLT_EPSILO N);
1706 coincident |= flatness < flatnessLimit;
1707 } 1728 }
1708 } 1729 }
1709 } 1730 }
1710 return coincident; 1731 return coincident;
1711 } 1732 }
1712 1733
1713 void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) { 1734 void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) {
1714 SkOpSpan* span = this->head(); 1735 SkOpSpan* span = this->head();
1715 do { 1736 do {
1716 if (!span->done()) { 1737 if (!span->done()) {
(...skipping 66 matching lines...)
1783 int absOut = SkTAbs(outerWinding); 1804 int absOut = SkTAbs(outerWinding);
1784 int absIn = SkTAbs(innerWinding); 1805 int absIn = SkTAbs(innerWinding);
1785 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; 1806 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1786 return result; 1807 return result;
1787 } 1808 }
1788 1809
1789 int SkOpSegment::windSum(const SkOpAngle* angle) const { 1810 int SkOpSegment::windSum(const SkOpAngle* angle) const {
1790 const SkOpSpan* minSpan = angle->start()->starter(angle->end()); 1811 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1791 return minSpan->windSum(); 1812 return minSpan->windSum();
1792 } 1813 }
OLDNEW

Powered by Google App Engine