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 "PathOpsTestCommon.h"
8#include "SkPathOpsBounds.h"
9#include "SkPathOpsCubic.h"
10#include "SkPathOpsLine.h"
11#include "SkPathOpsQuad.h"
12#include "SkPathOpsTriangle.h"
13
14void CubicToQuads(const SkDCubic& cubic, double precision, SkTArray<SkDQuad, true>& quads) {
15    SkTArray<double, true> ts;
16    cubic.toQuadraticTs(precision, &ts);
17    if (ts.count() <= 0) {
18        SkDQuad quad = cubic.toQuad();
19        quads.push_back(quad);
20        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();
27        quads.push_back(quad);
28        tStart = tEnd;
29    }
30}
31
32void 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
120static 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    }
159    return !SkDoubleIsNaN(pt.fY);
160}
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    }
196    return !SkDoubleIsNaN(v.fY);
197}
198