LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/pathops - SkOpEdgeBuilder.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 238 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 9 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 "SkGeometry.h"
       8             : #include "SkOpEdgeBuilder.h"
       9             : #include "SkReduceOrder.h"
      10             : 
      11           0 : void SkOpEdgeBuilder::init() {
      12           0 :     fOperand = false;
      13           0 :     fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask
      14             :             : kWinding_PathOpsMask;
      15           0 :     fUnparseable = false;
      16           0 :     fSecondHalf = preFetch();
      17           0 : }
      18             : 
      19             : // very tiny points cause numerical instability : don't allow them
      20           0 : static void force_small_to_zero(SkPoint* pt) {
      21           0 :     if (SkScalarAbs(pt->fX) < FLT_EPSILON_ORDERABLE_ERR) {
      22           0 :         pt->fX = 0;
      23             :     }
      24           0 :     if (SkScalarAbs(pt->fY) < FLT_EPSILON_ORDERABLE_ERR) {
      25           0 :         pt->fY = 0;
      26             :     }
      27           0 : }
      28             : 
      29           0 : static bool can_add_curve(SkPath::Verb verb, SkPoint* curve) {
      30           0 :     if (SkPath::kMove_Verb == verb) {
      31           0 :         return false;
      32             :     }
      33           0 :     for (int index = 0; index <= SkPathOpsVerbToPoints(verb); ++index) {
      34           0 :         force_small_to_zero(&curve[index]);
      35             :     }
      36           0 :     return SkPath::kLine_Verb != verb || !SkDPoint::ApproximatelyEqual(curve[0], curve[1]);
      37             : }
      38             : 
      39           0 : void SkOpEdgeBuilder::addOperand(const SkPath& path) {
      40           0 :     SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
      41           0 :     fPathVerbs.pop();
      42           0 :     fPath = &path;
      43           0 :     fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask
      44             :             : kWinding_PathOpsMask;
      45           0 :     preFetch();
      46           0 : }
      47             : 
      48           0 : bool SkOpEdgeBuilder::finish() {
      49           0 :     fOperand = false;
      50           0 :     if (fUnparseable || !walk()) {
      51           0 :         return false;
      52             :     }
      53           0 :     complete();
      54           0 :     SkOpContour* contour = fContourBuilder.contour();
      55           0 :     if (contour && !contour->count()) {
      56           0 :         fContoursHead->remove(contour);
      57             :     }
      58           0 :     return true;
      59             : }
      60             : 
      61           0 : void SkOpEdgeBuilder::closeContour(const SkPoint& curveEnd, const SkPoint& curveStart) {
      62           0 :     if (!SkDPoint::ApproximatelyEqual(curveEnd, curveStart)) {
      63           0 :         *fPathVerbs.append() = SkPath::kLine_Verb;
      64           0 :         *fPathPts.append() = curveStart;
      65             :     } else {
      66           0 :         int verbCount = fPathVerbs.count();
      67           0 :         int ptsCount = fPathPts.count();
      68           0 :         if (SkPath::kLine_Verb == fPathVerbs[verbCount - 1]
      69           0 :                 && fPathPts[ptsCount - 2] == curveStart) {
      70           0 :             fPathVerbs.pop();
      71           0 :             fPathPts.pop();
      72             :         } else {
      73           0 :             fPathPts[ptsCount - 1] = curveStart;
      74             :         }
      75             :     }
      76           0 :     *fPathVerbs.append() = SkPath::kClose_Verb;
      77           0 : }
      78             : 
      79           0 : int SkOpEdgeBuilder::preFetch() {
      80           0 :     if (!fPath->isFinite()) {
      81           0 :         fUnparseable = true;
      82           0 :         return 0;
      83             :     }
      84           0 :     SkPath::RawIter iter(*fPath);
      85             :     SkPoint curveStart;
      86             :     SkPoint curve[4];
      87             :     SkPoint pts[4];
      88             :     SkPath::Verb verb;
      89           0 :     bool lastCurve = false;
      90           0 :     do {
      91           0 :         verb = iter.next(pts);
      92           0 :         switch (verb) {
      93             :             case SkPath::kMove_Verb:
      94           0 :                 if (!fAllowOpenContours && lastCurve) {
      95           0 :                     closeContour(curve[0], curveStart);
      96             :                 }
      97           0 :                 *fPathVerbs.append() = verb;
      98           0 :                 force_small_to_zero(&pts[0]);
      99           0 :                 *fPathPts.append() = pts[0];
     100           0 :                 curveStart = curve[0] = pts[0];
     101           0 :                 lastCurve = false;
     102           0 :                 continue;
     103             :             case SkPath::kLine_Verb:
     104           0 :                 force_small_to_zero(&pts[1]);
     105           0 :                 if (SkDPoint::ApproximatelyEqual(curve[0], pts[1])) {
     106           0 :                     uint8_t lastVerb = fPathVerbs.top();
     107           0 :                     if (lastVerb != SkPath::kLine_Verb && lastVerb != SkPath::kMove_Verb) {
     108           0 :                         fPathPts.top() = curve[0] = pts[1];
     109             :                     }
     110           0 :                     continue;  // skip degenerate points
     111             :                 }
     112           0 :                 break;
     113             :             case SkPath::kQuad_Verb:
     114           0 :                 force_small_to_zero(&pts[1]);
     115           0 :                 force_small_to_zero(&pts[2]);
     116           0 :                 curve[1] = pts[1];
     117           0 :                 curve[2] = pts[2];
     118           0 :                 verb = SkReduceOrder::Quad(curve, pts);
     119           0 :                 if (verb == SkPath::kMove_Verb) {
     120           0 :                     continue;  // skip degenerate points
     121             :                 }
     122           0 :                 break;
     123             :             case SkPath::kConic_Verb:
     124           0 :                 force_small_to_zero(&pts[1]);
     125           0 :                 force_small_to_zero(&pts[2]);
     126           0 :                 curve[1] = pts[1];
     127           0 :                 curve[2] = pts[2];
     128           0 :                 verb = SkReduceOrder::Quad(curve, pts);
     129           0 :                 if (SkPath::kQuad_Verb == verb && 1 != iter.conicWeight()) {
     130           0 :                   verb = SkPath::kConic_Verb;
     131           0 :                 } else if (verb == SkPath::kMove_Verb) {
     132           0 :                     continue;  // skip degenerate points
     133             :                 }
     134           0 :                 break;
     135             :             case SkPath::kCubic_Verb:
     136           0 :                 force_small_to_zero(&pts[1]);
     137           0 :                 force_small_to_zero(&pts[2]);
     138           0 :                 force_small_to_zero(&pts[3]);
     139           0 :                 curve[1] = pts[1];
     140           0 :                 curve[2] = pts[2];
     141           0 :                 curve[3] = pts[3];
     142           0 :                 verb = SkReduceOrder::Cubic(curve, pts);
     143           0 :                 if (verb == SkPath::kMove_Verb) {
     144           0 :                     continue;  // skip degenerate points
     145             :                 }
     146           0 :                 break;
     147             :             case SkPath::kClose_Verb:
     148           0 :                 closeContour(curve[0], curveStart);
     149           0 :                 lastCurve = false;
     150           0 :                 continue;
     151             :             case SkPath::kDone_Verb:
     152           0 :                 continue;
     153             :         }
     154           0 :         *fPathVerbs.append() = verb;
     155           0 :         int ptCount = SkPathOpsVerbToPoints(verb);
     156           0 :         fPathPts.append(ptCount, &pts[1]);
     157           0 :         if (verb == SkPath::kConic_Verb) {
     158           0 :             *fWeights.append() = iter.conicWeight();
     159             :         }
     160           0 :         curve[0] = pts[ptCount];
     161           0 :         lastCurve = true;
     162           0 :     } while (verb != SkPath::kDone_Verb);
     163           0 :     if (!fAllowOpenContours && lastCurve) {
     164           0 :         closeContour(curve[0], curveStart);
     165             :     }
     166           0 :     *fPathVerbs.append() = SkPath::kDone_Verb;
     167           0 :     return fPathVerbs.count() - 1;
     168             : }
     169             : 
     170           0 : bool SkOpEdgeBuilder::close() {
     171           0 :     complete();
     172           0 :     return true;
     173             : }
     174             : 
     175           0 : bool SkOpEdgeBuilder::walk() {
     176           0 :     uint8_t* verbPtr = fPathVerbs.begin();
     177           0 :     uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
     178           0 :     SkPoint* pointsPtr = fPathPts.begin() - 1;
     179           0 :     SkScalar* weightPtr = fWeights.begin();
     180             :     SkPath::Verb verb;
     181           0 :     SkOpContour* contour = fContourBuilder.contour();
     182           0 :     while ((verb = (SkPath::Verb) *verbPtr) != SkPath::kDone_Verb) {
     183           0 :         if (verbPtr == endOfFirstHalf) {
     184           0 :             fOperand = true;
     185             :         }
     186           0 :         verbPtr++;
     187           0 :         switch (verb) {
     188             :             case SkPath::kMove_Verb:
     189           0 :                 if (contour && contour->count()) {
     190           0 :                     if (fAllowOpenContours) {
     191           0 :                         complete();
     192           0 :                     } else if (!close()) {
     193           0 :                         return false;
     194             :                     }
     195             :                 }
     196           0 :                 if (!contour) {
     197           0 :                     fContourBuilder.setContour(contour = fContoursHead->appendContour());
     198             :                 }
     199           0 :                 contour->init(fGlobalState, fOperand,
     200           0 :                     fXorMask[fOperand] == kEvenOdd_PathOpsMask);
     201           0 :                 pointsPtr += 1;
     202           0 :                 continue;
     203             :             case SkPath::kLine_Verb:
     204           0 :                 fContourBuilder.addLine(pointsPtr);
     205           0 :                 break;
     206             :             case SkPath::kQuad_Verb:
     207             :                 {
     208           0 :                     SkVector v1 = pointsPtr[1] - pointsPtr[0];
     209           0 :                     SkVector v2 = pointsPtr[2] - pointsPtr[1];
     210           0 :                     if (v1.dot(v2) < 0) {
     211             :                         SkPoint pair[5];
     212           0 :                         if (SkChopQuadAtMaxCurvature(pointsPtr, pair) == 1) {
     213           0 :                             goto addOneQuad;
     214             :                         }
     215           0 :                         if (!SkScalarsAreFinite(&pair[0].fX, SK_ARRAY_COUNT(pair) * 2)) {
     216           0 :                             return false;
     217             :                         }
     218             :                         SkPoint cStorage[2][2];
     219           0 :                         SkPath::Verb v1 = SkReduceOrder::Quad(&pair[0], cStorage[0]);
     220           0 :                         SkPath::Verb v2 = SkReduceOrder::Quad(&pair[2], cStorage[1]);
     221           0 :                         SkPoint* curve1 = v1 != SkPath::kLine_Verb ? &pair[0] : cStorage[0];
     222           0 :                         SkPoint* curve2 = v2 != SkPath::kLine_Verb ? &pair[2] : cStorage[1];
     223           0 :                         if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) {
     224           0 :                             fContourBuilder.addCurve(v1, curve1);
     225           0 :                             fContourBuilder.addCurve(v2, curve2);
     226           0 :                             break;
     227             :                         }
     228             :                     }
     229             :                 }
     230             :             addOneQuad:
     231           0 :                 fContourBuilder.addQuad(pointsPtr);
     232           0 :                 break;
     233             :             case SkPath::kConic_Verb: {
     234           0 :                 SkVector v1 = pointsPtr[1] - pointsPtr[0];
     235           0 :                 SkVector v2 = pointsPtr[2] - pointsPtr[1];
     236           0 :                 SkScalar weight = *weightPtr++;
     237           0 :                 if (v1.dot(v2) < 0) {
     238             :                     // FIXME: max curvature for conics hasn't been implemented; use placeholder
     239           0 :                     SkScalar maxCurvature = SkFindQuadMaxCurvature(pointsPtr);
     240           0 :                     if (maxCurvature > 0) {
     241           0 :                         SkConic conic(pointsPtr, weight);
     242           0 :                         SkConic pair[2];
     243           0 :                         if (!conic.chopAt(maxCurvature, pair)) {
     244             :                             // if result can't be computed, use original
     245           0 :                             fContourBuilder.addConic(pointsPtr, weight);
     246           0 :                             break;
     247             :                         }
     248             :                         SkPoint cStorage[2][3];
     249           0 :                         SkPath::Verb v1 = SkReduceOrder::Conic(pair[0], cStorage[0]);
     250           0 :                         SkPath::Verb v2 = SkReduceOrder::Conic(pair[1], cStorage[1]);
     251           0 :                         SkPoint* curve1 = v1 != SkPath::kLine_Verb ? pair[0].fPts : cStorage[0];
     252           0 :                         SkPoint* curve2 = v2 != SkPath::kLine_Verb ? pair[1].fPts : cStorage[1];
     253           0 :                         if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) {
     254           0 :                             fContourBuilder.addCurve(v1, curve1, pair[0].fW);
     255           0 :                             fContourBuilder.addCurve(v2, curve2, pair[1].fW);
     256           0 :                             break;
     257             :                         }
     258             :                     }
     259             :                 }
     260           0 :                 fContourBuilder.addConic(pointsPtr, weight);
     261           0 :                 } break;
     262             :             case SkPath::kCubic_Verb:
     263             :                 {
     264             :                     // Split complex cubics (such as self-intersecting curves or
     265             :                     // ones with difficult curvature) in two before proceeding.
     266             :                     // This can be required for intersection to succeed.
     267             :                     SkScalar splitT[3];
     268           0 :                     int breaks = SkDCubic::ComplexBreak(pointsPtr, splitT);
     269           0 :                     if (!breaks) {
     270           0 :                         fContourBuilder.addCubic(pointsPtr);
     271           0 :                         break;
     272             :                     }
     273           0 :                     SkASSERT(breaks <= (int) SK_ARRAY_COUNT(splitT));
     274             :                     struct Splitsville {
     275             :                         double fT[2];
     276             :                         SkPoint fPts[4];
     277             :                         SkPoint fReduced[4];
     278             :                         SkPath::Verb fVerb;
     279             :                         bool fCanAdd;
     280             :                     } splits[4];
     281             :                     SkASSERT(SK_ARRAY_COUNT(splits) == SK_ARRAY_COUNT(splitT) + 1);
     282           0 :                     SkTQSort(splitT, &splitT[breaks - 1]);
     283           0 :                     for (int index = 0; index <= breaks; ++index) {
     284           0 :                         Splitsville* split = &splits[index];
     285           0 :                         split->fT[0] = index ? splitT[index - 1] : 0;
     286           0 :                         split->fT[1] = index < breaks ? splitT[index] : 1;
     287           0 :                         SkDCubic part = SkDCubic::SubDivide(pointsPtr, split->fT[0], split->fT[1]);
     288           0 :                         if (!part.toFloatPoints(split->fPts)) {
     289           0 :                             return false;
     290             :                         }
     291           0 :                         split->fVerb = SkReduceOrder::Cubic(split->fPts, split->fReduced);
     292             :                         SkPoint* curve = SkPath::kCubic_Verb == verb
     293           0 :                                 ? split->fPts : split->fReduced;
     294           0 :                         split->fCanAdd = can_add_curve(split->fVerb, curve);
     295             :                     }
     296           0 :                     for (int index = 0; index <= breaks; ++index) {
     297           0 :                         Splitsville* split = &splits[index];
     298           0 :                         if (!split->fCanAdd) {
     299           0 :                             continue;
     300             :                         }
     301           0 :                         int prior = index;
     302           0 :                         while (prior > 0 && !splits[prior - 1].fCanAdd) {
     303           0 :                             --prior;
     304             :                         }
     305           0 :                         if (prior < index) {
     306           0 :                             split->fT[0] = splits[prior].fT[0];
     307             :                         }
     308           0 :                         int next = index;
     309           0 :                         while (next < breaks && !splits[next + 1].fCanAdd) {
     310           0 :                             ++next;
     311             :                         }
     312           0 :                         if (next > index) {
     313           0 :                             split->fT[1] = splits[next].fT[1];
     314             :                         }
     315           0 :                         if (prior < index || next > index) {
     316           0 :                             if (0 == split->fT[0] && 1 == split->fT[1]) {
     317           0 :                                 fContourBuilder.addCubic(pointsPtr);
     318           0 :                                 break;
     319             :                             }
     320             :                             SkDCubic part = SkDCubic::SubDivide(pointsPtr, split->fT[0],
     321           0 :                                     split->fT[1]);
     322           0 :                             if (!part.toFloatPoints(split->fPts)) {
     323           0 :                                 return false;
     324             :                             }
     325           0 :                             split->fVerb = SkReduceOrder::Cubic(split->fPts, split->fReduced);
     326             :                         }
     327           0 :                         SkPoint* curve = SkPath::kCubic_Verb == split->fVerb
     328           0 :                                 ? split->fPts : split->fReduced;
     329           0 :                         SkAssertResult(can_add_curve(split->fVerb, curve));
     330           0 :                         fContourBuilder.addCurve(split->fVerb, curve);
     331             :                     }
     332             :                 }
     333           0 :                 break;
     334             :             case SkPath::kClose_Verb:
     335           0 :                 SkASSERT(contour);
     336           0 :                 if (!close()) {
     337           0 :                     return false;
     338             :                 }
     339           0 :                 contour = nullptr;
     340           0 :                 continue;
     341             :             default:
     342           0 :                 SkDEBUGFAIL("bad verb");
     343           0 :                 return false;
     344             :         }
     345           0 :         SkASSERT(contour);
     346           0 :         if (contour->count()) {
     347           0 :             contour->debugValidate();
     348             :         }
     349           0 :         pointsPtr += SkPathOpsVerbToPoints(verb);
     350             :     }
     351           0 :     fContourBuilder.flush();
     352           0 :     if (contour && contour->count() &&!fAllowOpenContours && !close()) {
     353           0 :         return false;
     354             :     }
     355           0 :     return true;
     356             : }

Generated by: LCOV version 1.13