Home | History | Annotate | Download | only in pathops
      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 "SkPathOpsPoint.h"
      8 #include "SkPathWriter.h"
      9 
     10 // wrap path to keep track of whether the contour is initialized and non-empty
     11 SkPathWriter::SkPathWriter(SkPath& path)
     12     : fPathPtr(&path)
     13     , fCloses(0)
     14     , fMoves(0)
     15 {
     16     init();
     17 }
     18 
     19 void SkPathWriter::close() {
     20     if (!fHasMove) {
     21         return;
     22     }
     23     bool callClose = isClosed();
     24     lineTo();
     25     if (fEmpty) {
     26         return;
     27     }
     28     if (callClose) {
     29 #if DEBUG_PATH_CONSTRUCTION
     30         SkDebugf("path.close();\n");
     31 #endif
     32         fPathPtr->close();
     33         fCloses++;
     34     }
     35     init();
     36 }
     37 
     38 void SkPathWriter::conicTo(const SkPoint& pt1, const SkPoint& pt2, SkScalar weight) {
     39     lineTo();
     40     if (fEmpty && AlmostEqualUlps(fDefer[0], pt1) && AlmostEqualUlps(pt1, pt2)) {
     41         deferredLine(pt2);
     42         return;
     43     }
     44     moveTo();
     45     fDefer[1] = pt2;
     46     nudge();
     47     fDefer[0] = fDefer[1];
     48 #if DEBUG_PATH_CONSTRUCTION
     49     SkDebugf("path.conicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g);\n",
     50             pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY, weight);
     51 #endif
     52     fPathPtr->conicTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY, weight);
     53     fEmpty = false;
     54 }
     55 
     56 void SkPathWriter::cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
     57     lineTo();
     58     if (fEmpty && AlmostEqualUlps(fDefer[0], pt1) && AlmostEqualUlps(pt1, pt2)
     59             && AlmostEqualUlps(pt2, pt3)) {
     60         deferredLine(pt3);
     61         return;
     62     }
     63     moveTo();
     64     fDefer[1] = pt3;
     65     nudge();
     66     fDefer[0] = fDefer[1];
     67 #if DEBUG_PATH_CONSTRUCTION
     68     SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
     69             pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
     70 #endif
     71     fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
     72     fEmpty = false;
     73 }
     74 
     75 void SkPathWriter::deferredLine(const SkPoint& pt) {
     76     if (pt == fDefer[1]) {
     77         return;
     78     }
     79     if (changedSlopes(pt)) {
     80         lineTo();
     81         fDefer[0] = fDefer[1];
     82     }
     83     fDefer[1] = pt;
     84 }
     85 
     86 void SkPathWriter::deferredMove(const SkPoint& pt) {
     87     fMoved = true;
     88     fHasMove = true;
     89     fEmpty = true;
     90     fDefer[0] = fDefer[1] = pt;
     91 }
     92 
     93 void SkPathWriter::deferredMoveLine(const SkPoint& pt) {
     94     if (!fHasMove) {
     95         deferredMove(pt);
     96     }
     97     deferredLine(pt);
     98 }
     99 
    100 bool SkPathWriter::hasMove() const {
    101     return fHasMove;
    102 }
    103 
    104 void SkPathWriter::init() {
    105     fEmpty = true;
    106     fHasMove = false;
    107     fMoved = false;
    108 }
    109 
    110 bool SkPathWriter::isClosed() const {
    111     return !fEmpty && SkDPoint::ApproximatelyEqual(fFirstPt, fDefer[1]);
    112 }
    113 
    114 void SkPathWriter::lineTo() {
    115     if (fDefer[0] == fDefer[1]) {
    116         return;
    117     }
    118     moveTo();
    119     nudge();
    120     fEmpty = false;
    121 #if DEBUG_PATH_CONSTRUCTION
    122     SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
    123 #endif
    124     fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
    125     fDefer[0] = fDefer[1];
    126 }
    127 
    128 const SkPath* SkPathWriter::nativePath() const {
    129     return fPathPtr;
    130 }
    131 
    132 void SkPathWriter::nudge() {
    133     if (fEmpty || !AlmostEqualUlps(fDefer[1].fX, fFirstPt.fX)
    134             || !AlmostEqualUlps(fDefer[1].fY, fFirstPt.fY)) {
    135         return;
    136     }
    137     fDefer[1] = fFirstPt;
    138 }
    139 
    140 void SkPathWriter::quadTo(const SkPoint& pt1, const SkPoint& pt2) {
    141     lineTo();
    142     if (fEmpty && AlmostEqualUlps(fDefer[0], pt1) && AlmostEqualUlps(pt1, pt2)) {
    143         deferredLine(pt2);
    144         return;
    145     }
    146     moveTo();
    147     fDefer[1] = pt2;
    148     nudge();
    149     fDefer[0] = fDefer[1];
    150 #if DEBUG_PATH_CONSTRUCTION
    151     SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
    152             pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
    153 #endif
    154     fPathPtr->quadTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
    155     fEmpty = false;
    156 }
    157 
    158 bool SkPathWriter::someAssemblyRequired() const {
    159     return fCloses < fMoves;
    160 }
    161 
    162 bool SkPathWriter::changedSlopes(const SkPoint& pt) const {
    163     if (fDefer[0] == fDefer[1]) {
    164         return false;
    165     }
    166     SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
    167     SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
    168     SkScalar lineDx = pt.fX - fDefer[1].fX;
    169     SkScalar lineDy = pt.fY - fDefer[1].fY;
    170     return deferDx * lineDy != deferDy * lineDx;
    171 }
    172 
    173 void SkPathWriter::moveTo() {
    174     if (!fMoved) {
    175         return;
    176     }
    177     fFirstPt = fDefer[0];
    178 #if DEBUG_PATH_CONSTRUCTION
    179     SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
    180 #endif
    181     fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
    182     fMoved = false;
    183     fMoves++;
    184 }
    185