xref: /aosp_15_r20/external/skia/tests/PathOpsAsWindingTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2018 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 
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathTypes.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/pathops/SkPathOps.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/utils/SkParsePath.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
17*c8dee2aaSAndroid Build Coastguard Worker 
18*c8dee2aaSAndroid Build Coastguard Worker #include <initializer_list>
19*c8dee2aaSAndroid Build Coastguard Worker #include <string>
20*c8dee2aaSAndroid Build Coastguard Worker 
build_squircle(SkPath::Verb verb,const SkRect & rect,SkPathDirection dir)21*c8dee2aaSAndroid Build Coastguard Worker static SkPath build_squircle(SkPath::Verb verb, const SkRect& rect, SkPathDirection dir) {
22*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
23*c8dee2aaSAndroid Build Coastguard Worker     bool reverse = SkPathDirection::kCCW == dir;
24*c8dee2aaSAndroid Build Coastguard Worker     switch (verb) {
25*c8dee2aaSAndroid Build Coastguard Worker         case SkPath::kLine_Verb:
26*c8dee2aaSAndroid Build Coastguard Worker             path.addRect(rect, dir);
27*c8dee2aaSAndroid Build Coastguard Worker             reverse = false;
28*c8dee2aaSAndroid Build Coastguard Worker             break;
29*c8dee2aaSAndroid Build Coastguard Worker         case SkPath::kQuad_Verb:
30*c8dee2aaSAndroid Build Coastguard Worker             path.moveTo(rect.centerX(), rect.fTop);
31*c8dee2aaSAndroid Build Coastguard Worker             path.quadTo(rect.fRight, rect.fTop, rect.fRight, rect.centerY());
32*c8dee2aaSAndroid Build Coastguard Worker             path.quadTo(rect.fRight, rect.fBottom, rect.centerX(), rect.fBottom);
33*c8dee2aaSAndroid Build Coastguard Worker             path.quadTo(rect.fLeft, rect.fBottom, rect.fLeft, rect.centerY());
34*c8dee2aaSAndroid Build Coastguard Worker             path.quadTo(rect.fLeft, rect.fTop, rect.centerX(), rect.fTop);
35*c8dee2aaSAndroid Build Coastguard Worker             break;
36*c8dee2aaSAndroid Build Coastguard Worker         case SkPath::kConic_Verb:
37*c8dee2aaSAndroid Build Coastguard Worker             path.addCircle(rect.centerX(), rect.centerY(), rect.width() / 2, dir);
38*c8dee2aaSAndroid Build Coastguard Worker             reverse = false;
39*c8dee2aaSAndroid Build Coastguard Worker             break;
40*c8dee2aaSAndroid Build Coastguard Worker         case SkPath::kCubic_Verb: {
41*c8dee2aaSAndroid Build Coastguard Worker             SkScalar aX14 = rect.fLeft + rect.width() * 1 / 4;
42*c8dee2aaSAndroid Build Coastguard Worker             SkScalar aX34 = rect.fLeft + rect.width() * 3 / 4;
43*c8dee2aaSAndroid Build Coastguard Worker             SkScalar aY14 = rect.fTop + rect.height() * 1 / 4;
44*c8dee2aaSAndroid Build Coastguard Worker             SkScalar aY34 = rect.fTop + rect.height() * 3 / 4;
45*c8dee2aaSAndroid Build Coastguard Worker             path.moveTo(rect.centerX(), rect.fTop);
46*c8dee2aaSAndroid Build Coastguard Worker             path.cubicTo(aX34, rect.fTop, rect.fRight, aY14, rect.fRight, rect.centerY());
47*c8dee2aaSAndroid Build Coastguard Worker             path.cubicTo(rect.fRight, aY34, aX34, rect.fBottom, rect.centerX(), rect.fBottom);
48*c8dee2aaSAndroid Build Coastguard Worker             path.cubicTo(aX14, rect.fBottom, rect.fLeft, aY34, rect.fLeft, rect.centerY());
49*c8dee2aaSAndroid Build Coastguard Worker             path.cubicTo(rect.fLeft, aY14, aX14, rect.fTop, rect.centerX(), rect.fTop);
50*c8dee2aaSAndroid Build Coastguard Worker             } break;
51*c8dee2aaSAndroid Build Coastguard Worker         default:
52*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(0);
53*c8dee2aaSAndroid Build Coastguard Worker     }
54*c8dee2aaSAndroid Build Coastguard Worker     if (reverse) {
55*c8dee2aaSAndroid Build Coastguard Worker         SkPath temp;
56*c8dee2aaSAndroid Build Coastguard Worker         temp.reverseAddPath(path);
57*c8dee2aaSAndroid Build Coastguard Worker         path.swap(temp);
58*c8dee2aaSAndroid Build Coastguard Worker     }
59*c8dee2aaSAndroid Build Coastguard Worker     return path;
60*c8dee2aaSAndroid Build Coastguard Worker }
61*c8dee2aaSAndroid Build Coastguard Worker 
bug12040_1(skiatest::Reporter * reporter)62*c8dee2aaSAndroid Build Coastguard Worker void bug12040_1(skiatest::Reporter* reporter) {
63*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
64*c8dee2aaSAndroid Build Coastguard Worker     path.setFillType(SkPathFillType::kWinding);
65*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(375, -30);
66*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(578, -30, 749, 176, 749, 422);
67*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(749, 583, 666, 706, 518, 765);
68*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(163, 611);
69*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(163, 579);
70*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(405, 684);
71*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(551, 609, 645, 468, 645, 322);
72*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(645, 183, 563, 82, 450, 82);
73*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(303, 82, 179, 249, 179, 446);
74*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(179, 579, 235, 689, 341, 768);
75*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(327, 786);
76*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(165, 717, 56, 536, 56, 335);
77*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(56, 125, 192, -30, 375, -30);
78*c8dee2aaSAndroid Build Coastguard Worker     path.close();
79*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(214, 225);
80*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(333, 248, 396, 311, 396, 405);
81*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(396, 695);
82*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(267, 641);
83*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(267, 395);
84*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(267, 324, 249, 285, 201, 254);
85*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(201, 254, 214, 225, 214, 225);
86*c8dee2aaSAndroid Build Coastguard Worker     path.close();
87*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(682, -106);
88*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(832, 12);
89*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(813, 33);
90*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(772, 0);
91*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(716, 29, 668, 76, 628, 140);
92*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(527, 44);
93*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(575, -26, 628, -77, 682, -106);
94*c8dee2aaSAndroid Build Coastguard Worker     path.close();
95*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(450, 59);
96*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(480, 59);
97*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(480, 678);
98*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(450, 678);
99*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(450, 678, 450, 59, 450, 59);
100*c8dee2aaSAndroid Build Coastguard Worker     path.close();
101*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(463, 374);
102*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(633, 459);
103*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(633, 490);
104*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(463, 406);
105*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(463, 406, 463, 374, 463, 374);
106*c8dee2aaSAndroid Build Coastguard Worker     path.close();
107*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(463, 269);
108*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(667, 372);
109*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(667, 403);
110*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(463, 301);
111*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(463, 301, 463, 269, 463, 269);
112*c8dee2aaSAndroid Build Coastguard Worker     path.close();
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker     SkPath path2;
115*c8dee2aaSAndroid Build Coastguard Worker     path2.setFillType(SkPathFillType::kWinding);
116*c8dee2aaSAndroid Build Coastguard Worker     path2.moveTo(-83.5464f, 188);
117*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(-83.5464f, 184.285f, -84.8599f, 181.114f, -87.4868f, 178.487f);
118*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(-90.1138f, 175.86f, -93.2849f, 174.546f, -97, 174.546f);
119*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(-100.715f, 174.546f, -103.886f, 175.86f, -106.513f, 178.487f);
120*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(-109.14f, 181.114f, -110.454f, 184.285f, -110.454f, 188);
121*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(-110.454f, 191.715f, -109.14f, 194.886f, -106.513f, 197.513f);
122*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(-103.886f, 200.14f, -100.715f, 201.454f, -97, 201.454f);
123*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(-93.2849f, 201.454f, -90.1138f, 200.14f, -87.4868f, 197.513f);
124*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(-84.8599f, 194.886f, -83.5464f, 191.715f, -83.5464f, 188);
125*c8dee2aaSAndroid Build Coastguard Worker     path2.close();
126*c8dee2aaSAndroid Build Coastguard Worker 
127*c8dee2aaSAndroid Build Coastguard Worker     SkPath opResult;
128*c8dee2aaSAndroid Build Coastguard Worker     Op(path, path2, kDifference_SkPathOp, &opResult);
129*c8dee2aaSAndroid Build Coastguard Worker 
130*c8dee2aaSAndroid Build Coastguard Worker     SkPath winding;
131*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, AsWinding(opResult, &winding));
132*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, winding.getFillType() == SkPathFillType::kWinding);
133*c8dee2aaSAndroid Build Coastguard Worker 
134*c8dee2aaSAndroid Build Coastguard Worker     SkPath difference;
135*c8dee2aaSAndroid Build Coastguard Worker     Op(winding, opResult, kXOR_SkPathOp, &difference);
136*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, difference.isEmpty());
137*c8dee2aaSAndroid Build Coastguard Worker }
138*c8dee2aaSAndroid Build Coastguard Worker 
bug12040_2(skiatest::Reporter * reporter)139*c8dee2aaSAndroid Build Coastguard Worker void bug12040_2(skiatest::Reporter* reporter) {
140*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
141*c8dee2aaSAndroid Build Coastguard Worker     path.setFillType(SkPathFillType::kWinding);
142*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(375, -30);
143*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(578, -30, 749, 176, 749, 422);
144*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(749, 583, 666, 706, 518, 765);
145*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(163, 611);
146*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(163, 579);
147*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(405, 684);
148*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(551, 609, 645, 468, 645, 322);
149*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(645, 183, 563, 82, 450, 82);
150*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(303, 82, 179, 249, 179, 446);
151*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(179, 579, 235, 689, 341, 768);
152*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(327, 786);
153*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(165, 717, 56, 536, 56, 335);
154*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(56, 125, 192, -30, 375, -30);
155*c8dee2aaSAndroid Build Coastguard Worker     path.close();
156*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(214, 225);
157*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(333, 248, 396, 311, 396, 405);
158*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(396, 695);
159*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(267, 641);
160*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(267, 395);
161*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(267, 324, 249, 285, 201, 254);
162*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(201, 254, 214, 225, 214, 225);
163*c8dee2aaSAndroid Build Coastguard Worker     path.close();
164*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(682, -106);
165*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(832, 12);
166*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(813, 33);
167*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(772, 0);
168*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(716, 29, 668, 76, 628, 140);
169*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(527, 44);
170*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(575, -26, 628, -77, 682, -106);
171*c8dee2aaSAndroid Build Coastguard Worker     path.close();
172*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(450, 59);
173*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(480, 59);
174*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(480, 678);
175*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(450, 678);
176*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(450, 678, 450, 59, 450, 59);
177*c8dee2aaSAndroid Build Coastguard Worker     path.close();
178*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(463, 374);
179*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(633, 459);
180*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(633, 490);
181*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(463, 406);
182*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(463, 406, 463, 374, 463, 374);
183*c8dee2aaSAndroid Build Coastguard Worker     path.close();
184*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(463, 269);
185*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(667, 372);
186*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(667, 403);
187*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(463, 301);
188*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(463, 301, 463, 269, 463, 269);
189*c8dee2aaSAndroid Build Coastguard Worker     path.close();
190*c8dee2aaSAndroid Build Coastguard Worker 
191*c8dee2aaSAndroid Build Coastguard Worker     SkPath path2;
192*c8dee2aaSAndroid Build Coastguard Worker     path2.setFillType(SkPathFillType::kWinding);
193*c8dee2aaSAndroid Build Coastguard Worker     path2.moveTo(269.134f, 71.3392f);
194*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(269.134f, 67.6241f, 267.82f, 64.453f, 265.193f, 61.826f);
195*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(262.566f, 59.1991f, 259.395f, 57.8856f, 255.68f, 57.8856f);
196*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(251.965f, 57.8856f, 248.794f, 59.1991f, 246.167f, 61.826f);
197*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(243.54f, 64.453f, 242.226f, 67.6241f, 242.226f, 71.3392f);
198*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(242.226f, 75.0543f, 243.54f, 78.2255f, 246.167f, 80.8524f);
199*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(248.794f, 83.4794f, 251.965f, 84.7928f, 255.68f, 84.7928f);
200*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(259.395f, 84.7928f, 262.566f, 83.4794f, 265.193f, 80.8524f);
201*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(267.82f, 78.2255f, 269.134f, 75.0543f, 269.134f, 71.3392f);
202*c8dee2aaSAndroid Build Coastguard Worker     path2.close();
203*c8dee2aaSAndroid Build Coastguard Worker 
204*c8dee2aaSAndroid Build Coastguard Worker     SkPath opResult;
205*c8dee2aaSAndroid Build Coastguard Worker     Op(path, path2, kDifference_SkPathOp, &opResult);
206*c8dee2aaSAndroid Build Coastguard Worker 
207*c8dee2aaSAndroid Build Coastguard Worker     // This produces the correct result in all the cases I've tried.
208*c8dee2aaSAndroid Build Coastguard Worker     // So it appears to be a winding issue.
209*c8dee2aaSAndroid Build Coastguard Worker     // canvas->drawPath(opResult, p);
210*c8dee2aaSAndroid Build Coastguard Worker 
211*c8dee2aaSAndroid Build Coastguard Worker     SkPath winding;
212*c8dee2aaSAndroid Build Coastguard Worker     path2.setFillType(SkPathFillType::kWinding);
213*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, AsWinding(opResult, &winding));
214*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, winding.getFillType() == SkPathFillType::kWinding);
215*c8dee2aaSAndroid Build Coastguard Worker 
216*c8dee2aaSAndroid Build Coastguard Worker     SkPath difference;
217*c8dee2aaSAndroid Build Coastguard Worker     Op(winding, opResult, kXOR_SkPathOp, &difference);
218*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, difference.isEmpty());
219*c8dee2aaSAndroid Build Coastguard Worker }
220*c8dee2aaSAndroid Build Coastguard Worker 
bug12040_3(skiatest::Reporter * reporter)221*c8dee2aaSAndroid Build Coastguard Worker void bug12040_3(skiatest::Reporter* reporter) {
222*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
223*c8dee2aaSAndroid Build Coastguard Worker     path.setFillType(SkPathFillType::kWinding);
224*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(375, -30);
225*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(578, -30, 749, 176, 749, 422);
226*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(749, 583, 666, 706, 518, 765);
227*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(163, 611);
228*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(163, 579);
229*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(405, 684);
230*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(551, 609, 645, 468, 645, 322);
231*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(645, 183, 563, 82, 450, 82);
232*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(303, 82, 179, 249, 179, 446);
233*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(179, 579, 235, 689, 341, 768);
234*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(327, 786);
235*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(165, 717, 56, 536, 56, 335);
236*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(56, 125, 192, -30, 375, -30);
237*c8dee2aaSAndroid Build Coastguard Worker     path.close();
238*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(214, 225);
239*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(333, 248, 396, 311, 396, 405);
240*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(396, 695);
241*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(267, 641);
242*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(267, 395);
243*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(267, 324, 249, 285, 201, 254);
244*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(201, 254, 214, 225, 214, 225);
245*c8dee2aaSAndroid Build Coastguard Worker     path.close();
246*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(682, -106);
247*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(832, 12);
248*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(813, 33);
249*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(772, 0);
250*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(716, 29, 668, 76, 628, 140);
251*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(527, 44);
252*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(575, -26, 628, -77, 682, -106);
253*c8dee2aaSAndroid Build Coastguard Worker     path.close();
254*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(450, 59);
255*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(480, 59);
256*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(480, 678);
257*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(450, 678);
258*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(450, 678, 450, 59, 450, 59);
259*c8dee2aaSAndroid Build Coastguard Worker     path.close();
260*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(463, 374);
261*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(633, 459);
262*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(633, 490);
263*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(463, 406);
264*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(463, 406, 463, 374, 463, 374);
265*c8dee2aaSAndroid Build Coastguard Worker     path.close();
266*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(463, 269);
267*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(667, 372);
268*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(667, 403);
269*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(463, 301);
270*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(463, 301, 463, 269, 463, 269);
271*c8dee2aaSAndroid Build Coastguard Worker     path.close();
272*c8dee2aaSAndroid Build Coastguard Worker 
273*c8dee2aaSAndroid Build Coastguard Worker     SkPath path2;
274*c8dee2aaSAndroid Build Coastguard Worker     path2.setFillType(SkPathFillType::kWinding);
275*c8dee2aaSAndroid Build Coastguard Worker     path2.moveTo(492.041f, 525.339f);
276*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(492.041f, 521.624f, 490.727f, 518.453f, 488.1f, 515.826f);
277*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(485.473f, 513.199f, 482.302f, 511.886f, 478.587f, 511.886f);
278*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(474.872f, 511.886f, 471.701f, 513.199f, 469.074f, 515.826f);
279*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(466.447f, 518.453f, 465.134f, 521.624f, 465.134f, 525.339f);
280*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(465.134f, 529.054f, 466.447f, 532.226f, 469.074f, 534.853f);
281*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(471.701f, 537.479f, 474.872f, 538.793f, 478.587f, 538.793f);
282*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(482.302f, 538.793f, 485.473f, 537.479f, 488.1f, 534.853f);
283*c8dee2aaSAndroid Build Coastguard Worker     path2.cubicTo(490.727f, 532.226f, 492.041f, 529.054f, 492.041f, 525.339f);
284*c8dee2aaSAndroid Build Coastguard Worker     path2.close();
285*c8dee2aaSAndroid Build Coastguard Worker 
286*c8dee2aaSAndroid Build Coastguard Worker     SkPath opResult;
287*c8dee2aaSAndroid Build Coastguard Worker     Op(path, path2, kDifference_SkPathOp, &opResult);
288*c8dee2aaSAndroid Build Coastguard Worker 
289*c8dee2aaSAndroid Build Coastguard Worker     SkPath winding;
290*c8dee2aaSAndroid Build Coastguard Worker     path2.setFillType(SkPathFillType::kWinding);
291*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, AsWinding(opResult, &winding));
292*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, winding.getFillType() == SkPathFillType::kWinding);
293*c8dee2aaSAndroid Build Coastguard Worker 
294*c8dee2aaSAndroid Build Coastguard Worker     SkPath difference;
295*c8dee2aaSAndroid Build Coastguard Worker     Op(winding, opResult, kXOR_SkPathOp, &difference);
296*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, difference.isEmpty());
297*c8dee2aaSAndroid Build Coastguard Worker }
298*c8dee2aaSAndroid Build Coastguard Worker 
bug12040_4(skiatest::Reporter * reporter)299*c8dee2aaSAndroid Build Coastguard Worker void bug12040_4(skiatest::Reporter* reporter) {
300*c8dee2aaSAndroid Build Coastguard Worker     for (int moveX = 199; moveX <= 201; ++moveX) {
301*c8dee2aaSAndroid Build Coastguard Worker         for (int moveY = 299; moveY <= 301; ++moveY) {
302*c8dee2aaSAndroid Build Coastguard Worker             for (int lineX = 199; lineX <= 201; ++lineX) {
303*c8dee2aaSAndroid Build Coastguard Worker                 for (int lineY = 199; lineY <= 201; ++lineY) {
304*c8dee2aaSAndroid Build Coastguard Worker                     SkPath path;
305*c8dee2aaSAndroid Build Coastguard Worker                     path.setFillType(SkPathFillType::kWinding);
306*c8dee2aaSAndroid Build Coastguard Worker                     path.addCircle(250, 250, 150);
307*c8dee2aaSAndroid Build Coastguard Worker 
308*c8dee2aaSAndroid Build Coastguard Worker                     SkPath path2;
309*c8dee2aaSAndroid Build Coastguard Worker                     path2.setFillType(SkPathFillType::kWinding);
310*c8dee2aaSAndroid Build Coastguard Worker                     path2.moveTo(moveX, moveY);  // 200, 300 works... But not 200, 301!!
311*c8dee2aaSAndroid Build Coastguard Worker                     path2.lineTo(lineX, lineY);  // 200, 200 works... But not 199, 200!!
312*c8dee2aaSAndroid Build Coastguard Worker                     path2.lineTo(300, 300);
313*c8dee2aaSAndroid Build Coastguard Worker                     path2.close();
314*c8dee2aaSAndroid Build Coastguard Worker 
315*c8dee2aaSAndroid Build Coastguard Worker                     SkPath opResult;
316*c8dee2aaSAndroid Build Coastguard Worker                     Op(path, path2, kDifference_SkPathOp, &opResult);
317*c8dee2aaSAndroid Build Coastguard Worker 
318*c8dee2aaSAndroid Build Coastguard Worker                     SkPath winding;
319*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, AsWinding(opResult, &winding));
320*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, winding.getFillType() == SkPathFillType::kWinding);
321*c8dee2aaSAndroid Build Coastguard Worker 
322*c8dee2aaSAndroid Build Coastguard Worker                     SkPath difference;
323*c8dee2aaSAndroid Build Coastguard Worker                     Op(winding, opResult, kXOR_SkPathOp, &difference);
324*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, difference.isEmpty());
325*c8dee2aaSAndroid Build Coastguard Worker                 }
326*c8dee2aaSAndroid Build Coastguard Worker             }
327*c8dee2aaSAndroid Build Coastguard Worker         }
328*c8dee2aaSAndroid Build Coastguard Worker     }
329*c8dee2aaSAndroid Build Coastguard Worker }
330*c8dee2aaSAndroid Build Coastguard Worker 
bug12040_5(skiatest::Reporter * reporter)331*c8dee2aaSAndroid Build Coastguard Worker void bug12040_5(skiatest::Reporter* reporter) {
332*c8dee2aaSAndroid Build Coastguard Worker     for (int moveX = 199; moveX <= 201; ++moveX) {
333*c8dee2aaSAndroid Build Coastguard Worker         for (int moveY = 299; moveY <= 301; ++moveY) {
334*c8dee2aaSAndroid Build Coastguard Worker             for (int lineX = 199; lineX <= 201; ++lineX) {
335*c8dee2aaSAndroid Build Coastguard Worker                 for (int lineY = 199; lineY <= 201; ++lineY) {
336*c8dee2aaSAndroid Build Coastguard Worker                     SkPath path;
337*c8dee2aaSAndroid Build Coastguard Worker                     path.setFillType(SkPathFillType::kWinding);
338*c8dee2aaSAndroid Build Coastguard Worker                     path.addRect(100, 100, 400, 400);
339*c8dee2aaSAndroid Build Coastguard Worker 
340*c8dee2aaSAndroid Build Coastguard Worker                     SkPath path2;
341*c8dee2aaSAndroid Build Coastguard Worker                     path2.setFillType(SkPathFillType::kWinding);
342*c8dee2aaSAndroid Build Coastguard Worker                     path2.moveTo(moveX, moveY);
343*c8dee2aaSAndroid Build Coastguard Worker                     path2.lineTo(lineX, lineY);  // 200, 200 works... But not 199, 200!!
344*c8dee2aaSAndroid Build Coastguard Worker                     path2.lineTo(300, 300);
345*c8dee2aaSAndroid Build Coastguard Worker                     path2.close();
346*c8dee2aaSAndroid Build Coastguard Worker 
347*c8dee2aaSAndroid Build Coastguard Worker                     SkPath opResult;
348*c8dee2aaSAndroid Build Coastguard Worker                     Op(path, path2, kDifference_SkPathOp, &opResult);
349*c8dee2aaSAndroid Build Coastguard Worker 
350*c8dee2aaSAndroid Build Coastguard Worker                     SkPath winding;
351*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, AsWinding(opResult, &winding));
352*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, winding.getFillType() == SkPathFillType::kWinding);
353*c8dee2aaSAndroid Build Coastguard Worker 
354*c8dee2aaSAndroid Build Coastguard Worker                     SkPath difference;
355*c8dee2aaSAndroid Build Coastguard Worker                     Op(winding, opResult, kXOR_SkPathOp, &difference);
356*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, difference.isEmpty());
357*c8dee2aaSAndroid Build Coastguard Worker                 }
358*c8dee2aaSAndroid Build Coastguard Worker             }
359*c8dee2aaSAndroid Build Coastguard Worker         }
360*c8dee2aaSAndroid Build Coastguard Worker     }
361*c8dee2aaSAndroid Build Coastguard Worker }
362*c8dee2aaSAndroid Build Coastguard Worker 
bug13496_1(skiatest::Reporter * reporter)363*c8dee2aaSAndroid Build Coastguard Worker void bug13496_1(skiatest::Reporter* reporter) {
364*c8dee2aaSAndroid Build Coastguard Worker     std::string originalPathStr =
365*c8dee2aaSAndroid Build Coastguard Worker             "M5.93 -3.12C5.93 -5.03 4.73 -6.06 3.5 -6.06C2.67 -6.06 1.98 -5.59 1.76 -5.34L1.67 "
366*c8dee2aaSAndroid Build Coastguard Worker             "-5.93L0.75 -5.93L0.75 2.23L1.87 2.04L1.87 -0.12C2.12 -0.03 2.62 0.07 3.18 0.07C4.57 "
367*c8dee2aaSAndroid Build Coastguard Worker             "0.07 5.93 -1.06 5.93 -3.12ZM4.81 -3.09C4.81 -1.51 4.18 -0.85 3.17 -0.85C2.57 -0.85 "
368*c8dee2aaSAndroid Build Coastguard Worker             "2.15 -0.98 1.87 -1.12L1.87 -4.15C2.34 -4.73 2.75 -5.09 3.42 -5.09C4.31 -5.09 4.81 "
369*c8dee2aaSAndroid Build Coastguard Worker             "-4.46 4.81 -3.09Z";
370*c8dee2aaSAndroid Build Coastguard Worker 
371*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
372*c8dee2aaSAndroid Build Coastguard Worker     SkParsePath::FromSVGString(originalPathStr.c_str(), &path);
373*c8dee2aaSAndroid Build Coastguard Worker 
374*c8dee2aaSAndroid Build Coastguard Worker     SkPath simplifiedPath;
375*c8dee2aaSAndroid Build Coastguard Worker     Simplify(path, &simplifiedPath);
376*c8dee2aaSAndroid Build Coastguard Worker 
377*c8dee2aaSAndroid Build Coastguard Worker     SkPath windingPath;
378*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, AsWinding(simplifiedPath, &windingPath));
379*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, windingPath.getFillType() == SkPathFillType::kWinding);
380*c8dee2aaSAndroid Build Coastguard Worker 
381*c8dee2aaSAndroid Build Coastguard Worker     SkPath difference;
382*c8dee2aaSAndroid Build Coastguard Worker     Op(windingPath, simplifiedPath, kXOR_SkPathOp, &difference);
383*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, difference.isEmpty());
384*c8dee2aaSAndroid Build Coastguard Worker }
385*c8dee2aaSAndroid Build Coastguard Worker 
bug13496_2(skiatest::Reporter * reporter)386*c8dee2aaSAndroid Build Coastguard Worker void bug13496_2(skiatest::Reporter* reporter) {
387*c8dee2aaSAndroid Build Coastguard Worker     std::string originalPathStr =
388*c8dee2aaSAndroid Build Coastguard Worker             "M4 0"
389*c8dee2aaSAndroid Build Coastguard Worker             "L0 0"
390*c8dee2aaSAndroid Build Coastguard Worker             "L0 5"
391*c8dee2aaSAndroid Build Coastguard Worker             "L4 4"
392*c8dee2aaSAndroid Build Coastguard Worker             "Z"
393*c8dee2aaSAndroid Build Coastguard Worker             "M3 3"
394*c8dee2aaSAndroid Build Coastguard Worker             "L1 3"
395*c8dee2aaSAndroid Build Coastguard Worker             "L1 1"
396*c8dee2aaSAndroid Build Coastguard Worker             "L3 1"
397*c8dee2aaSAndroid Build Coastguard Worker             "Z";
398*c8dee2aaSAndroid Build Coastguard Worker 
399*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
400*c8dee2aaSAndroid Build Coastguard Worker     SkParsePath::FromSVGString(originalPathStr.c_str(), &path);
401*c8dee2aaSAndroid Build Coastguard Worker 
402*c8dee2aaSAndroid Build Coastguard Worker     SkPath simplifiedPath;
403*c8dee2aaSAndroid Build Coastguard Worker     Simplify(path, &simplifiedPath);
404*c8dee2aaSAndroid Build Coastguard Worker 
405*c8dee2aaSAndroid Build Coastguard Worker     SkPath windingPath;
406*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, AsWinding(simplifiedPath, &windingPath));
407*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, windingPath.getFillType() == SkPathFillType::kWinding);
408*c8dee2aaSAndroid Build Coastguard Worker 
409*c8dee2aaSAndroid Build Coastguard Worker     SkPath difference;
410*c8dee2aaSAndroid Build Coastguard Worker     Op(windingPath, simplifiedPath, kXOR_SkPathOp, &difference);
411*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, difference.isEmpty());
412*c8dee2aaSAndroid Build Coastguard Worker }
413*c8dee2aaSAndroid Build Coastguard Worker 
bug13496_3(skiatest::Reporter * reporter)414*c8dee2aaSAndroid Build Coastguard Worker void bug13496_3(skiatest::Reporter* reporter) {
415*c8dee2aaSAndroid Build Coastguard Worker     std::string originalPathStr =
416*c8dee2aaSAndroid Build Coastguard Worker             "M4 0"
417*c8dee2aaSAndroid Build Coastguard Worker             "L0 0"
418*c8dee2aaSAndroid Build Coastguard Worker             "L0 4"
419*c8dee2aaSAndroid Build Coastguard Worker             "L4 4"
420*c8dee2aaSAndroid Build Coastguard Worker             "Z"
421*c8dee2aaSAndroid Build Coastguard Worker             "M3 3"
422*c8dee2aaSAndroid Build Coastguard Worker             "L1 3"
423*c8dee2aaSAndroid Build Coastguard Worker             "L1 1"
424*c8dee2aaSAndroid Build Coastguard Worker             "L3 1"
425*c8dee2aaSAndroid Build Coastguard Worker             "Z";
426*c8dee2aaSAndroid Build Coastguard Worker 
427*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
428*c8dee2aaSAndroid Build Coastguard Worker     SkParsePath::FromSVGString(originalPathStr.c_str(), &path);
429*c8dee2aaSAndroid Build Coastguard Worker 
430*c8dee2aaSAndroid Build Coastguard Worker     SkPath simplifiedPath;
431*c8dee2aaSAndroid Build Coastguard Worker     Simplify(path, &simplifiedPath);
432*c8dee2aaSAndroid Build Coastguard Worker 
433*c8dee2aaSAndroid Build Coastguard Worker     SkPath windingPath;
434*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, AsWinding(simplifiedPath, &windingPath));
435*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, windingPath.getFillType() == SkPathFillType::kWinding);
436*c8dee2aaSAndroid Build Coastguard Worker 
437*c8dee2aaSAndroid Build Coastguard Worker     SkPath difference;
438*c8dee2aaSAndroid Build Coastguard Worker     Op(windingPath, simplifiedPath, kXOR_SkPathOp, &difference);
439*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, difference.isEmpty());
440*c8dee2aaSAndroid Build Coastguard Worker }
441*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(PathOpsAsWinding,reporter)442*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(PathOpsAsWinding, reporter) {
443*c8dee2aaSAndroid Build Coastguard Worker     SkPath test, result;
444*c8dee2aaSAndroid Build Coastguard Worker     test.addRect({1, 2, 3, 4});
445*c8dee2aaSAndroid Build Coastguard Worker     // if test is winding
446*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, AsWinding(test, &result));
447*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, test == result);
448*c8dee2aaSAndroid Build Coastguard Worker     // if test is empty
449*c8dee2aaSAndroid Build Coastguard Worker     test.reset();
450*c8dee2aaSAndroid Build Coastguard Worker     test.setFillType(SkPathFillType::kEvenOdd);
451*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, AsWinding(test, &result));
452*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, result.isEmpty());
453*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, result.getFillType() == SkPathFillType::kWinding);
454*c8dee2aaSAndroid Build Coastguard Worker     // if test is convex
455*c8dee2aaSAndroid Build Coastguard Worker     test.addCircle(5, 5, 10);
456*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, AsWinding(test, &result));
457*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, result.isConvex());
458*c8dee2aaSAndroid Build Coastguard Worker     test.setFillType(SkPathFillType::kWinding);
459*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, test == result);
460*c8dee2aaSAndroid Build Coastguard Worker     // if test has infinity
461*c8dee2aaSAndroid Build Coastguard Worker     test.reset();
462*c8dee2aaSAndroid Build Coastguard Worker     test.addRect({1, 2, 3, SK_ScalarInfinity});
463*c8dee2aaSAndroid Build Coastguard Worker     test.setFillType(SkPathFillType::kEvenOdd);
464*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !AsWinding(test, &result));
465*c8dee2aaSAndroid Build Coastguard Worker     // if test has only one contour
466*c8dee2aaSAndroid Build Coastguard Worker     test.reset();
467*c8dee2aaSAndroid Build Coastguard Worker     SkPoint ell[] = {{0, 0}, {4, 0}, {4, 1}, {1, 1}, {1, 4}, {0, 4}};
468*c8dee2aaSAndroid Build Coastguard Worker     test.addPoly(ell, std::size(ell), true);
469*c8dee2aaSAndroid Build Coastguard Worker     test.setFillType(SkPathFillType::kEvenOdd);
470*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, AsWinding(test, &result));
471*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !result.isConvex());
472*c8dee2aaSAndroid Build Coastguard Worker     test.setFillType(SkPathFillType::kWinding);
473*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, test == result);
474*c8dee2aaSAndroid Build Coastguard Worker     // test two contours that do not overlap or share bounds
475*c8dee2aaSAndroid Build Coastguard Worker     test.addRect({5, 2, 6, 3});
476*c8dee2aaSAndroid Build Coastguard Worker     test.setFillType(SkPathFillType::kEvenOdd);
477*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, AsWinding(test, &result));
478*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !result.isConvex());
479*c8dee2aaSAndroid Build Coastguard Worker     test.setFillType(SkPathFillType::kWinding);
480*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, test == result);
481*c8dee2aaSAndroid Build Coastguard Worker     // test two contours that do not overlap but share bounds
482*c8dee2aaSAndroid Build Coastguard Worker     test.reset();
483*c8dee2aaSAndroid Build Coastguard Worker     test.addPoly(ell, std::size(ell), true);
484*c8dee2aaSAndroid Build Coastguard Worker     test.addRect({2, 2, 3, 3});
485*c8dee2aaSAndroid Build Coastguard Worker     test.setFillType(SkPathFillType::kEvenOdd);
486*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, AsWinding(test, &result));
487*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !result.isConvex());
488*c8dee2aaSAndroid Build Coastguard Worker     test.setFillType(SkPathFillType::kWinding);
489*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, test == result);
490*c8dee2aaSAndroid Build Coastguard Worker     // test two contours that partially overlap
491*c8dee2aaSAndroid Build Coastguard Worker     test.reset();
492*c8dee2aaSAndroid Build Coastguard Worker     test.addRect({0, 0, 3, 3});
493*c8dee2aaSAndroid Build Coastguard Worker     test.addRect({1, 1, 4, 4});
494*c8dee2aaSAndroid Build Coastguard Worker     test.setFillType(SkPathFillType::kEvenOdd);
495*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, AsWinding(test, &result));
496*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !result.isConvex());
497*c8dee2aaSAndroid Build Coastguard Worker     test.setFillType(SkPathFillType::kWinding);
498*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, test == result);
499*c8dee2aaSAndroid Build Coastguard Worker     // test that result may be input
500*c8dee2aaSAndroid Build Coastguard Worker     SkPath copy = test;
501*c8dee2aaSAndroid Build Coastguard Worker     test.setFillType(SkPathFillType::kEvenOdd);
502*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, AsWinding(test, &test));
503*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !test.isConvex());
504*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, test == copy);
505*c8dee2aaSAndroid Build Coastguard Worker     // test a in b, b in a, cw/ccw
506*c8dee2aaSAndroid Build Coastguard Worker     constexpr SkRect rectA = {0, 0, 3, 3};
507*c8dee2aaSAndroid Build Coastguard Worker     constexpr SkRect rectB = {1, 1, 2, 2};
508*c8dee2aaSAndroid Build Coastguard Worker     const std::initializer_list<SkPoint> revBccw = {{1, 2}, {2, 2}, {2, 1}, {1, 1}};
509*c8dee2aaSAndroid Build Coastguard Worker     const std::initializer_list<SkPoint> revBcw  = {{2, 1}, {2, 2}, {1, 2}, {1, 1}};
510*c8dee2aaSAndroid Build Coastguard Worker     for (bool aFirst : {false, true}) {
511*c8dee2aaSAndroid Build Coastguard Worker         for (auto dirA : {SkPathDirection::kCW, SkPathDirection::kCCW}) {
512*c8dee2aaSAndroid Build Coastguard Worker             for (auto dirB : {SkPathDirection::kCW, SkPathDirection::kCCW}) {
513*c8dee2aaSAndroid Build Coastguard Worker                 test.reset();
514*c8dee2aaSAndroid Build Coastguard Worker                 test.setFillType(SkPathFillType::kEvenOdd);
515*c8dee2aaSAndroid Build Coastguard Worker                 if (aFirst) {
516*c8dee2aaSAndroid Build Coastguard Worker                     test.addRect(rectA, dirA);
517*c8dee2aaSAndroid Build Coastguard Worker                     test.addRect(rectB, dirB);
518*c8dee2aaSAndroid Build Coastguard Worker                 } else {
519*c8dee2aaSAndroid Build Coastguard Worker                     test.addRect(rectB, dirB);
520*c8dee2aaSAndroid Build Coastguard Worker                     test.addRect(rectA, dirA);
521*c8dee2aaSAndroid Build Coastguard Worker                 }
522*c8dee2aaSAndroid Build Coastguard Worker                 SkPath original = test;
523*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, AsWinding(test, &result));
524*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, result.getFillType() == SkPathFillType::kWinding);
525*c8dee2aaSAndroid Build Coastguard Worker                 test.reset();
526*c8dee2aaSAndroid Build Coastguard Worker                 if (aFirst) {
527*c8dee2aaSAndroid Build Coastguard Worker                     test.addRect(rectA, dirA);
528*c8dee2aaSAndroid Build Coastguard Worker                 }
529*c8dee2aaSAndroid Build Coastguard Worker                 if (dirA != dirB) {
530*c8dee2aaSAndroid Build Coastguard Worker                     test.addRect(rectB, dirB);
531*c8dee2aaSAndroid Build Coastguard Worker                 } else {
532*c8dee2aaSAndroid Build Coastguard Worker                     test.addPoly(SkPathDirection::kCW == dirA ? revBccw : revBcw, true);
533*c8dee2aaSAndroid Build Coastguard Worker                 }
534*c8dee2aaSAndroid Build Coastguard Worker                 if (!aFirst) {
535*c8dee2aaSAndroid Build Coastguard Worker                     test.addRect(rectA, dirA);
536*c8dee2aaSAndroid Build Coastguard Worker                 }
537*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, test == result);
538*c8dee2aaSAndroid Build Coastguard Worker                 // test that result may be input
539*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, AsWinding(original, &original));
540*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, original.getFillType() == SkPathFillType::kWinding);
541*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, original == result);
542*c8dee2aaSAndroid Build Coastguard Worker             }
543*c8dee2aaSAndroid Build Coastguard Worker         }
544*c8dee2aaSAndroid Build Coastguard Worker     }
545*c8dee2aaSAndroid Build Coastguard Worker     // Test curve types with donuts. Create a donut with outer and hole in all directions.
546*c8dee2aaSAndroid Build Coastguard Worker     // After converting to winding, all donuts should have a hole in the middle.
547*c8dee2aaSAndroid Build Coastguard Worker     for (bool aFirst : {false, true}) {
548*c8dee2aaSAndroid Build Coastguard Worker         for (auto dirA : {SkPathDirection::kCW, SkPathDirection::kCCW}) {
549*c8dee2aaSAndroid Build Coastguard Worker             for (auto dirB : {SkPathDirection::kCW, SkPathDirection::kCCW}) {
550*c8dee2aaSAndroid Build Coastguard Worker                 for (auto curveA : { SkPath::kLine_Verb, SkPath::kQuad_Verb,
551*c8dee2aaSAndroid Build Coastguard Worker                                      SkPath::kConic_Verb, SkPath::kCubic_Verb } ) {
552*c8dee2aaSAndroid Build Coastguard Worker                     SkPath pathA = build_squircle(curveA, rectA, dirA);
553*c8dee2aaSAndroid Build Coastguard Worker                     for (auto curveB : { SkPath::kLine_Verb, SkPath::kQuad_Verb,
554*c8dee2aaSAndroid Build Coastguard Worker                                      SkPath::kConic_Verb, SkPath::kCubic_Verb } ) {
555*c8dee2aaSAndroid Build Coastguard Worker                         test = aFirst ? pathA : SkPath();
556*c8dee2aaSAndroid Build Coastguard Worker                         test.addPath(build_squircle(curveB, rectB, dirB));
557*c8dee2aaSAndroid Build Coastguard Worker                         if (!aFirst) {
558*c8dee2aaSAndroid Build Coastguard Worker                             test.addPath(pathA);
559*c8dee2aaSAndroid Build Coastguard Worker                         }
560*c8dee2aaSAndroid Build Coastguard Worker                         test.setFillType(SkPathFillType::kEvenOdd);
561*c8dee2aaSAndroid Build Coastguard Worker                         REPORTER_ASSERT(reporter, AsWinding(test, &result));
562*c8dee2aaSAndroid Build Coastguard Worker                        REPORTER_ASSERT(reporter, result.getFillType() == SkPathFillType::kWinding);
563*c8dee2aaSAndroid Build Coastguard Worker                         for (SkScalar x = rectA.fLeft - 1; x <= rectA.fRight + 1; ++x) {
564*c8dee2aaSAndroid Build Coastguard Worker                             for (SkScalar y = rectA.fTop - 1; y <= rectA.fBottom + 1; ++y) {
565*c8dee2aaSAndroid Build Coastguard Worker                                 bool evenOddContains = test.contains(x, y);
566*c8dee2aaSAndroid Build Coastguard Worker                                 bool windingContains = result.contains(x, y);
567*c8dee2aaSAndroid Build Coastguard Worker                                 REPORTER_ASSERT(reporter, evenOddContains == windingContains);
568*c8dee2aaSAndroid Build Coastguard Worker                             }
569*c8dee2aaSAndroid Build Coastguard Worker                         }
570*c8dee2aaSAndroid Build Coastguard Worker                     }
571*c8dee2aaSAndroid Build Coastguard Worker                 }
572*c8dee2aaSAndroid Build Coastguard Worker             }
573*c8dee2aaSAndroid Build Coastguard Worker         }
574*c8dee2aaSAndroid Build Coastguard Worker     }
575*c8dee2aaSAndroid Build Coastguard Worker     // test https://bugs.chromium.org/p/skia/issues/detail?id=12040
576*c8dee2aaSAndroid Build Coastguard Worker     bug12040_1(reporter);
577*c8dee2aaSAndroid Build Coastguard Worker     bug12040_2(reporter);
578*c8dee2aaSAndroid Build Coastguard Worker     bug12040_3(reporter);
579*c8dee2aaSAndroid Build Coastguard Worker     bug12040_4(reporter);
580*c8dee2aaSAndroid Build Coastguard Worker     bug12040_5(reporter);
581*c8dee2aaSAndroid Build Coastguard Worker     // test https://bugs.chromium.org/p/skia/issues/detail?id=13496
582*c8dee2aaSAndroid Build Coastguard Worker     bug13496_1(reporter);
583*c8dee2aaSAndroid Build Coastguard Worker     bug13496_2(reporter);
584*c8dee2aaSAndroid Build Coastguard Worker     bug13496_3(reporter);
585*c8dee2aaSAndroid Build Coastguard Worker }
586