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