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

          Line data    Source code
       1             : /*
       2             :  * Copyright 2014 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             : 
       8             : #include "SkArenaAlloc.h"
       9             : #include "SkMatrix.h"
      10             : #include "SkOpEdgeBuilder.h"
      11             : #include "SkPathPriv.h"
      12             : #include "SkPathOps.h"
      13             : #include "SkPathOpsCommon.h"
      14             : 
      15           0 : static bool one_contour(const SkPath& path) {
      16             :     char storage[256];
      17           0 :     SkArenaAlloc allocator(storage);
      18           0 :     int verbCount = path.countVerbs();
      19           0 :     uint8_t* verbs = (uint8_t*) allocator.makeArrayDefault<uint8_t>(verbCount);
      20           0 :     (void) path.getVerbs(verbs, verbCount);
      21           0 :     for (int index = 1; index < verbCount; ++index) {
      22           0 :         if (verbs[index] == SkPath::kMove_Verb) {
      23           0 :             return false;
      24             :         }
      25             :     }
      26           0 :     return true;
      27             : }
      28             : 
      29           0 : void SkOpBuilder::ReversePath(SkPath* path) {
      30           0 :     SkPath temp;
      31             :     SkPoint lastPt;
      32           0 :     SkAssertResult(path->getLastPt(&lastPt));
      33           0 :     temp.moveTo(lastPt);
      34           0 :     temp.reversePathTo(*path);
      35           0 :     temp.close();
      36           0 :     *path = temp;
      37           0 : }
      38             : 
      39           0 : bool SkOpBuilder::FixWinding(SkPath* path) {
      40           0 :     SkPath::FillType fillType = path->getFillType();
      41           0 :     if (fillType == SkPath::kInverseEvenOdd_FillType) {
      42           0 :         fillType = SkPath::kInverseWinding_FillType;
      43           0 :     } else if (fillType == SkPath::kEvenOdd_FillType) {
      44           0 :         fillType = SkPath::kWinding_FillType;
      45             :     }
      46             :     SkPathPriv::FirstDirection dir;
      47           0 :     if (one_contour(*path) && SkPathPriv::CheapComputeFirstDirection(*path, &dir)) {
      48           0 :         if (dir != SkPathPriv::kCCW_FirstDirection) {
      49           0 :             ReversePath(path);
      50             :         }
      51           0 :         path->setFillType(fillType);
      52           0 :         return true;
      53             :     }
      54             :     char storage[4096];
      55           0 :     SkArenaAlloc allocator(storage);
      56           0 :     SkOpContourHead contourHead;
      57             :     SkOpGlobalState globalState(&contourHead, &allocator  SkDEBUGPARAMS(false)
      58           0 :             SkDEBUGPARAMS(nullptr));
      59           0 :     SkOpEdgeBuilder builder(*path, &contourHead, &globalState);
      60           0 :     if (builder.unparseable() || !builder.finish()) {
      61           0 :         return false;
      62             :     }
      63           0 :     if (!contourHead.count()) {
      64           0 :         return true;
      65             :     }
      66           0 :     if (!contourHead.next()) {
      67           0 :         return false;
      68             :     }
      69           0 :     contourHead.joinAllSegments();
      70           0 :     contourHead.resetReverse();
      71           0 :     bool writePath = false;
      72             :     SkOpSpan* topSpan;
      73           0 :     globalState.setPhase(SkOpPhase::kFixWinding);
      74           0 :     while ((topSpan = FindSortableTop(&contourHead))) {
      75           0 :         SkOpSegment* topSegment = topSpan->segment();
      76           0 :         SkOpContour* topContour = topSegment->contour();
      77           0 :         SkASSERT(topContour->isCcw() >= 0);
      78             : #if DEBUG_WINDING
      79             :         SkDebugf("%s id=%d nested=%d ccw=%d\n",  __FUNCTION__,
      80             :                 topSegment->debugID(), globalState.nested(), topContour->isCcw());
      81             : #endif
      82           0 :         if ((globalState.nested() & 1) != SkToBool(topContour->isCcw())) {
      83           0 :             topContour->setReverse();
      84           0 :             writePath = true;
      85             :         }
      86           0 :         topContour->markAllDone();
      87           0 :         globalState.clearNested();
      88             :     }
      89           0 :     if (!writePath) {
      90           0 :         path->setFillType(fillType);
      91           0 :         return true;
      92             :     }
      93           0 :     SkPath empty;
      94           0 :     SkPathWriter woundPath(empty);
      95           0 :     SkOpContour* test = &contourHead;
      96           0 :     do {
      97           0 :         if (!test->count()) {
      98           0 :             continue;
      99             :         }
     100           0 :         if (test->reversed()) {
     101           0 :             test->toReversePath(&woundPath);
     102             :         } else {
     103           0 :             test->toPath(&woundPath);
     104             :         }
     105             :     } while ((test = test->next()));
     106           0 :     *path = *woundPath.nativePath();
     107           0 :     path->setFillType(fillType);
     108           0 :     return true;
     109             : }
     110             : 
     111           0 : void SkOpBuilder::add(const SkPath& path, SkPathOp op) {
     112           0 :     if (0 == fOps.count() && op != kUnion_SkPathOp) {
     113           0 :         fPathRefs.push_back() = SkPath();
     114           0 :         *fOps.append() = kUnion_SkPathOp;
     115             :     }
     116           0 :     fPathRefs.push_back() = path;
     117           0 :     *fOps.append() = op;
     118           0 : }
     119             : 
     120           0 : void SkOpBuilder::reset() {
     121           0 :     fPathRefs.reset();
     122           0 :     fOps.reset();
     123           0 : }
     124             : 
     125             : /* OPTIMIZATION: Union doesn't need to be all-or-nothing. A run of three or more convex
     126             :    paths with union ops could be locally resolved and still improve over doing the
     127             :    ops one at a time. */
     128           0 : bool SkOpBuilder::resolve(SkPath* result) {
     129           0 :     SkPath original = *result;
     130           0 :     int count = fOps.count();
     131           0 :     bool allUnion = true;
     132           0 :     SkPathPriv::FirstDirection firstDir = SkPathPriv::kUnknown_FirstDirection;
     133           0 :     for (int index = 0; index < count; ++index) {
     134           0 :         SkPath* test = &fPathRefs[index];
     135           0 :         if (kUnion_SkPathOp != fOps[index] || test->isInverseFillType()) {
     136           0 :             allUnion = false;
     137           0 :             break;
     138             :         }
     139             :         // If all paths are convex, track direction, reversing as needed.
     140           0 :         if (test->isConvex()) {
     141             :             SkPathPriv::FirstDirection dir;
     142           0 :             if (!SkPathPriv::CheapComputeFirstDirection(*test, &dir)) {
     143           0 :                 allUnion = false;
     144           0 :                 break;
     145             :             }
     146           0 :             if (firstDir == SkPathPriv::kUnknown_FirstDirection) {
     147           0 :                 firstDir = dir;
     148           0 :             } else if (firstDir != dir) {
     149           0 :                 ReversePath(test);
     150             :             }
     151           0 :             continue;
     152             :         }
     153             :         // If the path is not convex but its bounds do not intersect the others, simplify is enough.
     154           0 :         const SkRect& testBounds = test->getBounds();
     155           0 :         for (int inner = 0; inner < index; ++inner) {
     156             :             // OPTIMIZE: check to see if the contour bounds do not intersect other contour bounds?
     157           0 :             if (SkRect::Intersects(fPathRefs[inner].getBounds(), testBounds)) {
     158           0 :                 allUnion = false;
     159           0 :                 break;
     160             :             }
     161             :         }
     162             :     }
     163           0 :     if (!allUnion) {
     164           0 :         *result = fPathRefs[0];
     165           0 :         for (int index = 1; index < count; ++index) {
     166           0 :             if (!Op(*result, fPathRefs[index], fOps[index], result)) {
     167           0 :                 reset();
     168           0 :                 *result = original;
     169           0 :                 return false;
     170             :             }
     171             :         }
     172           0 :         reset();
     173           0 :         return true;
     174             :     }
     175           0 :     SkPath sum;
     176           0 :     for (int index = 0; index < count; ++index) {
     177           0 :         if (!Simplify(fPathRefs[index], &fPathRefs[index])) {
     178           0 :             reset();
     179           0 :             *result = original;
     180           0 :             return false;
     181             :         }
     182           0 :         if (!fPathRefs[index].isEmpty()) {
     183             :             // convert the even odd result back to winding form before accumulating it
     184           0 :             if (!FixWinding(&fPathRefs[index])) {
     185           0 :                 *result = original;
     186           0 :                 return false;
     187             :             }
     188           0 :             sum.addPath(fPathRefs[index]);
     189             :         }
     190             :     }
     191           0 :     reset();
     192           0 :     bool success = Simplify(sum, result);
     193           0 :     if (!success) {
     194           0 :         *result = original;
     195             :     }
     196           0 :     return success;
     197             : }

Generated by: LCOV version 1.13