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 && 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