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 #ifndef SkPathOpsCurve_DEFINE
8 #define SkPathOpsCurve_DEFINE
9 
10 #include "SkIntersections.h"
11 
12 #ifndef SK_RELEASE
13 #include "SkPath.h"
14 #endif
15 
16 struct SkPathOpsBounds;
17 
18 struct SkOpCurve {
19     SkPoint fPts[4];
20     SkScalar fWeight;
21     SkDEBUGCODE(SkPath::Verb fVerb);
22 
23     const SkPoint& operator[](int n) const {
24         SkASSERT(n >= 0 && n <= SkPathOpsVerbToPoints(fVerb));
25         return fPts[n];
26     }
27 
28     void dump() const;
29 
setSkOpCurve30     void set(const SkDQuad& quad) {
31         for (int index = 0; index < SkDQuad::kPointCount; ++index) {
32             fPts[index] = quad[index].asSkPoint();
33         }
34         SkDEBUGCODE(fWeight = 1);
35         SkDEBUGCODE(fVerb = SkPath::kQuad_Verb);
36     }
37 
setSkOpCurve38     void set(const SkDCubic& cubic) {
39         for (int index = 0; index < SkDCubic::kPointCount; ++index) {
40             fPts[index] = cubic[index].asSkPoint();
41         }
42         SkDEBUGCODE(fWeight = 1);
43         SkDEBUGCODE(fVerb = SkPath::kCubic_Verb);
44     }
45 
46 };
47 
48 struct SkDCurve {
49     union {
50         SkDLine fLine;
51         SkDQuad fQuad;
52         SkDConic fConic;
53         SkDCubic fCubic;
54     };
55     SkDEBUGCODE(SkPath::Verb fVerb);
56 
57     const SkDPoint& operator[](int n) const {
58         SkASSERT(n >= 0 && n <= SkPathOpsVerbToPoints(fVerb));
59         return fCubic[n];
60     }
61 
62     SkDPoint& operator[](int n) {
63         SkASSERT(n >= 0 && n <= SkPathOpsVerbToPoints(fVerb));
64         return fCubic[n];
65     }
66 
67     SkDPoint conicTop(const SkPoint curve[3], SkScalar curveWeight,
68                       double s, double e, double* topT);
69     SkDPoint cubicTop(const SkPoint curve[4], SkScalar , double s, double e, double* topT);
70     void dumpID(int ) const;
71     SkDPoint lineTop(const SkPoint[2], SkScalar , double , double , double* topT);
72     SkDPoint quadTop(const SkPoint curve[3], SkScalar , double s, double e, double* topT);
73 
74     void setConicBounds(const SkPoint curve[3], SkScalar curveWeight,
75                         double s, double e, SkPathOpsBounds* );
76     void setCubicBounds(const SkPoint curve[4], SkScalar ,
77                         double s, double e, SkPathOpsBounds* );
78     void setQuadBounds(const SkPoint curve[3], SkScalar ,
79                        double s, double e, SkPathOpsBounds*);
80 };
81 
82 
83 extern SkDPoint (SkDCurve::* const Top[])(const SkPoint curve[], SkScalar cWeight,
84     double tStart, double tEnd, double* topT);
85 
dline_xy_at_t(const SkPoint a[2],SkScalar,double t)86 static SkDPoint dline_xy_at_t(const SkPoint a[2], SkScalar , double t) {
87     SkDLine line;
88     line.set(a);
89     return line.ptAtT(t);
90 }
91 
dquad_xy_at_t(const SkPoint a[3],SkScalar,double t)92 static SkDPoint dquad_xy_at_t(const SkPoint a[3], SkScalar , double t) {
93     SkDQuad quad;
94     quad.set(a);
95     return quad.ptAtT(t);
96 }
97 
dconic_xy_at_t(const SkPoint a[3],SkScalar weight,double t)98 static SkDPoint dconic_xy_at_t(const SkPoint a[3], SkScalar weight, double t) {
99     SkDConic conic;
100     conic.set(a, weight);
101     return conic.ptAtT(t);
102 }
103 
dcubic_xy_at_t(const SkPoint a[4],SkScalar,double t)104 static SkDPoint dcubic_xy_at_t(const SkPoint a[4], SkScalar , double t) {
105     SkDCubic cubic;
106     cubic.set(a);
107     return cubic.ptAtT(t);
108 }
109 
110 static SkDPoint (* const CurveDPointAtT[])(const SkPoint[], SkScalar , double ) = {
111     NULL,
112     dline_xy_at_t,
113     dquad_xy_at_t,
114     dconic_xy_at_t,
115     dcubic_xy_at_t
116 };
117 
fline_xy_at_t(const SkPoint a[2],SkScalar weight,double t)118 static SkPoint fline_xy_at_t(const SkPoint a[2], SkScalar weight, double t) {
119     return dline_xy_at_t(a, weight, t).asSkPoint();
120 }
121 
fquad_xy_at_t(const SkPoint a[3],SkScalar weight,double t)122 static SkPoint fquad_xy_at_t(const SkPoint a[3], SkScalar weight, double t) {
123     return dquad_xy_at_t(a, weight, t).asSkPoint();
124 }
125 
fconic_xy_at_t(const SkPoint a[3],SkScalar weight,double t)126 static SkPoint fconic_xy_at_t(const SkPoint a[3], SkScalar weight, double t) {
127     return dconic_xy_at_t(a, weight, t).asSkPoint();
128 }
129 
fcubic_xy_at_t(const SkPoint a[4],SkScalar weight,double t)130 static SkPoint fcubic_xy_at_t(const SkPoint a[4], SkScalar weight, double t) {
131     return dcubic_xy_at_t(a, weight, t).asSkPoint();
132 }
133 
134 static SkPoint (* const CurvePointAtT[])(const SkPoint[], SkScalar , double ) = {
135     NULL,
136     fline_xy_at_t,
137     fquad_xy_at_t,
138     fconic_xy_at_t,
139     fcubic_xy_at_t
140 };
141 
dline_dxdy_at_t(const SkPoint a[2],SkScalar,double)142 static SkDVector dline_dxdy_at_t(const SkPoint a[2], SkScalar , double ) {
143     SkDLine line;
144     line.set(a);
145     return line[1] - line[0];
146 }
147 
dquad_dxdy_at_t(const SkPoint a[3],SkScalar,double t)148 static SkDVector dquad_dxdy_at_t(const SkPoint a[3], SkScalar , double t) {
149     SkDQuad quad;
150     quad.set(a);
151     return quad.dxdyAtT(t);
152 }
153 
dconic_dxdy_at_t(const SkPoint a[3],SkScalar weight,double t)154 static SkDVector dconic_dxdy_at_t(const SkPoint a[3], SkScalar weight, double t) {
155     SkDConic conic;
156     conic.set(a, weight);
157     return conic.dxdyAtT(t);
158 }
159 
dcubic_dxdy_at_t(const SkPoint a[4],SkScalar,double t)160 static SkDVector dcubic_dxdy_at_t(const SkPoint a[4], SkScalar , double t) {
161     SkDCubic cubic;
162     cubic.set(a);
163     return cubic.dxdyAtT(t);
164 }
165 
166 static SkDVector (* const CurveDSlopeAtT[])(const SkPoint[], SkScalar , double ) = {
167     NULL,
168     dline_dxdy_at_t,
169     dquad_dxdy_at_t,
170     dconic_dxdy_at_t,
171     dcubic_dxdy_at_t
172 };
173 
fline_dxdy_at_t(const SkPoint a[2],SkScalar,double)174 static SkVector fline_dxdy_at_t(const SkPoint a[2], SkScalar , double ) {
175     return a[1] - a[0];
176 }
177 
fquad_dxdy_at_t(const SkPoint a[3],SkScalar weight,double t)178 static SkVector fquad_dxdy_at_t(const SkPoint a[3], SkScalar weight, double t) {
179     return dquad_dxdy_at_t(a, weight, t).asSkVector();
180 }
181 
fconic_dxdy_at_t(const SkPoint a[3],SkScalar weight,double t)182 static SkVector fconic_dxdy_at_t(const SkPoint a[3], SkScalar weight, double t) {
183     return dconic_dxdy_at_t(a, weight, t).asSkVector();
184 }
185 
fcubic_dxdy_at_t(const SkPoint a[4],SkScalar weight,double t)186 static SkVector fcubic_dxdy_at_t(const SkPoint a[4], SkScalar weight, double t) {
187     return dcubic_dxdy_at_t(a, weight, t).asSkVector();
188 }
189 
190 static SkVector (* const CurveSlopeAtT[])(const SkPoint[], SkScalar , double ) = {
191     NULL,
192     fline_dxdy_at_t,
193     fquad_dxdy_at_t,
194     fconic_dxdy_at_t,
195     fcubic_dxdy_at_t
196 };
197 
line_is_vertical(const SkPoint a[2],SkScalar,double startT,double endT)198 static bool line_is_vertical(const SkPoint a[2], SkScalar , double startT, double endT) {
199     SkDLine line;
200     line.set(a);
201     SkDPoint dst[2] = { line.ptAtT(startT), line.ptAtT(endT) };
202     return AlmostEqualUlps(dst[0].fX, dst[1].fX);
203 }
204 
quad_is_vertical(const SkPoint a[3],SkScalar,double startT,double endT)205 static bool quad_is_vertical(const SkPoint a[3], SkScalar , double startT, double endT) {
206     SkDQuad quad;
207     quad.set(a);
208     SkDQuad dst = quad.subDivide(startT, endT);
209     return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX);
210 }
211 
conic_is_vertical(const SkPoint a[3],SkScalar weight,double startT,double endT)212 static bool conic_is_vertical(const SkPoint a[3], SkScalar weight, double startT, double endT) {
213     SkDConic conic;
214     conic.set(a, weight);
215     SkDConic dst = conic.subDivide(startT, endT);
216     return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX);
217 }
218 
cubic_is_vertical(const SkPoint a[4],SkScalar,double startT,double endT)219 static bool cubic_is_vertical(const SkPoint a[4], SkScalar , double startT, double endT) {
220     SkDCubic cubic;
221     cubic.set(a);
222     SkDCubic dst = cubic.subDivide(startT, endT);
223     return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX)
224             && AlmostEqualUlps(dst[2].fX, dst[3].fX);
225 }
226 
227 static bool (* const CurveIsVertical[])(const SkPoint[], SkScalar , double , double) = {
228     NULL,
229     line_is_vertical,
230     quad_is_vertical,
231     conic_is_vertical,
232     cubic_is_vertical
233 };
234 
line_intersect_ray(const SkPoint a[2],SkScalar,const SkDLine & ray,SkIntersections * i)235 static void line_intersect_ray(const SkPoint a[2], SkScalar , const SkDLine& ray,
236         SkIntersections* i) {
237     SkDLine line;
238     line.set(a);
239     i->intersectRay(line, ray);
240 }
241 
quad_intersect_ray(const SkPoint a[3],SkScalar,const SkDLine & ray,SkIntersections * i)242 static void quad_intersect_ray(const SkPoint a[3], SkScalar , const SkDLine& ray,
243         SkIntersections* i) {
244     SkDQuad quad;
245     quad.set(a);
246     i->intersectRay(quad, ray);
247 }
248 
conic_intersect_ray(const SkPoint a[3],SkScalar weight,const SkDLine & ray,SkIntersections * i)249 static void conic_intersect_ray(const SkPoint a[3], SkScalar weight, const SkDLine& ray,
250         SkIntersections* i) {
251     SkDConic conic;
252     conic.set(a, weight);
253     i->intersectRay(conic, ray);
254 }
255 
cubic_intersect_ray(const SkPoint a[4],SkScalar,const SkDLine & ray,SkIntersections * i)256 static void cubic_intersect_ray(const SkPoint a[4], SkScalar , const SkDLine& ray,
257         SkIntersections* i) {
258     SkDCubic cubic;
259     cubic.set(a);
260     i->intersectRay(cubic, ray);
261 }
262 
263 static void (* const CurveIntersectRay[])(const SkPoint[] , SkScalar , const SkDLine& ,
264         SkIntersections* ) = {
265     NULL,
266     line_intersect_ray,
267     quad_intersect_ray,
268     conic_intersect_ray,
269     cubic_intersect_ray
270 };
271 
line_intercept_h(const SkPoint a[2],SkScalar,SkScalar y,double * roots)272 static int line_intercept_h(const SkPoint a[2], SkScalar , SkScalar y, double* roots) {
273     SkDLine line;
274     roots[0] = SkIntersections::HorizontalIntercept(line.set(a), y);
275     return between(0, roots[0], 1);
276 }
277 
line_intercept_v(const SkPoint a[2],SkScalar,SkScalar x,double * roots)278 static int line_intercept_v(const SkPoint a[2], SkScalar , SkScalar x, double* roots) {
279     SkDLine line;
280     roots[0] = SkIntersections::VerticalIntercept(line.set(a), x);
281     return between(0, roots[0], 1);
282 }
283 
quad_intercept_h(const SkPoint a[2],SkScalar,SkScalar y,double * roots)284 static int quad_intercept_h(const SkPoint a[2], SkScalar , SkScalar y, double* roots) {
285     SkDQuad quad;
286     return SkIntersections::HorizontalIntercept(quad.set(a), y, roots);
287 }
288 
quad_intercept_v(const SkPoint a[2],SkScalar,SkScalar x,double * roots)289 static int quad_intercept_v(const SkPoint a[2], SkScalar , SkScalar x, double* roots) {
290     SkDQuad quad;
291     return SkIntersections::VerticalIntercept(quad.set(a), x, roots);
292 }
293 
conic_intercept_h(const SkPoint a[2],SkScalar w,SkScalar y,double * roots)294 static int conic_intercept_h(const SkPoint a[2], SkScalar w, SkScalar y, double* roots) {
295     SkDConic conic;
296     return SkIntersections::HorizontalIntercept(conic.set(a, w), y, roots);
297 }
298 
conic_intercept_v(const SkPoint a[2],SkScalar w,SkScalar x,double * roots)299 static int conic_intercept_v(const SkPoint a[2], SkScalar w, SkScalar x, double* roots) {
300     SkDConic conic;
301     return SkIntersections::VerticalIntercept(conic.set(a, w), x, roots);
302 }
303 
cubic_intercept_h(const SkPoint a[3],SkScalar,SkScalar y,double * roots)304 static int cubic_intercept_h(const SkPoint a[3], SkScalar , SkScalar y, double* roots) {
305     SkDCubic cubic;
306     return cubic.set(a).horizontalIntersect(y, roots);
307 }
308 
cubic_intercept_v(const SkPoint a[3],SkScalar,SkScalar x,double * roots)309 static int cubic_intercept_v(const SkPoint a[3], SkScalar , SkScalar x, double* roots) {
310     SkDCubic cubic;
311     return cubic.set(a).verticalIntersect(x, roots);
312 }
313 
314 static int (* const CurveIntercept[])(const SkPoint[] , SkScalar , SkScalar , double* ) = {
315     NULL,
316     NULL,
317     line_intercept_h,
318     line_intercept_v,
319     quad_intercept_h,
320     quad_intercept_v,
321     conic_intercept_h,
322     conic_intercept_v,
323     cubic_intercept_h,
324     cubic_intercept_v,
325 };
326 
327 #endif
328