LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/pathops - SkPathOpsOp.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 153 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 4 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             : 
      13           0 : static SkOpSegment* findChaseOp(SkTDArray<SkOpSpanBase*>& chase, SkOpSpanBase** startPtr,
      14             :         SkOpSpanBase** endPtr) {
      15           0 :     while (chase.count()) {
      16             :         SkOpSpanBase* span;
      17           0 :         chase.pop(&span);
      18             :         // OPTIMIZE: prev makes this compatible with old code -- but is it necessary?
      19           0 :         *startPtr = span->ptT()->prev()->span();
      20           0 :         SkOpSegment* segment = (*startPtr)->segment();
      21           0 :         bool done = true;
      22           0 :         *endPtr = nullptr;
      23           0 :         if (SkOpAngle* last = segment->activeAngle(*startPtr, startPtr, endPtr, &done)) {
      24           0 :             *startPtr = last->start();
      25           0 :             *endPtr = last->end();
      26             :    #if TRY_ROTATE
      27             :             *chase.insert(0) = span;
      28             :    #else
      29           0 :             *chase.append() = span;
      30             :    #endif
      31           0 :             return last->segment();
      32             :         }
      33           0 :         if (done) {
      34           0 :             continue;
      35             :         }
      36             :         int winding;
      37             :         bool sortable;
      38           0 :         const SkOpAngle* angle = AngleWinding(*startPtr, *endPtr, &winding, &sortable);
      39           0 :         if (!angle) {
      40           0 :             return nullptr;
      41             :         }
      42           0 :         if (winding == SK_MinS32) {
      43           0 :             continue;
      44             :         }
      45             :         int sumMiWinding, sumSuWinding;
      46           0 :         if (sortable) {
      47           0 :             segment = angle->segment();
      48           0 :             sumMiWinding = segment->updateWindingReverse(angle);
      49           0 :             if (sumMiWinding == SK_MinS32) {
      50           0 :                 SkASSERT(segment->globalState()->debugSkipAssert());
      51           0 :                 return nullptr;
      52             :             }
      53           0 :             sumSuWinding = segment->updateOppWindingReverse(angle);
      54           0 :             if (sumSuWinding == SK_MinS32) {
      55           0 :                 SkASSERT(segment->globalState()->debugSkipAssert());
      56           0 :                 return nullptr;
      57             :             }
      58           0 :             if (segment->operand()) {
      59           0 :                 SkTSwap<int>(sumMiWinding, sumSuWinding);
      60             :             }
      61             :         }
      62           0 :         SkOpSegment* first = nullptr;
      63           0 :         const SkOpAngle* firstAngle = angle;
      64           0 :         while ((angle = angle->next()) != firstAngle) {
      65           0 :             segment = angle->segment();
      66           0 :             SkOpSpanBase* start = angle->start();
      67           0 :             SkOpSpanBase* end = angle->end();
      68             :             int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
      69           0 :             if (sortable) {
      70             :                 segment->setUpWindings(start, end, &sumMiWinding, &sumSuWinding,
      71           0 :                         &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
      72             :             }
      73           0 :             if (!segment->done(angle)) {
      74           0 :                 if (!first && (sortable || start->starter(end)->windSum() != SK_MinS32)) {
      75           0 :                     first = segment;
      76           0 :                     *startPtr = start;
      77           0 :                     *endPtr = end;
      78             :                 }
      79             :                 // OPTIMIZATION: should this also add to the chase?
      80           0 :                 if (sortable) {
      81             :                     (void) segment->markAngle(maxWinding, sumWinding, oppMaxWinding,
      82           0 :                         oppSumWinding, angle);
      83             :                 }
      84             :             }
      85             :         }
      86           0 :         if (first) {
      87             :        #if TRY_ROTATE
      88             :             *chase.insert(0) = span;
      89             :        #else
      90           0 :             *chase.append() = span;
      91             :        #endif
      92           0 :             return first;
      93             :         }
      94             :     }
      95           0 :     return nullptr;
      96             : }
      97             : 
      98           0 : static bool bridgeOp(SkOpContourHead* contourList, const SkPathOp op,
      99             :         const int xorMask, const int xorOpMask, SkPathWriter* simple) {
     100           0 :     bool unsortable = false;
     101             :     do {
     102           0 :         SkOpSpan* span = FindSortableTop(contourList);
     103           0 :         if (!span) {
     104           0 :             break;
     105             :         }
     106           0 :         SkOpSegment* current = span->segment();
     107           0 :         SkOpSpanBase* start = span->next();
     108           0 :         SkOpSpanBase* end = span;
     109           0 :         SkTDArray<SkOpSpanBase*> chase;
     110             :         do {
     111           0 :             if (current->activeOp(start, end, xorMask, xorOpMask, op)) {
     112           0 :                 do {
     113           0 :                     if (!unsortable && current->done()) {
     114           0 :                         break;
     115             :                     }
     116           0 :                     SkASSERT(unsortable || !current->done());
     117           0 :                     SkOpSpanBase* nextStart = start;
     118           0 :                     SkOpSpanBase* nextEnd = end;
     119             :                     SkOpSegment* next = current->findNextOp(&chase, &nextStart, &nextEnd,
     120           0 :                             &unsortable, op, xorMask, xorOpMask);
     121           0 :                     if (!next) {
     122           0 :                         if (!unsortable && simple->hasMove()
     123           0 :                                 && current->verb() != SkPath::kLine_Verb
     124           0 :                                 && !simple->isClosed()) {
     125           0 :                             if (!current->addCurveTo(start, end, simple)) {
     126           0 :                                 return false;
     127             :                             }
     128           0 :                             if (!simple->isClosed()) {
     129           0 :                                 SkPathOpsDebug::ShowActiveSpans(contourList);
     130             :                             }
     131             :                         }
     132           0 :                         break;
     133             :                     }
     134             :         #if DEBUG_FLOW
     135             :                     SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
     136             :                             current->debugID(), start->pt().fX, start->pt().fY,
     137             :                             end->pt().fX, end->pt().fY);
     138             :         #endif
     139           0 :                     if (!current->addCurveTo(start, end, simple)) {
     140           0 :                         return false;
     141             :                     }
     142           0 :                     current = next;
     143           0 :                     start = nextStart;
     144           0 :                     end = nextEnd;
     145           0 :                 } while (!simple->isClosed() && (!unsortable || !start->starter(end)->done()));
     146           0 :                 if (current->activeWinding(start, end) && !simple->isClosed()) {
     147           0 :                     SkOpSpan* spanStart = start->starter(end);
     148           0 :                     if (!spanStart->done()) {
     149           0 :                         if (!current->addCurveTo(start, end, simple)) {
     150           0 :                             return false;
     151             :                         }
     152           0 :                         current->markDone(spanStart);
     153             :                     }
     154             :                 }
     155           0 :                 simple->finishContour();
     156             :             } else {
     157           0 :                 SkOpSpanBase* last = current->markAndChaseDone(start, end);
     158           0 :                 if (last && !last->chased()) {
     159           0 :                     last->setChased(true);
     160           0 :                     SkASSERT(!SkPathOpsDebug::ChaseContains(chase, last));
     161           0 :                     *chase.append() = last;
     162             : #if DEBUG_WINDING
     163             :                     SkDebugf("%s chase.append id=%d", __FUNCTION__, last->segment()->debugID());
     164             :                     if (!last->final()) {
     165             :                          SkDebugf(" windSum=%d", last->upCast()->windSum());
     166             :                     }
     167             :                     SkDebugf("\n");
     168             : #endif
     169             :                 }
     170             :             }
     171           0 :             current = findChaseOp(chase, &start, &end);
     172           0 :             SkPathOpsDebug::ShowActiveSpans(contourList);
     173           0 :             if (!current) {
     174           0 :                 break;
     175           0 :             }
     176           0 :         } while (true);
     177             :     } while (true);
     178           0 :     return true;
     179             : }
     180             : 
     181             : // pretty picture:
     182             : // https://docs.google.com/a/google.com/drawings/d/1sPV8rPfpEFXymBp3iSbDRWAycp1b-7vD9JP2V-kn9Ss/edit?usp=sharing
     183             : static const SkPathOp gOpInverse[kReverseDifference_SkPathOp + 1][2][2] = {
     184             : //                  inside minuend                               outside minuend
     185             : //     inside subtrahend     outside subtrahend      inside subtrahend     outside subtrahend
     186             : {{ kDifference_SkPathOp,   kIntersect_SkPathOp }, { kUnion_SkPathOp, kReverseDifference_SkPathOp }},
     187             : {{ kIntersect_SkPathOp,   kDifference_SkPathOp }, { kReverseDifference_SkPathOp, kUnion_SkPathOp }},
     188             : {{ kUnion_SkPathOp, kReverseDifference_SkPathOp }, { kDifference_SkPathOp,   kIntersect_SkPathOp }},
     189             : {{ kXOR_SkPathOp,                 kXOR_SkPathOp }, { kXOR_SkPathOp,                kXOR_SkPathOp }},
     190             : {{ kReverseDifference_SkPathOp, kUnion_SkPathOp }, { kIntersect_SkPathOp,   kDifference_SkPathOp }},
     191             : };
     192             : 
     193             : static const bool gOutInverse[kReverseDifference_SkPathOp + 1][2][2] = {
     194             :     {{ false, false }, { true, false }},  // diff
     195             :     {{ false, false }, { false, true }},  // sect
     196             :     {{ false, true }, { true, true }},    // union
     197             :     {{ false, true }, { true, false }},   // xor
     198             :     {{ false, true }, { false, false }},  // rev diff
     199             : };
     200             : 
     201             : #if DEBUG_T_SECT_LOOP_COUNT
     202             : 
     203             : #include "SkMutex.h"
     204             : 
     205             : SK_DECLARE_STATIC_MUTEX(debugWorstLoop);
     206             : 
     207             : SkOpGlobalState debugWorstState(nullptr, nullptr  SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr)
     208             :         SkDEBUGPARAMS(nullptr));
     209             : 
     210             : void ReportPathOpsDebugging() {
     211             :     debugWorstState.debugLoopReport();
     212             : }
     213             : 
     214             : extern void (*gVerboseFinalize)();
     215             : 
     216             : #endif
     217             : 
     218           0 : bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result
     219             :         SkDEBUGPARAMS(bool skipAssert) SkDEBUGPARAMS(const char* testName)) {
     220             :     char storage[4096];
     221           0 :     SkArenaAlloc allocator(storage);  // FIXME: add a constant expression here, tune
     222           0 :     SkOpContour contour;
     223           0 :     SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour);
     224             :     SkOpGlobalState globalState(contourList, &allocator
     225           0 :             SkDEBUGPARAMS(skipAssert) SkDEBUGPARAMS(testName));
     226           0 :     SkOpCoincidence coincidence(&globalState);
     227             : #if DEBUG_DUMP_VERIFY
     228             : #ifndef SK_DEBUG
     229             :     const char* testName = "release";
     230             : #endif
     231             :     if (SkPathOpsDebug::gDumpOp) {
     232             :         SkPathOpsDebug::DumpOp(one, two, op, testName);
     233             :     }
     234             : #endif
     235           0 :     op = gOpInverse[op][one.isInverseFillType()][two.isInverseFillType()];
     236           0 :     SkPath::FillType fillType = gOutInverse[op][one.isInverseFillType()][two.isInverseFillType()]
     237           0 :             ? SkPath::kInverseEvenOdd_FillType : SkPath::kEvenOdd_FillType;
     238           0 :     SkScalar scaleFactor = SkTMax(ScaleFactor(one), ScaleFactor(two));
     239           0 :     SkPath scaledOne, scaledTwo;
     240             :     const SkPath* minuend, * subtrahend;
     241           0 :     if (scaleFactor > SK_Scalar1) {
     242           0 :         ScalePath(one, 1.f / scaleFactor, &scaledOne);
     243           0 :         minuend = &scaledOne;
     244           0 :         ScalePath(two, 1.f / scaleFactor, &scaledTwo);
     245           0 :         subtrahend = &scaledTwo;
     246             :     } else {
     247           0 :         minuend = &one;
     248           0 :         subtrahend = &two;
     249             :     }
     250           0 :     if (op == kReverseDifference_SkPathOp) {
     251           0 :         SkTSwap(minuend, subtrahend);
     252           0 :         op = kDifference_SkPathOp;
     253             :     }
     254             : #if DEBUG_SORT
     255             :     SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault;
     256             : #endif
     257             :     // turn path into list of segments
     258           0 :     SkOpEdgeBuilder builder(*minuend, contourList, &globalState);
     259           0 :     if (builder.unparseable()) {
     260           0 :         return false;
     261             :     }
     262           0 :     const int xorMask = builder.xorMask();
     263           0 :     builder.addOperand(*subtrahend);
     264           0 :     if (!builder.finish()) {
     265           0 :         return false;
     266             :     }
     267             : #if DEBUG_DUMP_SEGMENTS
     268             :     contourList->dumpSegments("seg", op);
     269             : #endif
     270             : 
     271           0 :     const int xorOpMask = builder.xorMask();
     272           0 :     if (!SortContourList(&contourList, xorMask == kEvenOdd_PathOpsMask,
     273             :             xorOpMask == kEvenOdd_PathOpsMask)) {
     274           0 :         result->reset();
     275           0 :         result->setFillType(fillType);
     276           0 :         return true;
     277             :     }
     278             :     // find all intersections between segments
     279           0 :     SkOpContour* current = contourList;
     280           0 :     do {
     281           0 :         SkOpContour* next = current;
     282           0 :         while (AddIntersectTs(current, next, &coincidence)
     283           0 :                 && (next = next->next()))
     284             :             ;
     285             :     } while ((current = current->next()));
     286             : #if DEBUG_VALIDATE
     287             :     globalState.setPhase(SkOpPhase::kWalking);
     288             : #endif
     289           0 :     bool success = HandleCoincidence(contourList, &coincidence);
     290             : #if DEBUG_COIN
     291             :     globalState.debugAddToGlobalCoinDicts();
     292             : #endif
     293           0 :     if (!success) {
     294           0 :         return false;
     295             :     }
     296             : #if DEBUG_ALIGNMENT
     297             :     contourList->dumpSegments("aligned");
     298             : #endif
     299             :     // construct closed contours
     300           0 :     result->reset();
     301           0 :     result->setFillType(fillType);
     302           0 :     SkPathWriter wrapper(*result);
     303           0 :     if (!bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper)) {
     304           0 :         return false;
     305             :     }
     306           0 :     wrapper.assemble();  // if some edges could not be resolved, assemble remaining
     307             : #if DEBUG_T_SECT_LOOP_COUNT
     308             :     {
     309             :         SkAutoMutexAcquire autoM(debugWorstLoop);
     310             :         if (!gVerboseFinalize) {
     311             :             gVerboseFinalize = &ReportPathOpsDebugging;
     312             :         }
     313             :         debugWorstState.debugDoYourWorst(&globalState);
     314             :     }
     315             : #endif
     316           0 :     if (scaleFactor > 1) {
     317           0 :         ScalePath(*result, scaleFactor, result);
     318             :     }
     319           0 :     return true;
     320             : }
     321             : 
     322           0 : bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) {
     323             : #if DEBUG_DUMP_VERIFY
     324             :     if (SkPathOpsDebug::gVerifyOp) {
     325             :         if (!OpDebug(one, two, op, result  SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr))) {
     326             :             SkPathOpsDebug::ReportOpFail(one, two, op);
     327             :             return false;
     328             :         }
     329             :         SkPathOpsDebug::VerifyOp(one, two, op, *result);
     330             :         return true;
     331             :     }
     332             : #endif
     333           0 :     return OpDebug(one, two, op, result  SkDEBUGPARAMS(true) SkDEBUGPARAMS(nullptr));
     334             : }

Generated by: LCOV version 1.13