blob: 60a12ee56ec87afcb606e05a6916283502b5e23b [file] [log] [blame]
caryclark@google.com818b0cc2013-04-08 11:50:46 +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 */
7#include "PathOpsTestCommon.h"
caryclark@google.com8d0a5242013-07-16 16:11:16 +00008#include "SkPathOpsBounds.h"
caryclark@google.com818b0cc2013-04-08 11:50:46 +00009#include "SkPathOpsCubic.h"
caryclark@google.com8d0a5242013-07-16 16:11:16 +000010#include "SkPathOpsLine.h"
11#include "SkPathOpsQuad.h"
12#include "SkPathOpsTriangle.h"
caryclark@google.com818b0cc2013-04-08 11:50:46 +000013
caryclark@google.comd892bd82013-06-17 14:10:36 +000014void CubicToQuads(const SkDCubic& cubic, double precision, SkTArray<SkDQuad, true>& quads) {
15 SkTArray<double, true> ts;
caryclark@google.com818b0cc2013-04-08 11:50:46 +000016 cubic.toQuadraticTs(precision, &ts);
caryclark@google.comcffbcc32013-06-04 17:59:42 +000017 if (ts.count() <= 0) {
caryclark@google.com818b0cc2013-04-08 11:50:46 +000018 SkDQuad quad = cubic.toQuad();
caryclark@google.comd892bd82013-06-17 14:10:36 +000019 quads.push_back(quad);
caryclark@google.com818b0cc2013-04-08 11:50:46 +000020 return;
21 }
22 double tStart = 0;
23 for (int i1 = 0; i1 <= ts.count(); ++i1) {
24 const double tEnd = i1 < ts.count() ? ts[i1] : 1;
25 SkDCubic part = cubic.subDivide(tStart, tEnd);
26 SkDQuad quad = part.toQuad();
caryclark@google.comd892bd82013-06-17 14:10:36 +000027 quads.push_back(quad);
caryclark@google.com818b0cc2013-04-08 11:50:46 +000028 tStart = tEnd;
29 }
30}
caryclark@google.com8d0a5242013-07-16 16:11:16 +000031
caryclarke4097e32014-06-18 07:24:19 -070032void CubicPathToQuads(const SkPath& cubicPath, SkPath* quadPath) {
33 quadPath->reset();
34 SkDCubic cubic;
35 SkTArray<SkDQuad, true> quads;
36 SkPath::RawIter iter(cubicPath);
37 uint8_t verb;
38 SkPoint pts[4];
39 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
40 switch (verb) {
41 case SkPath::kMove_Verb:
42 quadPath->moveTo(pts[0].fX, pts[0].fY);
43 continue;
44 case SkPath::kLine_Verb:
45 quadPath->lineTo(pts[1].fX, pts[1].fY);
46 break;
47 case SkPath::kQuad_Verb:
48 quadPath->quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
49 break;
50 case SkPath::kCubic_Verb:
51 quads.reset();
52 cubic.set(pts);
53 CubicToQuads(cubic, cubic.calcPrecision(), quads);
54 for (int index = 0; index < quads.count(); ++index) {
55 SkPoint qPts[2] = {
56 quads[index][1].asSkPoint(),
57 quads[index][2].asSkPoint()
58 };
59 quadPath->quadTo(qPts[0].fX, qPts[0].fY, qPts[1].fX, qPts[1].fY);
60 }
61 break;
62 case SkPath::kClose_Verb:
63 quadPath->close();
64 break;
65 default:
66 SkDEBUGFAIL("bad verb");
67 return;
68 }
69 }
70}
71
72void CubicPathToSimple(const SkPath& cubicPath, SkPath* simplePath) {
73 simplePath->reset();
74 SkDCubic cubic;
75 SkPath::RawIter iter(cubicPath);
76 uint8_t verb;
77 SkPoint pts[4];
78 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
79 switch (verb) {
80 case SkPath::kMove_Verb:
81 simplePath->moveTo(pts[0].fX, pts[0].fY);
82 continue;
83 case SkPath::kLine_Verb:
84 simplePath->lineTo(pts[1].fX, pts[1].fY);
85 break;
86 case SkPath::kQuad_Verb:
87 simplePath->quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
88 break;
89 case SkPath::kCubic_Verb: {
90 cubic.set(pts);
91 double tInflects[2];
92 int inflections = cubic.findInflections(tInflects);
93 if (inflections > 1 && tInflects[0] > tInflects[1]) {
94 SkTSwap(tInflects[0], tInflects[1]);
95 }
96 double lo = 0;
97 for (int index = 0; index <= inflections; ++index) {
98 double hi = index < inflections ? tInflects[index] : 1;
99 SkDCubic part = cubic.subDivide(lo, hi);
100 SkPoint cPts[3];
101 cPts[0] = part[1].asSkPoint();
102 cPts[1] = part[2].asSkPoint();
103 cPts[2] = part[3].asSkPoint();
104 simplePath->cubicTo(cPts[0].fX, cPts[0].fY, cPts[1].fX, cPts[1].fY,
105 cPts[2].fX, cPts[2].fY);
106 lo = hi;
107 }
108 break;
109 }
110 case SkPath::kClose_Verb:
111 simplePath->close();
112 break;
113 default:
114 SkDEBUGFAIL("bad verb");
115 return;
116 }
117 }
118}
119
caryclark@google.com8d0a5242013-07-16 16:11:16 +0000120static bool SkDoubleIsNaN(double x) {
121 return x != x;
122}
123
124bool ValidBounds(const SkPathOpsBounds& bounds) {
125 if (SkScalarIsNaN(bounds.fLeft)) {
126 return false;
127 }
128 if (SkScalarIsNaN(bounds.fTop)) {
129 return false;
130 }
131 if (SkScalarIsNaN(bounds.fRight)) {
132 return false;
133 }
134 return !SkScalarIsNaN(bounds.fBottom);
135}
136
137bool ValidCubic(const SkDCubic& cubic) {
138 for (int index = 0; index < 4; ++index) {
139 if (!ValidPoint(cubic[index])) {
140 return false;
141 }
142 }
143 return true;
144}
145
146bool ValidLine(const SkDLine& line) {
147 for (int index = 0; index < 2; ++index) {
148 if (!ValidPoint(line[index])) {
149 return false;
150 }
151 }
152 return true;
153}
154
155bool ValidPoint(const SkDPoint& pt) {
156 if (SkDoubleIsNaN(pt.fX)) {
157 return false;
158 }
skia.committer@gmail.comeebe6f42013-07-17 07:01:13 +0000159 return !SkDoubleIsNaN(pt.fY);
caryclark@google.com8d0a5242013-07-16 16:11:16 +0000160}
161
162bool ValidPoints(const SkPoint* pts, int count) {
163 for (int index = 0; index < count; ++index) {
164 if (SkScalarIsNaN(pts[index].fX)) {
165 return false;
166 }
167 if (SkScalarIsNaN(pts[index].fY)) {
168 return false;
169 }
170 }
171 return true;
172}
173
174bool ValidQuad(const SkDQuad& quad) {
175 for (int index = 0; index < 3; ++index) {
176 if (!ValidPoint(quad[index])) {
177 return false;
178 }
179 }
180 return true;
181}
182
183bool ValidTriangle(const SkDTriangle& triangle) {
184 for (int index = 0; index < 3; ++index) {
185 if (!ValidPoint(triangle.fPts[index])) {
186 return false;
187 }
188 }
189 return true;
190}
191
192bool ValidVector(const SkDVector& v) {
193 if (SkDoubleIsNaN(v.fX)) {
194 return false;
195 }
skia.committer@gmail.comeebe6f42013-07-17 07:01:13 +0000196 return !SkDoubleIsNaN(v.fY);
caryclark@google.com8d0a5242013-07-16 16:11:16 +0000197}