xref: /aosp_15_r20/external/skia/src/pathops/SkReduceOrder.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2012 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkReduceOrder.h"
8*c8dee2aaSAndroid Build Coastguard Worker 
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkGeometry.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsPoint.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsTypes.h"
13*c8dee2aaSAndroid Build Coastguard Worker 
14*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
15*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
16*c8dee2aaSAndroid Build Coastguard Worker 
reduce(const SkDLine & line)17*c8dee2aaSAndroid Build Coastguard Worker int SkReduceOrder::reduce(const SkDLine& line) {
18*c8dee2aaSAndroid Build Coastguard Worker     fLine[0] = line[0];
19*c8dee2aaSAndroid Build Coastguard Worker     int different = line[0] != line[1];
20*c8dee2aaSAndroid Build Coastguard Worker     fLine[1] = line[different];
21*c8dee2aaSAndroid Build Coastguard Worker     return 1 + different;
22*c8dee2aaSAndroid Build Coastguard Worker }
23*c8dee2aaSAndroid Build Coastguard Worker 
coincident_line(const SkDQuad & quad,SkDQuad & reduction)24*c8dee2aaSAndroid Build Coastguard Worker static int coincident_line(const SkDQuad& quad, SkDQuad& reduction) {
25*c8dee2aaSAndroid Build Coastguard Worker     reduction[0] = reduction[1] = quad[0];
26*c8dee2aaSAndroid Build Coastguard Worker     return 1;
27*c8dee2aaSAndroid Build Coastguard Worker }
28*c8dee2aaSAndroid Build Coastguard Worker 
reductionLineCount(const SkDQuad & reduction)29*c8dee2aaSAndroid Build Coastguard Worker static int reductionLineCount(const SkDQuad& reduction) {
30*c8dee2aaSAndroid Build Coastguard Worker     return 1 + !reduction[0].approximatelyEqual(reduction[1]);
31*c8dee2aaSAndroid Build Coastguard Worker }
32*c8dee2aaSAndroid Build Coastguard Worker 
vertical_line(const SkDQuad & quad,SkDQuad & reduction)33*c8dee2aaSAndroid Build Coastguard Worker static int vertical_line(const SkDQuad& quad, SkDQuad& reduction) {
34*c8dee2aaSAndroid Build Coastguard Worker     reduction[0] = quad[0];
35*c8dee2aaSAndroid Build Coastguard Worker     reduction[1] = quad[2];
36*c8dee2aaSAndroid Build Coastguard Worker     return reductionLineCount(reduction);
37*c8dee2aaSAndroid Build Coastguard Worker }
38*c8dee2aaSAndroid Build Coastguard Worker 
horizontal_line(const SkDQuad & quad,SkDQuad & reduction)39*c8dee2aaSAndroid Build Coastguard Worker static int horizontal_line(const SkDQuad& quad, SkDQuad& reduction) {
40*c8dee2aaSAndroid Build Coastguard Worker     reduction[0] = quad[0];
41*c8dee2aaSAndroid Build Coastguard Worker     reduction[1] = quad[2];
42*c8dee2aaSAndroid Build Coastguard Worker     return reductionLineCount(reduction);
43*c8dee2aaSAndroid Build Coastguard Worker }
44*c8dee2aaSAndroid Build Coastguard Worker 
check_linear(const SkDQuad & quad,int minX,int maxX,int minY,int maxY,SkDQuad & reduction)45*c8dee2aaSAndroid Build Coastguard Worker static int check_linear(const SkDQuad& quad,
46*c8dee2aaSAndroid Build Coastguard Worker         int minX, int maxX, int minY, int maxY, SkDQuad& reduction) {
47*c8dee2aaSAndroid Build Coastguard Worker     if (!quad.isLinear(0, 2)) {
48*c8dee2aaSAndroid Build Coastguard Worker         return 0;
49*c8dee2aaSAndroid Build Coastguard Worker     }
50*c8dee2aaSAndroid Build Coastguard Worker     // four are colinear: return line formed by outside
51*c8dee2aaSAndroid Build Coastguard Worker     reduction[0] = quad[0];
52*c8dee2aaSAndroid Build Coastguard Worker     reduction[1] = quad[2];
53*c8dee2aaSAndroid Build Coastguard Worker     return reductionLineCount(reduction);
54*c8dee2aaSAndroid Build Coastguard Worker }
55*c8dee2aaSAndroid Build Coastguard Worker 
56*c8dee2aaSAndroid Build Coastguard Worker // reduce to a quadratic or smaller
57*c8dee2aaSAndroid Build Coastguard Worker // look for identical points
58*c8dee2aaSAndroid Build Coastguard Worker // look for all four points in a line
59*c8dee2aaSAndroid Build Coastguard Worker     // note that three points in a line doesn't simplify a cubic
60*c8dee2aaSAndroid Build Coastguard Worker // look for approximation with single quadratic
61*c8dee2aaSAndroid Build Coastguard Worker     // save approximation with multiple quadratics for later
reduce(const SkDQuad & quad)62*c8dee2aaSAndroid Build Coastguard Worker int SkReduceOrder::reduce(const SkDQuad& quad) {
63*c8dee2aaSAndroid Build Coastguard Worker     int index, minX, maxX, minY, maxY;
64*c8dee2aaSAndroid Build Coastguard Worker     int minXSet, minYSet;
65*c8dee2aaSAndroid Build Coastguard Worker     minX = maxX = minY = maxY = 0;
66*c8dee2aaSAndroid Build Coastguard Worker     minXSet = minYSet = 0;
67*c8dee2aaSAndroid Build Coastguard Worker     for (index = 1; index < 3; ++index) {
68*c8dee2aaSAndroid Build Coastguard Worker         if (quad[minX].fX > quad[index].fX) {
69*c8dee2aaSAndroid Build Coastguard Worker             minX = index;
70*c8dee2aaSAndroid Build Coastguard Worker         }
71*c8dee2aaSAndroid Build Coastguard Worker         if (quad[minY].fY > quad[index].fY) {
72*c8dee2aaSAndroid Build Coastguard Worker             minY = index;
73*c8dee2aaSAndroid Build Coastguard Worker         }
74*c8dee2aaSAndroid Build Coastguard Worker         if (quad[maxX].fX < quad[index].fX) {
75*c8dee2aaSAndroid Build Coastguard Worker             maxX = index;
76*c8dee2aaSAndroid Build Coastguard Worker         }
77*c8dee2aaSAndroid Build Coastguard Worker         if (quad[maxY].fY < quad[index].fY) {
78*c8dee2aaSAndroid Build Coastguard Worker             maxY = index;
79*c8dee2aaSAndroid Build Coastguard Worker         }
80*c8dee2aaSAndroid Build Coastguard Worker     }
81*c8dee2aaSAndroid Build Coastguard Worker     for (index = 0; index < 3; ++index) {
82*c8dee2aaSAndroid Build Coastguard Worker         if (AlmostEqualUlps(quad[index].fX, quad[minX].fX)) {
83*c8dee2aaSAndroid Build Coastguard Worker             minXSet |= 1 << index;
84*c8dee2aaSAndroid Build Coastguard Worker         }
85*c8dee2aaSAndroid Build Coastguard Worker         if (AlmostEqualUlps(quad[index].fY, quad[minY].fY)) {
86*c8dee2aaSAndroid Build Coastguard Worker             minYSet |= 1 << index;
87*c8dee2aaSAndroid Build Coastguard Worker         }
88*c8dee2aaSAndroid Build Coastguard Worker     }
89*c8dee2aaSAndroid Build Coastguard Worker     if ((minXSet & 0x05) == 0x5 && (minYSet & 0x05) == 0x5) { // test for degenerate
90*c8dee2aaSAndroid Build Coastguard Worker         // this quad starts and ends at the same place, so never contributes
91*c8dee2aaSAndroid Build Coastguard Worker         // to the fill
92*c8dee2aaSAndroid Build Coastguard Worker         return coincident_line(quad, fQuad);
93*c8dee2aaSAndroid Build Coastguard Worker     }
94*c8dee2aaSAndroid Build Coastguard Worker     if (minXSet == 0x7) {  // test for vertical line
95*c8dee2aaSAndroid Build Coastguard Worker         return vertical_line(quad, fQuad);
96*c8dee2aaSAndroid Build Coastguard Worker     }
97*c8dee2aaSAndroid Build Coastguard Worker     if (minYSet == 0x7) {  // test for horizontal line
98*c8dee2aaSAndroid Build Coastguard Worker         return horizontal_line(quad, fQuad);
99*c8dee2aaSAndroid Build Coastguard Worker     }
100*c8dee2aaSAndroid Build Coastguard Worker     int result = check_linear(quad, minX, maxX, minY, maxY, fQuad);
101*c8dee2aaSAndroid Build Coastguard Worker     if (result) {
102*c8dee2aaSAndroid Build Coastguard Worker         return result;
103*c8dee2aaSAndroid Build Coastguard Worker     }
104*c8dee2aaSAndroid Build Coastguard Worker     fQuad = quad;
105*c8dee2aaSAndroid Build Coastguard Worker     return 3;
106*c8dee2aaSAndroid Build Coastguard Worker }
107*c8dee2aaSAndroid Build Coastguard Worker 
108*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////////
109*c8dee2aaSAndroid Build Coastguard Worker 
coincident_line(const SkDCubic & cubic,SkDCubic & reduction)110*c8dee2aaSAndroid Build Coastguard Worker static int coincident_line(const SkDCubic& cubic, SkDCubic& reduction) {
111*c8dee2aaSAndroid Build Coastguard Worker     reduction[0] = reduction[1] = cubic[0];
112*c8dee2aaSAndroid Build Coastguard Worker     return 1;
113*c8dee2aaSAndroid Build Coastguard Worker }
114*c8dee2aaSAndroid Build Coastguard Worker 
reductionLineCount(const SkDCubic & reduction)115*c8dee2aaSAndroid Build Coastguard Worker static int reductionLineCount(const SkDCubic& reduction) {
116*c8dee2aaSAndroid Build Coastguard Worker     return 1 + !reduction[0].approximatelyEqual(reduction[1]);
117*c8dee2aaSAndroid Build Coastguard Worker }
118*c8dee2aaSAndroid Build Coastguard Worker 
vertical_line(const SkDCubic & cubic,SkDCubic & reduction)119*c8dee2aaSAndroid Build Coastguard Worker static int vertical_line(const SkDCubic& cubic, SkDCubic& reduction) {
120*c8dee2aaSAndroid Build Coastguard Worker     reduction[0] = cubic[0];
121*c8dee2aaSAndroid Build Coastguard Worker     reduction[1] = cubic[3];
122*c8dee2aaSAndroid Build Coastguard Worker     return reductionLineCount(reduction);
123*c8dee2aaSAndroid Build Coastguard Worker }
124*c8dee2aaSAndroid Build Coastguard Worker 
horizontal_line(const SkDCubic & cubic,SkDCubic & reduction)125*c8dee2aaSAndroid Build Coastguard Worker static int horizontal_line(const SkDCubic& cubic, SkDCubic& reduction) {
126*c8dee2aaSAndroid Build Coastguard Worker     reduction[0] = cubic[0];
127*c8dee2aaSAndroid Build Coastguard Worker     reduction[1] = cubic[3];
128*c8dee2aaSAndroid Build Coastguard Worker     return reductionLineCount(reduction);
129*c8dee2aaSAndroid Build Coastguard Worker }
130*c8dee2aaSAndroid Build Coastguard Worker 
131*c8dee2aaSAndroid Build Coastguard Worker // check to see if it is a quadratic or a line
check_quadratic(const SkDCubic & cubic,SkDCubic & reduction)132*c8dee2aaSAndroid Build Coastguard Worker static int check_quadratic(const SkDCubic& cubic, SkDCubic& reduction) {
133*c8dee2aaSAndroid Build Coastguard Worker     double dx10 = cubic[1].fX - cubic[0].fX;
134*c8dee2aaSAndroid Build Coastguard Worker     double dx23 = cubic[2].fX - cubic[3].fX;
135*c8dee2aaSAndroid Build Coastguard Worker     double midX = cubic[0].fX + dx10 * 3 / 2;
136*c8dee2aaSAndroid Build Coastguard Worker     double sideAx = midX - cubic[3].fX;
137*c8dee2aaSAndroid Build Coastguard Worker     double sideBx = dx23 * 3 / 2;
138*c8dee2aaSAndroid Build Coastguard Worker     if (approximately_zero(sideAx) ? !approximately_equal(sideAx, sideBx)
139*c8dee2aaSAndroid Build Coastguard Worker             : !AlmostEqualUlps_Pin(sideAx, sideBx)) {
140*c8dee2aaSAndroid Build Coastguard Worker         return 0;
141*c8dee2aaSAndroid Build Coastguard Worker     }
142*c8dee2aaSAndroid Build Coastguard Worker     double dy10 = cubic[1].fY - cubic[0].fY;
143*c8dee2aaSAndroid Build Coastguard Worker     double dy23 = cubic[2].fY - cubic[3].fY;
144*c8dee2aaSAndroid Build Coastguard Worker     double midY = cubic[0].fY + dy10 * 3 / 2;
145*c8dee2aaSAndroid Build Coastguard Worker     double sideAy = midY - cubic[3].fY;
146*c8dee2aaSAndroid Build Coastguard Worker     double sideBy = dy23 * 3 / 2;
147*c8dee2aaSAndroid Build Coastguard Worker     if (approximately_zero(sideAy) ? !approximately_equal(sideAy, sideBy)
148*c8dee2aaSAndroid Build Coastguard Worker             : !AlmostEqualUlps_Pin(sideAy, sideBy)) {
149*c8dee2aaSAndroid Build Coastguard Worker         return 0;
150*c8dee2aaSAndroid Build Coastguard Worker     }
151*c8dee2aaSAndroid Build Coastguard Worker     reduction[0] = cubic[0];
152*c8dee2aaSAndroid Build Coastguard Worker     reduction[1].fX = midX;
153*c8dee2aaSAndroid Build Coastguard Worker     reduction[1].fY = midY;
154*c8dee2aaSAndroid Build Coastguard Worker     reduction[2] = cubic[3];
155*c8dee2aaSAndroid Build Coastguard Worker     return 3;
156*c8dee2aaSAndroid Build Coastguard Worker }
157*c8dee2aaSAndroid Build Coastguard Worker 
check_linear(const SkDCubic & cubic,int minX,int maxX,int minY,int maxY,SkDCubic & reduction)158*c8dee2aaSAndroid Build Coastguard Worker static int check_linear(const SkDCubic& cubic,
159*c8dee2aaSAndroid Build Coastguard Worker         int minX, int maxX, int minY, int maxY, SkDCubic& reduction) {
160*c8dee2aaSAndroid Build Coastguard Worker     if (!cubic.isLinear(0, 3)) {
161*c8dee2aaSAndroid Build Coastguard Worker         return 0;
162*c8dee2aaSAndroid Build Coastguard Worker     }
163*c8dee2aaSAndroid Build Coastguard Worker     // four are colinear: return line formed by outside
164*c8dee2aaSAndroid Build Coastguard Worker     reduction[0] = cubic[0];
165*c8dee2aaSAndroid Build Coastguard Worker     reduction[1] = cubic[3];
166*c8dee2aaSAndroid Build Coastguard Worker     return reductionLineCount(reduction);
167*c8dee2aaSAndroid Build Coastguard Worker }
168*c8dee2aaSAndroid Build Coastguard Worker 
169*c8dee2aaSAndroid Build Coastguard Worker /* food for thought:
170*c8dee2aaSAndroid Build Coastguard Worker http://objectmix.com/graphics/132906-fast-precision-driven-cubic-quadratic-piecewise-degree-reduction-algos-2-a.html
171*c8dee2aaSAndroid Build Coastguard Worker 
172*c8dee2aaSAndroid Build Coastguard Worker Given points c1, c2, c3 and c4 of a cubic Bezier, the points of the
173*c8dee2aaSAndroid Build Coastguard Worker corresponding quadratic Bezier are (given in convex combinations of
174*c8dee2aaSAndroid Build Coastguard Worker points):
175*c8dee2aaSAndroid Build Coastguard Worker 
176*c8dee2aaSAndroid Build Coastguard Worker q1 = (11/13)c1 + (3/13)c2 -(3/13)c3 + (2/13)c4
177*c8dee2aaSAndroid Build Coastguard Worker q2 = -c1 + (3/2)c2 + (3/2)c3 - c4
178*c8dee2aaSAndroid Build Coastguard Worker q3 = (2/13)c1 - (3/13)c2 + (3/13)c3 + (11/13)c4
179*c8dee2aaSAndroid Build Coastguard Worker 
180*c8dee2aaSAndroid Build Coastguard Worker Of course, this curve does not interpolate the end-points, but it would
181*c8dee2aaSAndroid Build Coastguard Worker be interesting to see the behaviour of such a curve in an applet.
182*c8dee2aaSAndroid Build Coastguard Worker 
183*c8dee2aaSAndroid Build Coastguard Worker --
184*c8dee2aaSAndroid Build Coastguard Worker Kalle Rutanen
185*c8dee2aaSAndroid Build Coastguard Worker http://kaba.hilvi.org
186*c8dee2aaSAndroid Build Coastguard Worker 
187*c8dee2aaSAndroid Build Coastguard Worker */
188*c8dee2aaSAndroid Build Coastguard Worker 
189*c8dee2aaSAndroid Build Coastguard Worker // reduce to a quadratic or smaller
190*c8dee2aaSAndroid Build Coastguard Worker // look for identical points
191*c8dee2aaSAndroid Build Coastguard Worker // look for all four points in a line
192*c8dee2aaSAndroid Build Coastguard Worker     // note that three points in a line doesn't simplify a cubic
193*c8dee2aaSAndroid Build Coastguard Worker // look for approximation with single quadratic
194*c8dee2aaSAndroid Build Coastguard Worker     // save approximation with multiple quadratics for later
reduce(const SkDCubic & cubic,Quadratics allowQuadratics)195*c8dee2aaSAndroid Build Coastguard Worker int SkReduceOrder::reduce(const SkDCubic& cubic, Quadratics allowQuadratics) {
196*c8dee2aaSAndroid Build Coastguard Worker     int index, minX, maxX, minY, maxY;
197*c8dee2aaSAndroid Build Coastguard Worker     int minXSet, minYSet;
198*c8dee2aaSAndroid Build Coastguard Worker     minX = maxX = minY = maxY = 0;
199*c8dee2aaSAndroid Build Coastguard Worker     minXSet = minYSet = 0;
200*c8dee2aaSAndroid Build Coastguard Worker     for (index = 1; index < 4; ++index) {
201*c8dee2aaSAndroid Build Coastguard Worker         if (cubic[minX].fX > cubic[index].fX) {
202*c8dee2aaSAndroid Build Coastguard Worker             minX = index;
203*c8dee2aaSAndroid Build Coastguard Worker         }
204*c8dee2aaSAndroid Build Coastguard Worker         if (cubic[minY].fY > cubic[index].fY) {
205*c8dee2aaSAndroid Build Coastguard Worker             minY = index;
206*c8dee2aaSAndroid Build Coastguard Worker         }
207*c8dee2aaSAndroid Build Coastguard Worker         if (cubic[maxX].fX < cubic[index].fX) {
208*c8dee2aaSAndroid Build Coastguard Worker             maxX = index;
209*c8dee2aaSAndroid Build Coastguard Worker         }
210*c8dee2aaSAndroid Build Coastguard Worker         if (cubic[maxY].fY < cubic[index].fY) {
211*c8dee2aaSAndroid Build Coastguard Worker             maxY = index;
212*c8dee2aaSAndroid Build Coastguard Worker         }
213*c8dee2aaSAndroid Build Coastguard Worker     }
214*c8dee2aaSAndroid Build Coastguard Worker     for (index = 0; index < 4; ++index) {
215*c8dee2aaSAndroid Build Coastguard Worker         double cx = cubic[index].fX;
216*c8dee2aaSAndroid Build Coastguard Worker         double cy = cubic[index].fY;
217*c8dee2aaSAndroid Build Coastguard Worker         double denom = std::max(fabs(cx), std::max(fabs(cy),
218*c8dee2aaSAndroid Build Coastguard Worker                 std::max(fabs(cubic[minX].fX), fabs(cubic[minY].fY))));
219*c8dee2aaSAndroid Build Coastguard Worker         if (denom == 0) {
220*c8dee2aaSAndroid Build Coastguard Worker             minXSet |= 1 << index;
221*c8dee2aaSAndroid Build Coastguard Worker             minYSet |= 1 << index;
222*c8dee2aaSAndroid Build Coastguard Worker             continue;
223*c8dee2aaSAndroid Build Coastguard Worker         }
224*c8dee2aaSAndroid Build Coastguard Worker         double inv = 1 / denom;
225*c8dee2aaSAndroid Build Coastguard Worker         if (approximately_equal_half(cx * inv, cubic[minX].fX * inv)) {
226*c8dee2aaSAndroid Build Coastguard Worker             minXSet |= 1 << index;
227*c8dee2aaSAndroid Build Coastguard Worker         }
228*c8dee2aaSAndroid Build Coastguard Worker         if (approximately_equal_half(cy * inv, cubic[minY].fY * inv)) {
229*c8dee2aaSAndroid Build Coastguard Worker             minYSet |= 1 << index;
230*c8dee2aaSAndroid Build Coastguard Worker         }
231*c8dee2aaSAndroid Build Coastguard Worker     }
232*c8dee2aaSAndroid Build Coastguard Worker     if (minXSet == 0xF) {  // test for vertical line
233*c8dee2aaSAndroid Build Coastguard Worker         if (minYSet == 0xF) {  // return 1 if all four are coincident
234*c8dee2aaSAndroid Build Coastguard Worker             return coincident_line(cubic, fCubic);
235*c8dee2aaSAndroid Build Coastguard Worker         }
236*c8dee2aaSAndroid Build Coastguard Worker         return vertical_line(cubic, fCubic);
237*c8dee2aaSAndroid Build Coastguard Worker     }
238*c8dee2aaSAndroid Build Coastguard Worker     if (minYSet == 0xF) {  // test for horizontal line
239*c8dee2aaSAndroid Build Coastguard Worker         return horizontal_line(cubic, fCubic);
240*c8dee2aaSAndroid Build Coastguard Worker     }
241*c8dee2aaSAndroid Build Coastguard Worker     int result = check_linear(cubic, minX, maxX, minY, maxY, fCubic);
242*c8dee2aaSAndroid Build Coastguard Worker     if (result) {
243*c8dee2aaSAndroid Build Coastguard Worker         return result;
244*c8dee2aaSAndroid Build Coastguard Worker     }
245*c8dee2aaSAndroid Build Coastguard Worker     if (allowQuadratics == SkReduceOrder::kAllow_Quadratics
246*c8dee2aaSAndroid Build Coastguard Worker             && (result = check_quadratic(cubic, fCubic))) {
247*c8dee2aaSAndroid Build Coastguard Worker         return result;
248*c8dee2aaSAndroid Build Coastguard Worker     }
249*c8dee2aaSAndroid Build Coastguard Worker     fCubic = cubic;
250*c8dee2aaSAndroid Build Coastguard Worker     return 4;
251*c8dee2aaSAndroid Build Coastguard Worker }
252*c8dee2aaSAndroid Build Coastguard Worker 
Quad(const SkPoint a[3],SkPoint * reducePts)253*c8dee2aaSAndroid Build Coastguard Worker SkPath::Verb SkReduceOrder::Quad(const SkPoint a[3], SkPoint* reducePts) {
254*c8dee2aaSAndroid Build Coastguard Worker     SkDQuad quad;
255*c8dee2aaSAndroid Build Coastguard Worker     quad.set(a);
256*c8dee2aaSAndroid Build Coastguard Worker     SkReduceOrder reducer;
257*c8dee2aaSAndroid Build Coastguard Worker     int order = reducer.reduce(quad);
258*c8dee2aaSAndroid Build Coastguard Worker     if (order == 2) {  // quad became line
259*c8dee2aaSAndroid Build Coastguard Worker         for (int index = 0; index < order; ++index) {
260*c8dee2aaSAndroid Build Coastguard Worker             *reducePts++ = reducer.fLine[index].asSkPoint();
261*c8dee2aaSAndroid Build Coastguard Worker         }
262*c8dee2aaSAndroid Build Coastguard Worker     }
263*c8dee2aaSAndroid Build Coastguard Worker     return SkPathOpsPointsToVerb(order - 1);
264*c8dee2aaSAndroid Build Coastguard Worker }
265*c8dee2aaSAndroid Build Coastguard Worker 
Conic(const SkConic & c,SkPoint * reducePts)266*c8dee2aaSAndroid Build Coastguard Worker SkPath::Verb SkReduceOrder::Conic(const SkConic& c, SkPoint* reducePts) {
267*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Verb verb = SkReduceOrder::Quad(c.fPts, reducePts);
268*c8dee2aaSAndroid Build Coastguard Worker     if (verb > SkPath::kLine_Verb && c.fW == 1) {
269*c8dee2aaSAndroid Build Coastguard Worker         return SkPath::kQuad_Verb;
270*c8dee2aaSAndroid Build Coastguard Worker     }
271*c8dee2aaSAndroid Build Coastguard Worker     return verb == SkPath::kQuad_Verb ? SkPath::kConic_Verb : verb;
272*c8dee2aaSAndroid Build Coastguard Worker }
273*c8dee2aaSAndroid Build Coastguard Worker 
Cubic(const SkPoint a[4],SkPoint * reducePts)274*c8dee2aaSAndroid Build Coastguard Worker SkPath::Verb SkReduceOrder::Cubic(const SkPoint a[4], SkPoint* reducePts) {
275*c8dee2aaSAndroid Build Coastguard Worker     if (SkDPoint::ApproximatelyEqual(a[0], a[1]) && SkDPoint::ApproximatelyEqual(a[0], a[2])
276*c8dee2aaSAndroid Build Coastguard Worker             && SkDPoint::ApproximatelyEqual(a[0], a[3])) {
277*c8dee2aaSAndroid Build Coastguard Worker         reducePts[0] = a[0];
278*c8dee2aaSAndroid Build Coastguard Worker         return SkPath::kMove_Verb;
279*c8dee2aaSAndroid Build Coastguard Worker     }
280*c8dee2aaSAndroid Build Coastguard Worker     SkDCubic cubic;
281*c8dee2aaSAndroid Build Coastguard Worker     cubic.set(a);
282*c8dee2aaSAndroid Build Coastguard Worker     SkReduceOrder reducer;
283*c8dee2aaSAndroid Build Coastguard Worker     int order = reducer.reduce(cubic, kAllow_Quadratics);
284*c8dee2aaSAndroid Build Coastguard Worker     if (order == 2 || order == 3) {  // cubic became line or quad
285*c8dee2aaSAndroid Build Coastguard Worker         for (int index = 0; index < order; ++index) {
286*c8dee2aaSAndroid Build Coastguard Worker             *reducePts++ = reducer.fQuad[index].asSkPoint();
287*c8dee2aaSAndroid Build Coastguard Worker         }
288*c8dee2aaSAndroid Build Coastguard Worker     }
289*c8dee2aaSAndroid Build Coastguard Worker     return SkPathOpsPointsToVerb(order - 1);
290*c8dee2aaSAndroid Build Coastguard Worker }
291