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