Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(167)

Side by Side Diff: src/pathops/SkPathOpsCommon.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. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
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 "SkAddIntersections.h" 7 #include "SkAddIntersections.h"
8 #include "SkOpCoincidence.h" 8 #include "SkOpCoincidence.h"
9 #include "SkOpEdgeBuilder.h" 9 #include "SkOpEdgeBuilder.h"
10 #include "SkPathOpsCommon.h" 10 #include "SkPathOpsCommon.h"
11 #include "SkPathWriter.h" 11 #include "SkPathWriter.h"
12 #include "SkTSort.h" 12 #include "SkTSort.h"
13 13
14 SkScalar ScaleFactor(const SkPath& path) {
15 static const SkScalar twoTo10 = 1024.f;
16 SkScalar largest = 0;
17 const SkScalar* oneBounds = &path.getBounds().fLeft;
18 for (int index = 0; index < 4; ++index) {
19 largest = SkTMax(largest, SkScalarAbs(oneBounds[index]));
20 }
21 SkScalar scale = twoTo10;
22 SkScalar next;
23 while ((next = scale * twoTo10) < largest) {
24 scale = next;
25 }
26 return scale == twoTo10 ? SK_Scalar1 : scale;
27 }
28
29 void ScalePath(const SkPath& path, SkScalar scale, SkPath* scaled) {
30 SkMatrix matrix;
31 matrix.setScale(scale, scale);
32 *scaled = path;
33 scaled->transform(matrix);
34 }
35
14 const SkOpAngle* AngleWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* windi ngPtr, 36 const SkOpAngle* AngleWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* windi ngPtr,
15 bool* sortablePtr) { 37 bool* sortablePtr) {
16 // find first angle, initialize winding to computed fWindSum 38 // find first angle, initialize winding to computed fWindSum
17 SkOpSegment* segment = start->segment(); 39 SkOpSegment* segment = start->segment();
18 const SkOpAngle* angle = segment->spanToAngle(start, end); 40 const SkOpAngle* angle = segment->spanToAngle(start, end);
19 if (!angle) { 41 if (!angle) {
20 *windingPtr = SK_MinS32; 42 *windingPtr = SK_MinS32;
21 return nullptr; 43 return nullptr;
22 } 44 }
23 bool computeWinding = false; 45 bool computeWinding = false;
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
137 *chase->insert(0) = span; 159 *chase->insert(0) = span;
138 #else 160 #else
139 *chase->append() = span; 161 *chase->append() = span;
140 #endif 162 #endif
141 return first; 163 return first;
142 } 164 }
143 } 165 }
144 return nullptr; 166 return nullptr;
145 } 167 }
146 168
147 #if DEBUG_ACTIVE_SPANS
148 void DebugShowActiveSpans(SkOpContourHead* contourList) {
149 SkOpContour* contour = contourList;
150 do {
151 contour->debugShowActiveSpans();
152 } while ((contour = contour->next()));
153 }
154 #endif
155
156 bool SortContourList(SkOpContourHead** contourList, bool evenOdd, bool oppEvenOd d) { 169 bool SortContourList(SkOpContourHead** contourList, bool evenOdd, bool oppEvenOd d) {
157 SkTDArray<SkOpContour* > list; 170 SkTDArray<SkOpContour* > list;
158 SkOpContour* contour = *contourList; 171 SkOpContour* contour = *contourList;
159 do { 172 do {
160 if (contour->count()) { 173 if (contour->count()) {
161 contour->setOppXor(contour->operand() ? evenOdd : oppEvenOdd); 174 contour->setOppXor(contour->operand() ? evenOdd : oppEvenOdd);
162 *list.append() = contour; 175 *list.append() = contour;
163 } 176 }
164 } while ((contour = contour->next())); 177 } while ((contour = contour->next()));
165 int count = list.count(); 178 int count = list.count();
(...skipping 28 matching lines...) Expand all
194 /* 207 /*
195 check start and end of each contour 208 check start and end of each contour
196 if not the same, record them 209 if not the same, record them
197 match them up 210 match them up
198 connect closest 211 connect closest
199 reassemble contour pieces into new path 212 reassemble contour pieces into new path
200 */ 213 */
201 void Assemble(const SkPathWriter& path, SkPathWriter* simple) { 214 void Assemble(const SkPathWriter& path, SkPathWriter* simple) {
202 SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune 215 SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune
203 SkOpContourHead contour; 216 SkOpContourHead contour;
204 SkOpGlobalState globalState(nullptr, &contour SkDEBUGPARAMS(false) 217 SkOpGlobalState globalState(&contour, &allocator SkDEBUGPARAMS(false)
205 SkDEBUGPARAMS(nullptr)); 218 SkDEBUGPARAMS(nullptr));
206 #if DEBUG_SHOW_TEST_NAME 219 #if DEBUG_SHOW_TEST_NAME
207 SkDebugf("</div>\n"); 220 SkDebugf("</div>\n");
208 #endif 221 #endif
209 #if DEBUG_PATH_CONSTRUCTION 222 #if DEBUG_PATH_CONSTRUCTION
210 SkDebugf("%s\n", __FUNCTION__); 223 SkDebugf("%s\n", __FUNCTION__);
211 #endif 224 #endif
212 SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState); 225 SkOpEdgeBuilder builder(path, &contour, &globalState);
213 builder.finish(&allocator); 226 builder.finish();
214 SkTDArray<const SkOpContour* > runs; // indices of partial contours 227 SkTDArray<const SkOpContour* > runs; // indices of partial contours
215 const SkOpContour* eContour = builder.head(); 228 const SkOpContour* eContour = builder.head();
216 do { 229 do {
217 if (!eContour->count()) { 230 if (!eContour->count()) {
218 continue; 231 continue;
219 } 232 }
220 const SkPoint& eStart = eContour->start(); 233 const SkPoint& eStart = eContour->start();
221 const SkPoint& eEnd = eContour->end(); 234 const SkPoint& eEnd = eContour->end();
222 #if DEBUG_ASSEMBLE 235 #if DEBUG_ASSEMBLE
223 SkDebugf("%s contour", __FUNCTION__); 236 SkDebugf("%s contour", __FUNCTION__);
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 } 397 }
385 } while (rIndex < count); 398 } while (rIndex < count);
386 #if DEBUG_ASSEMBLE 399 #if DEBUG_ASSEMBLE
387 for (rIndex = 0; rIndex < count; ++rIndex) { 400 for (rIndex = 0; rIndex < count; ++rIndex) {
388 SkASSERT(sLink[rIndex] == SK_MaxS32); 401 SkASSERT(sLink[rIndex] == SK_MaxS32);
389 SkASSERT(eLink[rIndex] == SK_MaxS32); 402 SkASSERT(eLink[rIndex] == SK_MaxS32);
390 } 403 }
391 #endif 404 #endif
392 } 405 }
393 406
394 static void align(SkOpContourHead* contourList) { 407 static void calcAngles(SkOpContourHead* contourList) {
395 SkOpContour* contour = contourList; 408 SkOpContour* contour = contourList;
396 do { 409 do {
397 contour->align(); 410 contour->calcAngles();
398 } while ((contour = contour->next())); 411 } while ((contour = contour->next()));
399 } 412 }
400 413
401 static void addAlignIntersections(SkOpContourHead* contourList, SkChunkAlloc* al locator) { 414 static bool missingCoincidence(SkOpContourHead* contourList) {
402 SkOpContour* contour = contourList;
403 do {
404 contour->addAlignIntersections(contourList, allocator);
405 } while ((contour = contour->next()));
406 }
407
408 static void calcAngles(SkOpContourHead* contourList, SkChunkAlloc* allocator) {
409 SkOpContour* contour = contourList;
410 do {
411 contour->calcAngles(allocator);
412 } while ((contour = contour->next()));
413 }
414
415 static void findCollapsed(SkOpContourHead* contourList) {
416 SkOpContour* contour = contourList;
417 do {
418 contour->findCollapsed();
419 } while ((contour = contour->next()));
420 }
421
422 static bool missingCoincidence(SkOpContourHead* contourList,
423 SkOpCoincidence* coincidence, SkChunkAlloc* allocator) {
424 SkOpContour* contour = contourList; 415 SkOpContour* contour = contourList;
425 bool result = false; 416 bool result = false;
426 do { 417 do {
427 result |= contour->missingCoincidence(coincidence, allocator); 418 result |= contour->missingCoincidence();
428 } while ((contour = contour->next())); 419 } while ((contour = contour->next()));
429 return result; 420 return result;
430 } 421 }
431 422
432 static bool moveMultiples(SkOpContourHead* contourList) { 423 static bool moveMultiples(SkOpContourHead* contourList) {
433 SkOpContour* contour = contourList; 424 SkOpContour* contour = contourList;
434 do { 425 do {
435 if (!contour->moveMultiples()) { 426 if (!contour->moveMultiples()) {
436 return false; 427 return false;
437 } 428 }
438 } while ((contour = contour->next())); 429 } while ((contour = contour->next()));
439 return true; 430 return true;
440 } 431 }
441 432
442 static void moveNearby(SkOpContourHead* contourList) { 433 static void moveNearby(SkOpContourHead* contourList) {
443 SkOpContour* contour = contourList; 434 SkOpContour* contour = contourList;
444 do { 435 do {
445 contour->moveNearby(); 436 contour->moveNearby();
446 } while ((contour = contour->next())); 437 } while ((contour = contour->next()));
447 } 438 }
448 439
449 static void sortAngles(SkOpContourHead* contourList) { 440 static void sortAngles(SkOpContourHead* contourList) {
450 SkOpContour* contour = contourList; 441 SkOpContour* contour = contourList;
451 do { 442 do {
452 contour->sortAngles(); 443 contour->sortAngles();
453 } while ((contour = contour->next())); 444 } while ((contour = contour->next()));
454 } 445 }
455 446
456 bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidenc e, 447 bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidenc e) {
457 SkChunkAlloc* allocator) {
458 SkOpGlobalState* globalState = contourList->globalState(); 448 SkOpGlobalState* globalState = contourList->globalState();
449 DEBUG_COINCIDENCE_HEALTH(contourList, "start");
450 #if DEBUG_VALIDATE
451 globalState->setPhase(SkOpGlobalState::kIntersecting);
452 #endif
453
454 // match up points within the coincident runs
455 if (!coincidence->addExpanded()) {
456 return false;
457 }
458 DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded");
459 #if DEBUG_VALIDATE
460 globalState->setPhase(SkOpGlobalState::kWalking);
461 #endif
459 // combine t values when multiple intersections occur on some segments but n ot others 462 // combine t values when multiple intersections occur on some segments but n ot others
460 DEBUG_COINCIDENCE_HEALTH(contourList, "start");
461 if (!moveMultiples(contourList)) { 463 if (!moveMultiples(contourList)) {
462 return false; 464 return false;
463 } 465 }
464 DEBUG_COINCIDENCE_HEALTH(contourList, "moveMultiples"); 466 DEBUG_COINCIDENCE_HEALTH(contourList, "moveMultiples");
465 findCollapsed(contourList);
466 DEBUG_COINCIDENCE_HEALTH(contourList, "findCollapsed");
467 // move t values and points together to eliminate small/tiny gaps 467 // move t values and points together to eliminate small/tiny gaps
468 moveNearby(contourList); 468 (void) moveNearby(contourList);
469 DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby"); 469 DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby");
470 align(contourList); // give all span members common values
471 DEBUG_COINCIDENCE_HEALTH(contourList, "align");
472 if (!coincidence->fixAligned()) { // aligning may have marked a coincidence pt-t deleted
473 return false;
474 }
475 DEBUG_COINCIDENCE_HEALTH(contourList, "fixAligned");
476 #if DEBUG_VALIDATE 470 #if DEBUG_VALIDATE
477 globalState->setPhase(SkOpGlobalState::kIntersecting); 471 globalState->setPhase(SkOpGlobalState::kIntersecting);
478 #endif 472 #endif
479 // look for intersections on line segments formed by moving end points 473 // add coincidence formed by pairing on curve points and endpoints
480 addAlignIntersections(contourList, allocator); 474 coincidence->correctEnds();
481 DEBUG_COINCIDENCE_HEALTH(contourList, "addAlignIntersections"); 475 if (!coincidence->addEndMovedSpans()) {
482 if (coincidence->addMissing(allocator)) { 476 return false;
477 }
478 DEBUG_COINCIDENCE_HEALTH(contourList, "addEndMovedSpans");
479
480 const int SAFETY_COUNT = 100; // FIXME: tune
481 int safetyHatch = SAFETY_COUNT;
482 // look for coincidence present in A-B and A-C but missing in B-C
483 while (coincidence->addMissing()) {
484 if (!--safetyHatch) {
485 SkASSERT(0); // FIXME: take this out after verifying std tests don' t trigger
486 return false;
487 }
483 DEBUG_COINCIDENCE_HEALTH(contourList, "addMissing"); 488 DEBUG_COINCIDENCE_HEALTH(contourList, "addMissing");
484 moveNearby(contourList); 489 moveNearby(contourList);
485 DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby2"); 490 DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby");
486 align(contourList); // give all span members common values 491 }
487 DEBUG_COINCIDENCE_HEALTH(contourList, "align2"); 492 DEBUG_COINCIDENCE_HEALTH(contourList, "addMissing2");
488 if (!coincidence->fixAligned()) { // aligning may have marked a coincid ence pt-t deleted 493 // FIXME: only call this if addMissing modified something when returning fal se
494 moveNearby(contourList);
495 DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby2");
496 // check to see if, loosely, coincident ranges may be expanded
497 if (coincidence->expand()) {
498 DEBUG_COINCIDENCE_HEALTH(contourList, "expand1");
499 coincidence->addMissing();
500 DEBUG_COINCIDENCE_HEALTH(contourList, "addMissing2");
501 if (!coincidence->addExpanded()) {
489 return false; 502 return false;
490 } 503 }
491 DEBUG_COINCIDENCE_HEALTH(contourList, "fixAligned2"); 504 DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded2");
505 if (!moveMultiples(contourList)) {
506 return false;
507 }
508 DEBUG_COINCIDENCE_HEALTH(contourList, "moveMultiples2");
509 moveNearby(contourList);
492 } 510 }
493 #if DEBUG_VALIDATE 511 #if DEBUG_VALIDATE
494 globalState->setPhase(SkOpGlobalState::kWalking); 512 globalState->setPhase(SkOpGlobalState::kWalking);
495 #endif 513 #endif
496 // check to see if, loosely, coincident ranges may be expanded
497 if (coincidence->expand()) {
498 DEBUG_COINCIDENCE_HEALTH(contourList, "expand1");
499 if (!coincidence->addExpanded(allocator PATH_OPS_DEBUG_VALIDATE_PARAMS( globalState))) {
500 return false;
501 }
502 }
503 DEBUG_COINCIDENCE_HEALTH(contourList, "expand2"); 514 DEBUG_COINCIDENCE_HEALTH(contourList, "expand2");
504 // the expanded ranges may not align -- add the missing spans 515 // the expanded ranges may not align -- add the missing spans
516 SkAssertResult(coincidence->addExpanded());
517 DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded3");
518 coincidence->correctEnds();
505 if (!coincidence->mark()) { // mark spans of coincident segments as coincid ent 519 if (!coincidence->mark()) { // mark spans of coincident segments as coincid ent
506 return false; 520 return false;
507 } 521 }
508 DEBUG_COINCIDENCE_HEALTH(contourList, "mark1"); 522 DEBUG_COINCIDENCE_HEALTH(contourList, "mark1");
509 // look for coincidence missed earlier 523 // look for coincidence lines and curves undetected by intersection
510 if (missingCoincidence(contourList, coincidence, allocator)) { 524 if (missingCoincidence(contourList)) {
525 #if DEBUG_VALIDATE
526 globalState->setPhase(SkOpGlobalState::kIntersecting);
527 #endif
511 DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence1"); 528 DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence1");
512 (void) coincidence->expand(); 529 (void) coincidence->expand();
513 DEBUG_COINCIDENCE_HEALTH(contourList, "expand3"); 530 DEBUG_COINCIDENCE_HEALTH(contourList, "expand3");
514 if (!coincidence->addExpanded(allocator PATH_OPS_DEBUG_VALIDATE_PARAMS( globalState))) { 531 if (!coincidence->addExpanded()) {
515 return false; 532 return false;
516 } 533 }
517 DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded2"); 534 #if DEBUG_VALIDATE
518 coincidence->mark(); 535 globalState->setPhase(SkOpGlobalState::kWalking);
536 #endif
537 DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded3");
538 if (!coincidence->mark()) {
539 return false;
540 }
541 } else {
542 DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence2");
543 (void) coincidence->expand();
519 } 544 }
520 DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence2"); 545 DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence3");
521 SkOpCoincidence overlaps; 546
547 (void) coincidence->expand();
548
549 #if 0 // under development
550 // coincident runs may cross two or more spans, but the opposite spans may b e out of order
551 if (!coincidence->reorder()) {
552 return false;
553 }
554 #endif
555 DEBUG_COINCIDENCE_HEALTH(contourList, "coincidence.reorder");
556 SkOpCoincidence overlaps(globalState);
522 do { 557 do {
523 SkOpCoincidence* pairs = overlaps.isEmpty() ? coincidence : &overlaps; 558 SkOpCoincidence* pairs = overlaps.isEmpty() ? coincidence : &overlaps;
524 if (!pairs->apply()) { // adjust the winding value to account for coinc ident edges 559 if (!pairs->apply()) { // adjust the winding value to account for coinc ident edges
525 return false; 560 return false;
526 } 561 }
527 DEBUG_COINCIDENCE_HEALTH(contourList, "pairs->apply"); 562 DEBUG_COINCIDENCE_HEALTH(contourList, "pairs->apply");
528 // For each coincident pair that overlaps another, when the receivers (t he 1st of the pair) 563 // For each coincident pair that overlaps another, when the receivers (t he 1st of the pair)
529 // are different, construct a new pair to resolve their mutual span 564 // are different, construct a new pair to resolve their mutual span
530 if (!pairs->findOverlaps(&overlaps, allocator)) { 565 if (!pairs->findOverlaps(&overlaps)) {
531 return false; 566 return false;
532 } 567 }
533 DEBUG_COINCIDENCE_HEALTH(contourList, "pairs->findOverlaps"); 568 DEBUG_COINCIDENCE_HEALTH(contourList, "pairs->findOverlaps");
534 } while (!overlaps.isEmpty()); 569 } while (!overlaps.isEmpty());
535 calcAngles(contourList, allocator); 570 calcAngles(contourList);
536 sortAngles(contourList); 571 sortAngles(contourList);
537 if (globalState->angleCoincidence()) { 572 if (globalState->angleCoincidence()) {
538 (void) missingCoincidence(contourList, coincidence, allocator); 573 (void) missingCoincidence(contourList);
539 if (!coincidence->apply()) { 574 if (!coincidence->apply()) {
540 return false; 575 return false;
541 } 576 }
542 } 577 }
543 #if DEBUG_ACTIVE_SPANS 578 #if DEBUG_COINCIDENCE_VERBOSE
544 coincidence->debugShowCoincidence(); 579 coincidence->debugShowCoincidence();
545 DebugShowActiveSpans(contourList);
546 #endif 580 #endif
581 #if DEBUG_COINCIDENCE
582 coincidence->debugValidate();
583 #endif
584 SkPathOpsDebug::ShowActiveSpans(contourList);
547 return true; 585 return true;
548 } 586 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698