• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #ifndef SkPathOpsCubic_DEFINED
9 #define SkPathOpsCubic_DEFINED
10 
11 #include "include/core/SkPoint.h"
12 #include "include/core/SkScalar.h"
13 #include "include/core/SkTypes.h"
14 #include "include/private/base/SkMalloc.h"
15 #include "include/private/base/SkDebug.h"
16 #include "src/base/SkArenaAlloc.h"
17 #include "src/pathops/SkPathOpsDebug.h"
18 #include "src/pathops/SkPathOpsPoint.h"
19 #include "src/pathops/SkPathOpsTCurve.h"
20 
21 class SkIntersections;
22 class SkOpGlobalState;
23 struct SkDConic;
24 struct SkDCubicPair;
25 struct SkDLine;
26 struct SkDQuad;
27 struct SkDRect;
28 
29 struct SkDCubic {
30     static const int kPointCount = 4;
31     static const int kPointLast = kPointCount - 1;
32     static const int kMaxIntersections = 9;
33 
34     enum SearchAxis {
35         kXAxis,
36         kYAxis
37     };
38 
collapsedSkDCubic39     bool collapsed() const {
40         return fPts[0].approximatelyEqual(fPts[1]) && fPts[0].approximatelyEqual(fPts[2])
41                 && fPts[0].approximatelyEqual(fPts[3]);
42     }
43 
controlsInsideSkDCubic44     bool controlsInside() const {
45         SkDVector v01 = fPts[0] - fPts[1];
46         SkDVector v02 = fPts[0] - fPts[2];
47         SkDVector v03 = fPts[0] - fPts[3];
48         SkDVector v13 = fPts[1] - fPts[3];
49         SkDVector v23 = fPts[2] - fPts[3];
50         return v03.dot(v01) > 0 && v03.dot(v02) > 0 && v03.dot(v13) > 0 && v03.dot(v23) > 0;
51     }
52 
IsConicSkDCubic53     static bool IsConic() { return false; }
54 
55     const SkDPoint& operator[](int n) const { SkASSERT(n >= 0 && n < kPointCount); return fPts[n]; }
56     SkDPoint& operator[](int n) { SkASSERT(n >= 0 && n < kPointCount); return fPts[n]; }
57 
58     void align(int endIndex, int ctrlIndex, SkDPoint* dstPt) const;
59     double binarySearch(double min, double max, double axisIntercept, SearchAxis xAxis) const;
60     double calcPrecision() const;
61     SkDCubicPair chopAt(double t) const;
62     static void Coefficients(const double* cubic, double* A, double* B, double* C, double* D);
63     static int ComplexBreak(const SkPoint pts[4], SkScalar* t);
64     int convexHull(char order[kPointCount]) const;
65 
debugInitSkDCubic66     void debugInit() {
67         sk_bzero(fPts, sizeof(fPts));
68     }
69 
70     void debugSet(const SkDPoint* pts);
71 
72     void dump() const;  // callable from the debugger when the implementation code is linked in
73     void dumpID(int id) const;
74     void dumpInner() const;
75     SkDVector dxdyAtT(double t) const;
76     bool endsAreExtremaInXOrY() const;
77     static int FindExtrema(const double src[], double tValue[2]);
78     int findInflections(double tValues[2]) const;
79 
FindInflectionsSkDCubic80     static int FindInflections(const SkPoint a[kPointCount], double tValues[2]) {
81         SkDCubic cubic;
82         return cubic.set(a).findInflections(tValues);
83     }
84 
85     int findMaxCurvature(double tValues[]) const;
86 
87 #ifdef SK_DEBUG
globalStateSkDCubic88     SkOpGlobalState* globalState() const { return fDebugGlobalState; }
89 #endif
90 
91     bool hullIntersects(const SkDCubic& c2, bool* isLinear) const;
92     bool hullIntersects(const SkDConic& c, bool* isLinear) const;
93     bool hullIntersects(const SkDQuad& c2, bool* isLinear) const;
94     bool hullIntersects(const SkDPoint* pts, int ptCount, bool* isLinear) const;
95     bool isLinear(int startIndex, int endIndex) const;
maxIntersectionsSkDCubic96     static int maxIntersections() { return kMaxIntersections; }
97     bool monotonicInX() const;
98     bool monotonicInY() const;
99     void otherPts(int index, const SkDPoint* o1Pts[kPointCount - 1]) const;
pointCountSkDCubic100     static int pointCount() { return kPointCount; }
pointLastSkDCubic101     static int pointLast() { return kPointLast; }
102     SkDPoint ptAtT(double t) const;
103     static int RootsReal(double A, double B, double C, double D, double t[3]);
104     static int RootsValidT(const double A, const double B, const double C, double D, double s[3]);
105 
106     int searchRoots(double extremes[6], int extrema, double axisIntercept,
107                     SearchAxis xAxis, double* validRoots) const;
108 
109     bool toFloatPoints(SkPoint* ) const;
110     /**
111      *  Return the number of valid roots (0 < root < 1) for this cubic intersecting the
112      *  specified horizontal line.
113      */
114     int horizontalIntersect(double yIntercept, double roots[3]) const;
115     /**
116      *  Return the number of valid roots (0 < root < 1) for this cubic intersecting the
117      *  specified vertical line.
118      */
119     int verticalIntersect(double xIntercept, double roots[3]) const;
120 
121 // add debug only global pointer so asserts can be skipped by fuzzers
setSkDCubic122     const SkDCubic& set(const SkPoint pts[kPointCount]
123             SkDEBUGPARAMS(SkOpGlobalState* state = nullptr)) {
124         fPts[0] = pts[0];
125         fPts[1] = pts[1];
126         fPts[2] = pts[2];
127         fPts[3] = pts[3];
128         SkDEBUGCODE(fDebugGlobalState = state);
129         return *this;
130     }
131 
132     SkDCubic subDivide(double t1, double t2) const;
subDivideSkDCubic133     void subDivide(double t1, double t2, SkDCubic* c) const { *c = this->subDivide(t1, t2); }
134 
SubDivideSkDCubic135     static SkDCubic SubDivide(const SkPoint a[kPointCount], double t1, double t2) {
136         SkDCubic cubic;
137         return cubic.set(a).subDivide(t1, t2);
138     }
139 
140     void subDivide(const SkDPoint& a, const SkDPoint& d, double t1, double t2, SkDPoint p[2]) const;
141 
SubDivideSkDCubic142     static void SubDivide(const SkPoint pts[kPointCount], const SkDPoint& a, const SkDPoint& d, double t1,
143                           double t2, SkDPoint p[2]) {
144         SkDCubic cubic;
145         cubic.set(pts).subDivide(a, d, t1, t2, p);
146     }
147 
148     double top(const SkDCubic& dCurve, double startT, double endT, SkDPoint*topPt) const;
149     SkDQuad toQuad() const;
150 
151     static const int gPrecisionUnit;
152     SkDPoint fPts[kPointCount];
153     SkDEBUGCODE(SkOpGlobalState* fDebugGlobalState);
154 };
155 
156 /* Given the set [0, 1, 2, 3], and two of the four members, compute an XOR mask
157    that computes the other two. Note that:
158 
159    one ^ two == 3 for (0, 3), (1, 2)
160    one ^ two <  3 for (0, 1), (0, 2), (1, 3), (2, 3)
161    3 - (one ^ two) is either 0, 1, or 2
162    1 >> (3 - (one ^ two)) is either 0 or 1
163 thus:
164    returned == 2 for (0, 3), (1, 2)
165    returned == 3 for (0, 1), (0, 2), (1, 3), (2, 3)
166 given that:
167    (0, 3) ^ 2 -> (2, 1)  (1, 2) ^ 2 -> (3, 0)
168    (0, 1) ^ 3 -> (3, 2)  (0, 2) ^ 3 -> (3, 1)  (1, 3) ^ 3 -> (2, 0)  (2, 3) ^ 3 -> (1, 0)
169 */
other_two(int one,int two)170 inline int other_two(int one, int two) {
171     return 1 >> (3 - (one ^ two)) ^ 3;
172 }
173 
174 struct SkDCubicPair {
firstSkDCubicPair175     SkDCubic first() const {
176 #ifdef SK_DEBUG
177         SkDCubic result;
178         result.debugSet(&pts[0]);
179         return result;
180 #else
181         return (const SkDCubic&) pts[0];
182 #endif
183     }
secondSkDCubicPair184     SkDCubic second() const {
185 #ifdef SK_DEBUG
186         SkDCubic result;
187         result.debugSet(&pts[3]);
188         return result;
189 #else
190         return (const SkDCubic&) pts[3];
191 #endif
192     }
193     SkDPoint pts[7];
194 };
195 
196 class SkTCubic : public SkTCurve {
197 public:
198     SkDCubic fCubic;
199 
SkTCubic()200     SkTCubic() {}
201 
SkTCubic(const SkDCubic & c)202     SkTCubic(const SkDCubic& c)
203         : fCubic(c) {
204     }
205 
~SkTCubic()206     ~SkTCubic() override {}
207 
208     const SkDPoint& operator[](int n) const override { return fCubic[n]; }
209     SkDPoint& operator[](int n) override { return fCubic[n]; }
210 
collapsed()211     bool collapsed() const override { return fCubic.collapsed(); }
controlsInside()212     bool controlsInside() const override { return fCubic.controlsInside(); }
debugInit()213     void debugInit() override { return fCubic.debugInit(); }
214 #if DEBUG_T_SECT
dumpID(int id)215     void dumpID(int id) const override { return fCubic.dumpID(id); }
216 #endif
dxdyAtT(double t)217     SkDVector dxdyAtT(double t) const override { return fCubic.dxdyAtT(t); }
218 #ifdef SK_DEBUG
globalState()219     SkOpGlobalState* globalState() const override { return fCubic.globalState(); }
220 #endif
221     bool hullIntersects(const SkDQuad& quad, bool* isLinear) const override;
222     bool hullIntersects(const SkDConic& conic, bool* isLinear) const override;
223 
hullIntersects(const SkDCubic & cubic,bool * isLinear)224     bool hullIntersects(const SkDCubic& cubic, bool* isLinear) const override {
225         return cubic.hullIntersects(fCubic, isLinear);
226     }
227 
hullIntersects(const SkTCurve & curve,bool * isLinear)228     bool hullIntersects(const SkTCurve& curve, bool* isLinear) const override {
229         return curve.hullIntersects(fCubic, isLinear);
230     }
231 
232     int intersectRay(SkIntersections* i, const SkDLine& line) const override;
IsConic()233     bool IsConic() const override { return false; }
make(SkArenaAlloc & heap)234     SkTCurve* make(SkArenaAlloc& heap) const override { return heap.make<SkTCubic>(); }
235 
maxIntersections()236     int maxIntersections() const override { return SkDCubic::kMaxIntersections; }
237 
otherPts(int oddMan,const SkDPoint * endPt[2])238     void otherPts(int oddMan, const SkDPoint* endPt[2]) const override {
239         fCubic.otherPts(oddMan, endPt);
240     }
241 
pointCount()242     int pointCount() const override { return SkDCubic::kPointCount; }
pointLast()243     int pointLast() const override { return SkDCubic::kPointLast; }
ptAtT(double t)244     SkDPoint ptAtT(double t) const override { return fCubic.ptAtT(t); }
245     void setBounds(SkDRect* ) const override;
246 
subDivide(double t1,double t2,SkTCurve * curve)247     void subDivide(double t1, double t2, SkTCurve* curve) const override {
248         ((SkTCubic*) curve)->fCubic = fCubic.subDivide(t1, t2);
249     }
250 };
251 
252 #endif
253