blob: 5559026119a39227325176612c7fac45a5337d08 [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +00001/*
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 */
caryclark@google.coma5e55922013-05-07 18:51:31 +00007#include "SkPathOpsPoint.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +00008#include "SkPathWriter.h"
9
10// wrap path to keep track of whether the contour is initialized and non-empty
11SkPathWriter::SkPathWriter(SkPath& path)
12 : fPathPtr(&path)
13 , fCloses(0)
14 , fMoves(0)
15{
16 init();
17}
18
19void 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
38void SkPathWriter::cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) {
39 lineTo();
caryclark@google.coma5e55922013-05-07 18:51:31 +000040 if (fEmpty && AlmostEqualUlps(fDefer[0], pt1) && AlmostEqualUlps(pt1, pt2)
41 && AlmostEqualUlps(pt2, pt3)) {
42 deferredLine(pt3);
43 return;
44 }
caryclark@google.com07393ca2013-04-08 11:47:37 +000045 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
57void 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
68void SkPathWriter::deferredMove(const SkPoint& pt) {
69 fMoved = true;
70 fHasMove = true;
71 fEmpty = true;
72 fDefer[0] = fDefer[1] = pt;
73}
74
75void SkPathWriter::deferredMoveLine(const SkPoint& pt) {
76 if (!fHasMove) {
77 deferredMove(pt);
78 }
79 deferredLine(pt);
80}
81
82bool SkPathWriter::hasMove() const {
83 return fHasMove;
84}
85
86void SkPathWriter::init() {
87 fEmpty = true;
88 fHasMove = false;
89 fMoved = false;
90}
91
92bool SkPathWriter::isClosed() const {
93 return !fEmpty && fFirstPt == fDefer[1];
94}
95
96void 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
110const SkPath* SkPathWriter::nativePath() const {
111 return fPathPtr;
112}
113
114void 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
122void SkPathWriter::quadTo(const SkPoint& pt1, const SkPoint& pt2) {
123 lineTo();
caryclark@google.coma5e55922013-05-07 18:51:31 +0000124 if (fEmpty && AlmostEqualUlps(fDefer[0], pt1) && AlmostEqualUlps(pt1, pt2)) {
125 deferredLine(pt2);
126 return;
127 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000128 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
140bool SkPathWriter::someAssemblyRequired() const {
141 return fCloses < fMoves;
142}
143
144bool 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
155void 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}