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::cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
     39     lineTo();
     40     if (fEmpty && AlmostEqualUlps(fDefer[0], pt1) && AlmostEqualUlps(pt1, pt2)
     41             && AlmostEqualUlps(pt2, pt3)) {
     42         deferredLine(pt3);
     43         return;
     44     }
     45     moveTo();
     46     fDefer[1] = pt3;
     47     nudge();
     48     fDefer[0] = fDefer[1];
     49 #if DEBUG_PATH_CONSTRUCTION
     50     SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
     51             pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
     52 #endif
     53     fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY);
     54     fEmpty = false;
     55 }
     56 
     57 void SkPathWriter::deferredLine(const SkPoint& pt) {
     58     if (pt == fDefer[1]) {
     59         return;
     60     }
     61     if (changedSlopes(pt)) {
     62         lineTo();
     63         fDefer[0] = fDefer[1];
     64     }
     65     fDefer[1] = pt;
     66 }
     67 
     68 void SkPathWriter::deferredMove(const SkPoint& pt) {
     69     fMoved = true;
     70     fHasMove = true;
     71     fEmpty = true;
     72     fDefer[0] = fDefer[1] = pt;
     73 }
     74 
     75 void SkPathWriter::deferredMoveLine(const SkPoint& pt) {
     76     if (!fHasMove) {
     77         deferredMove(pt);
     78     }
     79     deferredLine(pt);
     80 }
     81 
     82 bool SkPathWriter::hasMove() const {
     83     return fHasMove;
     84 }
     85 
     86 void SkPathWriter::init() {
     87     fEmpty = true;
     88     fHasMove = false;
     89     fMoved = false;
     90 }
     91 
     92 bool SkPathWriter::isClosed() const {
     93     return !fEmpty && SkDPoint::ApproximatelyEqual(fFirstPt, fDefer[1]);
     94 }
     95 
     96 void SkPathWriter::lineTo() {
     97     if (fDefer[0] == fDefer[1]) {
     98         return;
     99     }
    100     moveTo();
    101     nudge();
    102     fEmpty = false;
    103 #if DEBUG_PATH_CONSTRUCTION
    104     SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY);
    105 #endif
    106     fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY);
    107     fDefer[0] = fDefer[1];
    108 }
    109 
    110 const SkPath* SkPathWriter::nativePath() const {
    111     return fPathPtr;
    112 }
    113 
    114 void SkPathWriter::nudge() {
    115     if (fEmpty || !AlmostEqualUlps(fDefer[1].fX, fFirstPt.fX)
    116             || !AlmostEqualUlps(fDefer[1].fY, fFirstPt.fY)) {
    117         return;
    118     }
    119     fDefer[1] = fFirstPt;
    120 }
    121 
    122 void SkPathWriter::quadTo(const SkPoint& pt1, const SkPoint& pt2) {
    123     lineTo();
    124     if (fEmpty && AlmostEqualUlps(fDefer[0], pt1) && AlmostEqualUlps(pt1, pt2)) {
    125         deferredLine(pt2);
    126         return;
    127     }
    128     moveTo();
    129     fDefer[1] = pt2;
    130     nudge();
    131     fDefer[0] = fDefer[1];
    132 #if DEBUG_PATH_CONSTRUCTION
    133     SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
    134             pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
    135 #endif
    136     fPathPtr->quadTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY);
    137     fEmpty = false;
    138 }
    139 
    140 bool SkPathWriter::someAssemblyRequired() const {
    141     return fCloses < fMoves;
    142 }
    143 
    144 bool SkPathWriter::changedSlopes(const SkPoint& pt) const {
    145     if (fDefer[0] == fDefer[1]) {
    146         return false;
    147     }
    148     SkScalar deferDx = fDefer[1].fX - fDefer[0].fX;
    149     SkScalar deferDy = fDefer[1].fY - fDefer[0].fY;
    150     SkScalar lineDx = pt.fX - fDefer[1].fX;
    151     SkScalar lineDy = pt.fY - fDefer[1].fY;
    152     return deferDx * lineDy != deferDy * lineDx;
    153 }
    154 
    155 void SkPathWriter::moveTo() {
    156     if (!fMoved) {
    157         return;
    158     }
    159     fFirstPt = fDefer[0];
    160 #if DEBUG_PATH_CONSTRUCTION
    161     SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY);
    162 #endif
    163     fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY);
    164     fMoved = false;
    165     fMoves++;
    166 }
    167