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
SkPathWriter(SkPath & path)11 SkPathWriter::SkPathWriter(SkPath& path)
12 : fPathPtr(&path)
13 , fCloses(0)
14 , fMoves(0)
15 {
16 init();
17 }
18
close()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
cubicTo(const SkPoint & pt1,const SkPoint & pt2,const SkPoint & pt3)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
deferredLine(const SkPoint & pt)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
deferredMove(const SkPoint & pt)68 void SkPathWriter::deferredMove(const SkPoint& pt) {
69 fMoved = true;
70 fHasMove = true;
71 fEmpty = true;
72 fDefer[0] = fDefer[1] = pt;
73 }
74
deferredMoveLine(const SkPoint & pt)75 void SkPathWriter::deferredMoveLine(const SkPoint& pt) {
76 if (!fHasMove) {
77 deferredMove(pt);
78 }
79 deferredLine(pt);
80 }
81
hasMove() const82 bool SkPathWriter::hasMove() const {
83 return fHasMove;
84 }
85
init()86 void SkPathWriter::init() {
87 fEmpty = true;
88 fHasMove = false;
89 fMoved = false;
90 }
91
isClosed() const92 bool SkPathWriter::isClosed() const {
93 return !fEmpty && SkDPoint::ApproximatelyEqual(fFirstPt, fDefer[1]);
94 }
95
lineTo()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
nativePath() const110 const SkPath* SkPathWriter::nativePath() const {
111 return fPathPtr;
112 }
113
nudge()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
quadTo(const SkPoint & pt1,const SkPoint & pt2)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
someAssemblyRequired() const140 bool SkPathWriter::someAssemblyRequired() const {
141 return fCloses < fMoves;
142 }
143
changedSlopes(const SkPoint & pt) const144 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
moveTo()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