LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/pathops - SkPathOpsCommon.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 214 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2012 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : #include "SkAddIntersections.h"
       8             : #include "SkOpCoincidence.h"
       9             : #include "SkOpEdgeBuilder.h"
      10             : #include "SkPathOpsCommon.h"
      11             : #include "SkPathWriter.h"
      12             : #include "SkTSort.h"
      13             : 
      14           0 : SkScalar ScaleFactor(const SkPath& path) {
      15             :     static const SkScalar twoTo10 = 1024.f;
      16           0 :     SkScalar largest = 0;
      17           0 :     const SkScalar* oneBounds = &path.getBounds().fLeft;
      18           0 :     for (int index = 0; index < 4; ++index) {
      19           0 :         largest = SkTMax(largest, SkScalarAbs(oneBounds[index]));
      20             :     }
      21           0 :     SkScalar scale = twoTo10;
      22             :     SkScalar next;
      23           0 :     while ((next = scale * twoTo10) < largest) {
      24           0 :         scale = next;
      25             :     }
      26           0 :     return scale == twoTo10 ? SK_Scalar1 : scale;
      27             : }
      28             : 
      29           0 : void ScalePath(const SkPath& path, SkScalar scale, SkPath* scaled) {
      30             :     SkMatrix matrix;
      31           0 :     matrix.setScale(scale, scale);
      32           0 :     *scaled = path;
      33           0 :     scaled->transform(matrix);
      34           0 : }
      35             : 
      36           0 : const SkOpAngle* AngleWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* windingPtr,
      37             :         bool* sortablePtr) {
      38             :     // find first angle, initialize winding to computed fWindSum
      39           0 :     SkOpSegment* segment = start->segment();
      40           0 :     const SkOpAngle* angle = segment->spanToAngle(start, end);
      41           0 :     if (!angle) {
      42           0 :         *windingPtr = SK_MinS32;
      43           0 :         return nullptr;
      44             :     }
      45           0 :     bool computeWinding = false;
      46           0 :     const SkOpAngle* firstAngle = angle;
      47           0 :     bool loop = false;
      48           0 :     bool unorderable = false;
      49           0 :     int winding = SK_MinS32;
      50           0 :     do {
      51           0 :         angle = angle->next();
      52           0 :         if (!angle) {
      53           0 :             return nullptr;
      54             :         }
      55           0 :         unorderable |= angle->unorderable();
      56           0 :         if ((computeWinding = unorderable || (angle == firstAngle && loop))) {
      57           0 :             break;    // if we get here, there's no winding, loop is unorderable
      58             :         }
      59           0 :         loop |= angle == firstAngle;
      60           0 :         segment = angle->segment();
      61           0 :         winding = segment->windSum(angle);
      62           0 :     } while (winding == SK_MinS32);
      63             :     // if the angle loop contains an unorderable span, the angle order may be useless
      64             :     // directly compute the winding in this case for each span
      65           0 :     if (computeWinding) {
      66           0 :         firstAngle = angle;
      67           0 :         winding = SK_MinS32;
      68           0 :         do {
      69           0 :             SkOpSpanBase* startSpan = angle->start();
      70           0 :             SkOpSpanBase* endSpan = angle->end();
      71           0 :             SkOpSpan* lesser = startSpan->starter(endSpan);
      72           0 :             int testWinding = lesser->windSum();
      73           0 :             if (testWinding == SK_MinS32) {
      74           0 :                 testWinding = lesser->computeWindSum();
      75             :             }
      76           0 :             if (testWinding != SK_MinS32) {
      77           0 :                 segment = angle->segment();
      78           0 :                 winding = testWinding;
      79             :             }
      80           0 :             angle = angle->next();
      81           0 :         } while (angle != firstAngle);
      82             :     }
      83           0 :     *sortablePtr = !unorderable;
      84           0 :     *windingPtr = winding;
      85           0 :     return angle;
      86             : }
      87             : 
      88           0 : SkOpSpan* FindUndone(SkOpContourHead* contourHead) {
      89           0 :     SkOpContour* contour = contourHead;
      90           0 :     do {
      91           0 :         if (contour->done()) {
      92           0 :             continue;
      93             :         }
      94           0 :         SkOpSpan* result = contour->undoneSpan();
      95           0 :         if (result) {
      96           0 :             return result;
      97             :         }
      98             :     } while ((contour = contour->next()));
      99           0 :     return nullptr;
     100             : }
     101             : 
     102           0 : SkOpSegment* FindChase(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** startPtr,
     103             :         SkOpSpanBase** endPtr) {
     104           0 :     while (chase->count()) {
     105             :         SkOpSpanBase* span;
     106           0 :         chase->pop(&span);
     107           0 :         SkOpSegment* segment = span->segment();
     108           0 :         *startPtr = span->ptT()->next()->span();
     109           0 :         bool done = true;
     110           0 :         *endPtr = nullptr;
     111           0 :         if (SkOpAngle* last = segment->activeAngle(*startPtr, startPtr, endPtr, &done)) {
     112           0 :             *startPtr = last->start();
     113           0 :             *endPtr = last->end();
     114             :     #if TRY_ROTATE
     115             :             *chase->insert(0) = span;
     116             :     #else
     117           0 :             *chase->append() = span;
     118             :     #endif
     119           0 :             return last->segment();
     120             :         }
     121           0 :         if (done) {
     122           0 :             continue;
     123             :         }
     124             :         // find first angle, initialize winding to computed wind sum
     125             :         int winding;
     126             :         bool sortable;
     127           0 :         const SkOpAngle* angle = AngleWinding(*startPtr, *endPtr, &winding, &sortable);
     128           0 :         if (!angle) {
     129           0 :             return nullptr;
     130             :         }
     131           0 :         if (winding == SK_MinS32) {
     132           0 :             continue;
     133             :         }
     134           0 :         int sumWinding SK_INIT_TO_AVOID_WARNING;
     135           0 :         if (sortable) {
     136           0 :             segment = angle->segment();
     137           0 :             sumWinding = segment->updateWindingReverse(angle);
     138             :         }
     139           0 :         SkOpSegment* first = nullptr;
     140           0 :         const SkOpAngle* firstAngle = angle;
     141           0 :         while ((angle = angle->next()) != firstAngle) {
     142           0 :             segment = angle->segment();
     143           0 :             SkOpSpanBase* start = angle->start();
     144           0 :             SkOpSpanBase* end = angle->end();
     145           0 :             int maxWinding SK_INIT_TO_AVOID_WARNING;
     146           0 :             if (sortable) {
     147           0 :                 segment->setUpWinding(start, end, &maxWinding, &sumWinding);
     148             :             }
     149           0 :             if (!segment->done(angle)) {
     150           0 :                 if (!first && (sortable || start->starter(end)->windSum() != SK_MinS32)) {
     151           0 :                     first = segment;
     152           0 :                     *startPtr = start;
     153           0 :                     *endPtr = end;
     154             :                 }
     155             :                 // OPTIMIZATION: should this also add to the chase?
     156           0 :                 if (sortable) {
     157           0 :                     (void) segment->markAngle(maxWinding, sumWinding, angle);
     158             :                 }
     159             :             }
     160             :         }
     161           0 :         if (first) {
     162             :        #if TRY_ROTATE
     163             :             *chase->insert(0) = span;
     164             :        #else
     165           0 :             *chase->append() = span;
     166             :        #endif
     167           0 :             return first;
     168             :         }
     169             :     }
     170           0 :     return nullptr;
     171             : }
     172             : 
     173           0 : bool SortContourList(SkOpContourHead** contourList, bool evenOdd, bool oppEvenOdd) {
     174           0 :     SkTDArray<SkOpContour* > list;
     175           0 :     SkOpContour* contour = *contourList;
     176           0 :     do {
     177           0 :         if (contour->count()) {
     178           0 :             contour->setOppXor(contour->operand() ? evenOdd : oppEvenOdd);
     179           0 :             *list.append() = contour;
     180             :         }
     181             :     } while ((contour = contour->next()));
     182           0 :     int count = list.count();
     183           0 :     if (!count) {
     184           0 :         return false;
     185             :     }
     186           0 :     if (count > 1) {
     187           0 :         SkTQSort<SkOpContour>(list.begin(), list.end() - 1);
     188             :     }
     189           0 :     contour = list[0];
     190           0 :     SkOpContourHead* contourHead = static_cast<SkOpContourHead*>(contour);
     191           0 :     contour->globalState()->setContourHead(contourHead);
     192           0 :     *contourList = contourHead;
     193           0 :     for (int index = 1; index < count; ++index) {
     194           0 :         SkOpContour* next = list[index];
     195           0 :         contour->setNext(next);
     196           0 :         contour = next;
     197             :     }
     198           0 :     contour->setNext(nullptr);
     199           0 :     return true;
     200             : }
     201             : 
     202           0 : static void calc_angles(SkOpContourHead* contourList  DEBUG_COIN_DECLARE_PARAMS()) {
     203             :     DEBUG_STATIC_SET_PHASE(contourList);
     204           0 :     SkOpContour* contour = contourList;
     205           0 :     do {
     206           0 :         contour->calcAngles();
     207             :     } while ((contour = contour->next()));
     208           0 : }
     209             : 
     210           0 : static bool missing_coincidence(SkOpContourHead* contourList  DEBUG_COIN_DECLARE_PARAMS()) {
     211             :     DEBUG_STATIC_SET_PHASE(contourList);
     212           0 :     SkOpContour* contour = contourList;
     213           0 :     bool result = false;
     214           0 :     do {
     215           0 :         result |= contour->missingCoincidence();
     216             :     } while ((contour = contour->next()));
     217           0 :     return result;
     218             : }
     219             : 
     220           0 : static bool move_multiples(SkOpContourHead* contourList  DEBUG_COIN_DECLARE_PARAMS()) {
     221             :     DEBUG_STATIC_SET_PHASE(contourList);
     222           0 :     SkOpContour* contour = contourList;
     223           0 :     do {
     224           0 :         if (!contour->moveMultiples()) {
     225           0 :             return false;
     226             :         }
     227             :     } while ((contour = contour->next()));
     228           0 :     return true;
     229             : }
     230             : 
     231           0 : static bool move_nearby(SkOpContourHead* contourList  DEBUG_COIN_DECLARE_PARAMS()) {
     232             :     DEBUG_STATIC_SET_PHASE(contourList);
     233           0 :     SkOpContour* contour = contourList;
     234           0 :     do {
     235           0 :         if (!contour->moveNearby()) {
     236           0 :             return false;
     237             :         }
     238             :     } while ((contour = contour->next()));
     239           0 :     return true;
     240             : }
     241             : 
     242           0 : static bool sort_angles(SkOpContourHead* contourList) {
     243           0 :     SkOpContour* contour = contourList;
     244           0 :     do {
     245           0 :         if (!contour->sortAngles()) {
     246           0 :             return false;
     247             :         }
     248             :     } while ((contour = contour->next()));
     249           0 :     return true;
     250             : }
     251             : 
     252           0 : bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidence) {
     253           0 :     SkOpGlobalState* globalState = contourList->globalState();
     254             :     // match up points within the coincident runs
     255           0 :     if (!coincidence->addExpanded(DEBUG_PHASE_ONLY_PARAMS(kIntersecting))) {
     256           0 :         return false;
     257             :     }
     258             :     // combine t values when multiple intersections occur on some segments but not others
     259           0 :     if (!move_multiples(contourList  DEBUG_PHASE_PARAMS(kWalking))) {
     260           0 :         return false;
     261             :     }
     262             :     // move t values and points together to eliminate small/tiny gaps
     263           0 :     if (!move_nearby(contourList  DEBUG_COIN_PARAMS())) {
     264           0 :         return false;
     265             :     }
     266             :     // add coincidence formed by pairing on curve points and endpoints
     267           0 :     coincidence->correctEnds(DEBUG_PHASE_ONLY_PARAMS(kIntersecting));
     268           0 :     if (!coincidence->addEndMovedSpans(DEBUG_COIN_ONLY_PARAMS())) {
     269           0 :         return false;
     270             :     }
     271           0 :     const int SAFETY_COUNT = 3;
     272           0 :     int safetyHatch = SAFETY_COUNT;
     273             :     // look for coincidence present in A-B and A-C but missing in B-C
     274             :     do {
     275             :         bool added;
     276           0 :         if (!coincidence->addMissing(&added  DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch))) {
     277           0 :             return false;
     278             :         }
     279           0 :         if (!added) {
     280           0 :             break;
     281             :         }
     282           0 :         if (!--safetyHatch) {
     283           0 :             SkASSERT(globalState->debugSkipAssert());
     284           0 :             return false;
     285             :         }
     286           0 :         move_nearby(contourList  DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch - 1));
     287             :     } while (true);
     288             :     // check to see if, loosely, coincident ranges may be expanded
     289           0 :     if (coincidence->expand(DEBUG_COIN_ONLY_PARAMS())) {
     290             :         bool added;
     291           0 :         if (!coincidence->addMissing(&added  DEBUG_COIN_PARAMS())) {
     292           0 :             return false;
     293             :         }
     294           0 :         if (!coincidence->addExpanded(DEBUG_COIN_ONLY_PARAMS())) {
     295           0 :             return false;
     296             :         }
     297           0 :         if (!move_multiples(contourList  DEBUG_COIN_PARAMS())) {
     298           0 :             return false;
     299             :         }
     300           0 :         move_nearby(contourList  DEBUG_COIN_PARAMS());
     301             :     }
     302             :     // the expanded ranges may not align -- add the missing spans
     303           0 :     if (!coincidence->addExpanded(DEBUG_PHASE_ONLY_PARAMS(kWalking))) {
     304           0 :         return false;
     305             :     }
     306             :     // mark spans of coincident segments as coincident
     307           0 :     coincidence->mark(DEBUG_COIN_ONLY_PARAMS());
     308             :     // look for coincidence lines and curves undetected by intersection
     309           0 :     if (missing_coincidence(contourList  DEBUG_COIN_PARAMS())) {
     310           0 :         (void) coincidence->expand(DEBUG_PHASE_ONLY_PARAMS(kIntersecting));
     311           0 :         if (!coincidence->addExpanded(DEBUG_COIN_ONLY_PARAMS())) {
     312           0 :             return false;
     313             :         }
     314           0 :         if (!coincidence->mark(DEBUG_PHASE_ONLY_PARAMS(kWalking))) {
     315           0 :             return false;
     316             :         }
     317             :     } else {
     318           0 :         (void) coincidence->expand(DEBUG_COIN_ONLY_PARAMS());
     319             :     }
     320           0 :     (void) coincidence->expand(DEBUG_COIN_ONLY_PARAMS());
     321             : 
     322           0 :     SkOpCoincidence overlaps(globalState);
     323           0 :     safetyHatch = SAFETY_COUNT;
     324           0 :     do {
     325           0 :         SkOpCoincidence* pairs = overlaps.isEmpty() ? coincidence : &overlaps;
     326             :         // adjust the winding value to account for coincident edges
     327           0 :         if (!pairs->apply(DEBUG_ITER_ONLY_PARAMS(SAFETY_COUNT - safetyHatch))) {
     328           0 :             return false;
     329             :         } 
     330             :         // For each coincident pair that overlaps another, when the receivers (the 1st of the pair)
     331             :         // are different, construct a new pair to resolve their mutual span
     332           0 :         if (!pairs->findOverlaps(&overlaps  DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch))) {
     333           0 :             return false;
     334             :         }
     335           0 :         if (!--safetyHatch) {
     336           0 :             SkASSERT(globalState->debugSkipAssert());
     337           0 :             return false;
     338             :         }
     339           0 :     } while (!overlaps.isEmpty());
     340           0 :     calc_angles(contourList  DEBUG_COIN_PARAMS());
     341           0 :     if (!sort_angles(contourList)) {
     342           0 :         return false;
     343             :     }
     344             : #if DEBUG_COINCIDENCE_VERBOSE
     345             :     coincidence->debugShowCoincidence();
     346             : #endif
     347             : #if DEBUG_COINCIDENCE
     348             :     coincidence->debugValidate();
     349             : #endif
     350           0 :     SkPathOpsDebug::ShowActiveSpans(contourList);
     351           0 :     return true;
     352             : }

Generated by: LCOV version 1.13