xref: /aosp_15_r20/external/skia/tests/PathTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2011 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/SkBlendMode.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontTypes.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathBuilder.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathTypes.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathUtils.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRRect.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRegion.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStream.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStrokeRec.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkVertices.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "include/pathops/SkPathOps.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkIDChangeListener.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkPathRef.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkFloatingPoint.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMalloc.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "include/utils/SkNullCanvas.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "include/utils/SkParse.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "include/utils/SkParsePath.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkAutoMalloc.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkFloatBits.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
45*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkGeometry.h"
46*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkPathEnums.h"
47*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkPathPriv.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkReadBuffer.h"
49*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkWriteBuffer.h"
50*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
51*c8dee2aaSAndroid Build Coastguard Worker #include "tools/fonts/FontToolUtils.h"
52*c8dee2aaSAndroid Build Coastguard Worker 
53*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
54*c8dee2aaSAndroid Build Coastguard Worker #include <cfloat>
55*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
56*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
57*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
58*c8dee2aaSAndroid Build Coastguard Worker #include <initializer_list>
59*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
60*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
61*c8dee2aaSAndroid Build Coastguard Worker 
set_radii(SkVector radii[4],int index,float rad)62*c8dee2aaSAndroid Build Coastguard Worker static void set_radii(SkVector radii[4], int index, float rad) {
63*c8dee2aaSAndroid Build Coastguard Worker     sk_bzero(radii, sizeof(SkVector) * 4);
64*c8dee2aaSAndroid Build Coastguard Worker     radii[index].set(rad, rad);
65*c8dee2aaSAndroid Build Coastguard Worker }
66*c8dee2aaSAndroid Build Coastguard Worker 
test_add_rrect(skiatest::Reporter * reporter,const SkRect & bounds,const SkVector radii[4])67*c8dee2aaSAndroid Build Coastguard Worker static void test_add_rrect(skiatest::Reporter* reporter, const SkRect& bounds,
68*c8dee2aaSAndroid Build Coastguard Worker                            const SkVector radii[4]) {
69*c8dee2aaSAndroid Build Coastguard Worker     SkRRect rrect;
70*c8dee2aaSAndroid Build Coastguard Worker     rrect.setRectRadii(bounds, radii);
71*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, bounds == rrect.rect());
72*c8dee2aaSAndroid Build Coastguard Worker 
73*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
74*c8dee2aaSAndroid Build Coastguard Worker     // this line should not assert in the debug build (from validate)
75*c8dee2aaSAndroid Build Coastguard Worker     path.addRRect(rrect);
76*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, bounds == path.getBounds());
77*c8dee2aaSAndroid Build Coastguard Worker }
78*c8dee2aaSAndroid Build Coastguard Worker 
test_skbug_3469(skiatest::Reporter * reporter)79*c8dee2aaSAndroid Build Coastguard Worker static void test_skbug_3469(skiatest::Reporter* reporter) {
80*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
81*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(20, 20);
82*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(20, 50, 80, 50);
83*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(20, 50, 20, 80);
84*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isConvex());
85*c8dee2aaSAndroid Build Coastguard Worker }
86*c8dee2aaSAndroid Build Coastguard Worker 
test_skbug_3239(skiatest::Reporter * reporter)87*c8dee2aaSAndroid Build Coastguard Worker static void test_skbug_3239(skiatest::Reporter* reporter) {
88*c8dee2aaSAndroid Build Coastguard Worker     const float min = SkBits2Float(0xcb7f16c8); /* -16717512.000000 */
89*c8dee2aaSAndroid Build Coastguard Worker     const float max = SkBits2Float(0x4b7f1c1d); /*  16718877.000000 */
90*c8dee2aaSAndroid Build Coastguard Worker     const float big = SkBits2Float(0x4b7f1bd7); /*  16718807.000000 */
91*c8dee2aaSAndroid Build Coastguard Worker 
92*c8dee2aaSAndroid Build Coastguard Worker     const float rad = 33436320;
93*c8dee2aaSAndroid Build Coastguard Worker 
94*c8dee2aaSAndroid Build Coastguard Worker     const SkRect rectx = SkRect::MakeLTRB(min, min, max, big);
95*c8dee2aaSAndroid Build Coastguard Worker     const SkRect recty = SkRect::MakeLTRB(min, min, big, max);
96*c8dee2aaSAndroid Build Coastguard Worker 
97*c8dee2aaSAndroid Build Coastguard Worker     SkVector radii[4];
98*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 4; ++i) {
99*c8dee2aaSAndroid Build Coastguard Worker         set_radii(radii, i, rad);
100*c8dee2aaSAndroid Build Coastguard Worker         test_add_rrect(reporter, rectx, radii);
101*c8dee2aaSAndroid Build Coastguard Worker         test_add_rrect(reporter, recty, radii);
102*c8dee2aaSAndroid Build Coastguard Worker     }
103*c8dee2aaSAndroid Build Coastguard Worker }
104*c8dee2aaSAndroid Build Coastguard Worker 
make_path_crbug364224(SkPath * path)105*c8dee2aaSAndroid Build Coastguard Worker static void make_path_crbug364224(SkPath* path) {
106*c8dee2aaSAndroid Build Coastguard Worker     path->reset();
107*c8dee2aaSAndroid Build Coastguard Worker     path->moveTo(3.747501373f, 2.724499941f);
108*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(3.747501373f, 3.75f);
109*c8dee2aaSAndroid Build Coastguard Worker     path->cubicTo(3.747501373f, 3.88774991f, 3.635501385f, 4.0f, 3.497501373f, 4.0f);
110*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(0.7475013733f, 4.0f);
111*c8dee2aaSAndroid Build Coastguard Worker     path->cubicTo(0.6095013618f, 4.0f, 0.4975013733f, 3.88774991f, 0.4975013733f, 3.75f);
112*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(0.4975013733f, 1.0f);
113*c8dee2aaSAndroid Build Coastguard Worker     path->cubicTo(0.4975013733f, 0.8622499704f, 0.6095013618f, 0.75f, 0.7475013733f,0.75f);
114*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(3.497501373f, 0.75f);
115*c8dee2aaSAndroid Build Coastguard Worker     path->cubicTo(3.50275135f, 0.75f, 3.5070014f, 0.7527500391f, 3.513001442f, 0.753000021f);
116*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(3.715001345f, 0.5512499809f);
117*c8dee2aaSAndroid Build Coastguard Worker     path->cubicTo(3.648251295f, 0.5194999576f, 3.575501442f, 0.4999999702f, 3.497501373f, 0.4999999702f);
118*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(0.7475013733f, 0.4999999702f);
119*c8dee2aaSAndroid Build Coastguard Worker     path->cubicTo(0.4715013802f, 0.4999999702f, 0.2475013733f, 0.7239999771f, 0.2475013733f, 1.0f);
120*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(0.2475013733f, 3.75f);
121*c8dee2aaSAndroid Build Coastguard Worker     path->cubicTo(0.2475013733f, 4.026000023f, 0.4715013504f, 4.25f, 0.7475013733f, 4.25f);
122*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(3.497501373f, 4.25f);
123*c8dee2aaSAndroid Build Coastguard Worker     path->cubicTo(3.773501396f, 4.25f, 3.997501373f, 4.026000023f, 3.997501373f, 3.75f);
124*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(3.997501373f, 2.474750042f);
125*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(3.747501373f, 2.724499941f);
126*c8dee2aaSAndroid Build Coastguard Worker     path->close();
127*c8dee2aaSAndroid Build Coastguard Worker }
128*c8dee2aaSAndroid Build Coastguard Worker 
make_path_crbug364224_simplified(SkPath * path)129*c8dee2aaSAndroid Build Coastguard Worker static void make_path_crbug364224_simplified(SkPath* path) {
130*c8dee2aaSAndroid Build Coastguard Worker     path->moveTo(3.747501373f, 2.724499941f);
131*c8dee2aaSAndroid Build Coastguard Worker     path->cubicTo(3.648251295f, 0.5194999576f, 3.575501442f, 0.4999999702f, 3.497501373f, 0.4999999702f);
132*c8dee2aaSAndroid Build Coastguard Worker     path->close();
133*c8dee2aaSAndroid Build Coastguard Worker }
134*c8dee2aaSAndroid Build Coastguard Worker 
test_sect_with_horizontal_needs_pinning()135*c8dee2aaSAndroid Build Coastguard Worker static void test_sect_with_horizontal_needs_pinning() {
136*c8dee2aaSAndroid Build Coastguard Worker     // Test that sect_with_horizontal in SkLineClipper.cpp needs to pin after computing the
137*c8dee2aaSAndroid Build Coastguard Worker     // intersection.
138*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
139*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
140*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(-540000, -720000);
141*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(-9.10000017e-05f, 9.99999996e-13f);
142*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(1, 1);
143*c8dee2aaSAndroid Build Coastguard Worker 
144*c8dee2aaSAndroid Build Coastguard Worker     // Without the pinning code in sect_with_horizontal(), this would assert in the lineclipper
145*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
146*c8dee2aaSAndroid Build Coastguard Worker     SkSurfaces::Raster(SkImageInfo::MakeN32Premul(10, 10))->getCanvas()->drawPath(path, paint);
147*c8dee2aaSAndroid Build Coastguard Worker }
148*c8dee2aaSAndroid Build Coastguard Worker 
test_iterative_intersect_line()149*c8dee2aaSAndroid Build Coastguard Worker static void test_iterative_intersect_line() {
150*c8dee2aaSAndroid Build Coastguard Worker     // crbug.com/1320467
151*c8dee2aaSAndroid Build Coastguard Worker     // SkLineClipper::IntersectLine used to clip against the horizontal segment. Then, if it still
152*c8dee2aaSAndroid Build Coastguard Worker     // needed clipping, would clip against the vertical segment, but start over from the un-clipped
153*c8dee2aaSAndroid Build Coastguard Worker     // endpoints. With that version, this draw would trigger an assert.
154*c8dee2aaSAndroid Build Coastguard Worker     // With the fix (iteratively clipping the intermediate results after the first operation),
155*c8dee2aaSAndroid Build Coastguard Worker     // this shouldn't assert:
156*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
157*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(-478.805145f, 153.862549f);
158*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(6.27216804e+19f, 6.27216804e+19f);
159*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(-666.754272f, 155.086304f);
160*c8dee2aaSAndroid Build Coastguard Worker     path.close();
161*c8dee2aaSAndroid Build Coastguard Worker 
162*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
163*c8dee2aaSAndroid Build Coastguard Worker     paint.setStyle(SkPaint::kStroke_Style);
164*c8dee2aaSAndroid Build Coastguard Worker     SkSurfaces::Raster(SkImageInfo::MakeN32Premul(256, 256))->getCanvas()->drawPath(path, paint);
165*c8dee2aaSAndroid Build Coastguard Worker }
166*c8dee2aaSAndroid Build Coastguard Worker 
test_path_crbug364224()167*c8dee2aaSAndroid Build Coastguard Worker static void test_path_crbug364224() {
168*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
169*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
170*c8dee2aaSAndroid Build Coastguard Worker     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(84, 88)));
171*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = surface->getCanvas();
172*c8dee2aaSAndroid Build Coastguard Worker 
173*c8dee2aaSAndroid Build Coastguard Worker     make_path_crbug364224_simplified(&path);
174*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPath(path, paint);
175*c8dee2aaSAndroid Build Coastguard Worker 
176*c8dee2aaSAndroid Build Coastguard Worker     make_path_crbug364224(&path);
177*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPath(path, paint);
178*c8dee2aaSAndroid Build Coastguard Worker }
179*c8dee2aaSAndroid Build Coastguard Worker 
test_draw_AA_path(int width,int height,const SkPath & path)180*c8dee2aaSAndroid Build Coastguard Worker static void test_draw_AA_path(int width, int height, const SkPath& path) {
181*c8dee2aaSAndroid Build Coastguard Worker     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(width, height)));
182*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = surface->getCanvas();
183*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
184*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(true);
185*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPath(path, paint);
186*c8dee2aaSAndroid Build Coastguard Worker }
187*c8dee2aaSAndroid Build Coastguard Worker 
188*c8dee2aaSAndroid Build Coastguard Worker // this is a unit test instead of a GM because it doesn't draw anything
test_fuzz_crbug_638223()189*c8dee2aaSAndroid Build Coastguard Worker static void test_fuzz_crbug_638223() {
190*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
191*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x47452a00), SkBits2Float(0x43211d01));  // 50474, 161.113f
192*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0x401c0000), SkBits2Float(0x40680000),
193*c8dee2aaSAndroid Build Coastguard Worker         SkBits2Float(0x02c25a81), SkBits2Float(0x981a1fa0),
194*c8dee2aaSAndroid Build Coastguard Worker         SkBits2Float(0x6bf9abea));  // 2.4375f, 3.625f, 2.85577e-37f, -1.992e-24f, 6.03669e+26f
195*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(250, 250, path);
196*c8dee2aaSAndroid Build Coastguard Worker }
197*c8dee2aaSAndroid Build Coastguard Worker 
test_fuzz_crbug_643933()198*c8dee2aaSAndroid Build Coastguard Worker static void test_fuzz_crbug_643933() {
199*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
200*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0);
201*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0x002001f2), SkBits2Float(0x4161ffff),  // 2.93943e-39f, 14.125f
202*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x49f7224d), SkBits2Float(0x45eec8df), // 2.02452e+06f, 7641.11f
203*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x721aee0c));  // 3.0687e+30f
204*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(250, 250, path);
205*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
206*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0);
207*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0x00007ff2), SkBits2Float(0x4169ffff),  // 4.58981e-41f, 14.625f
208*c8dee2aaSAndroid Build Coastguard Worker         SkBits2Float(0x43ff2261), SkBits2Float(0x41eeea04),  // 510.269f, 29.8643f
209*c8dee2aaSAndroid Build Coastguard Worker         SkBits2Float(0x5d06eff8));  // 6.07704e+17f
210*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(250, 250, path);
211*c8dee2aaSAndroid Build Coastguard Worker }
212*c8dee2aaSAndroid Build Coastguard Worker 
test_fuzz_crbug_647922()213*c8dee2aaSAndroid Build Coastguard Worker static void test_fuzz_crbug_647922() {
214*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
215*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0);
216*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0x00003939), SkBits2Float(0x42487fff),  // 2.05276e-41f, 50.125f
217*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x48082361), SkBits2Float(0x4408e8e9),  // 139406, 547.639f
218*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x4d1ade0f));  // 1.6239e+08f
219*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(250, 250, path);
220*c8dee2aaSAndroid Build Coastguard Worker }
221*c8dee2aaSAndroid Build Coastguard Worker 
test_fuzz_crbug_662780()222*c8dee2aaSAndroid Build Coastguard Worker static void test_fuzz_crbug_662780() {
223*c8dee2aaSAndroid Build Coastguard Worker     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(250, 250)));
224*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = surface->getCanvas();
225*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
226*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(true);
227*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
228*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x41000000), SkBits2Float(0x431e0000));  // 8, 158
229*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x41000000), SkBits2Float(0x42f00000));  // 8, 120
230*c8dee2aaSAndroid Build Coastguard Worker     // 8, 8, 8.00002f, 8, 0.707107f
231*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0x41000000), SkBits2Float(0x41000000),
232*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x41000010), SkBits2Float(0x41000000), SkBits2Float(0x3f3504f3));
233*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x439a0000), SkBits2Float(0x41000000));  // 308, 8
234*c8dee2aaSAndroid Build Coastguard Worker     // 308, 8, 308, 8, 0.707107f
235*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0x439a0000), SkBits2Float(0x41000000),
236*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x439a0000), SkBits2Float(0x41000000), SkBits2Float(0x3f3504f3));
237*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x439a0000), SkBits2Float(0x431e0000));  // 308, 158
238*c8dee2aaSAndroid Build Coastguard Worker     // 308, 158, 308, 158, 0.707107f
239*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0x439a0000), SkBits2Float(0x431e0000),
240*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x439a0000), SkBits2Float(0x431e0000), SkBits2Float(0x3f3504f3));
241*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x41000000), SkBits2Float(0x431e0000));  // 8, 158
242*c8dee2aaSAndroid Build Coastguard Worker     // 8, 158, 8, 158, 0.707107f
243*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0x41000000), SkBits2Float(0x431e0000),
244*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x41000000), SkBits2Float(0x431e0000), SkBits2Float(0x3f3504f3));
245*c8dee2aaSAndroid Build Coastguard Worker     path.close();
246*c8dee2aaSAndroid Build Coastguard Worker     canvas->clipPath(path, true);
247*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRect(SkRect::MakeWH(250, 250), paint);
248*c8dee2aaSAndroid Build Coastguard Worker }
249*c8dee2aaSAndroid Build Coastguard Worker 
test_mask_overflow()250*c8dee2aaSAndroid Build Coastguard Worker static void test_mask_overflow() {
251*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
252*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x43e28000), SkBits2Float(0x43aa8000));  // 453, 341
253*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x43de6000), SkBits2Float(0x43aa8000));  // 444.75f, 341
254*c8dee2aaSAndroid Build Coastguard Worker     // 440.47f, 341, 437, 344.47f, 437, 348.75f
255*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(SkBits2Float(0x43dc3c29), SkBits2Float(0x43aa8000),
256*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x43da8000), SkBits2Float(0x43ac3c29),
257*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x43da8000), SkBits2Float(0x43ae6000));
258*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x43da8000), SkBits2Float(0x43b18000));  // 437, 355
259*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x43e28000), SkBits2Float(0x43b18000));  // 453, 355
260*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x43e28000), SkBits2Float(0x43aa8000));  // 453, 341
261*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(500, 500, path);
262*c8dee2aaSAndroid Build Coastguard Worker }
263*c8dee2aaSAndroid Build Coastguard Worker 
test_fuzz_crbug_668907()264*c8dee2aaSAndroid Build Coastguard Worker static void test_fuzz_crbug_668907() {
265*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
266*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x46313741), SkBits2Float(0x3b00e540));  // 11341.8f, 0.00196679f
267*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0x41410041), SkBits2Float(0xc1414141), SkBits2Float(0x41414141),
268*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x414100ff));  // 12.0626f, -12.0784f, 12.0784f, 12.0627f
269*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x46313741), SkBits2Float(0x3b00e540));  // 11341.8f, 0.00196679f
270*c8dee2aaSAndroid Build Coastguard Worker     path.close();
271*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(400, 500, path);
272*c8dee2aaSAndroid Build Coastguard Worker }
273*c8dee2aaSAndroid Build Coastguard Worker 
274*c8dee2aaSAndroid Build Coastguard Worker /**
275*c8dee2aaSAndroid Build Coastguard Worker  * In debug mode, this path was causing an assertion to fail in
276*c8dee2aaSAndroid Build Coastguard Worker  * SkPathStroker::preJoinTo() and, in Release, the use of an unitialized value.
277*c8dee2aaSAndroid Build Coastguard Worker  */
make_path_crbugskia2820(SkPath * path,skiatest::Reporter * reporter)278*c8dee2aaSAndroid Build Coastguard Worker static void make_path_crbugskia2820(SkPath* path, skiatest::Reporter* reporter) {
279*c8dee2aaSAndroid Build Coastguard Worker     SkPoint orig, p1, p2, p3;
280*c8dee2aaSAndroid Build Coastguard Worker     orig = SkPoint::Make(1.f, 1.f);
281*c8dee2aaSAndroid Build Coastguard Worker     p1 = SkPoint::Make(1.f - SK_ScalarNearlyZero, 1.f);
282*c8dee2aaSAndroid Build Coastguard Worker     p2 = SkPoint::Make(1.f, 1.f + SK_ScalarNearlyZero);
283*c8dee2aaSAndroid Build Coastguard Worker     p3 = SkPoint::Make(2.f, 2.f);
284*c8dee2aaSAndroid Build Coastguard Worker 
285*c8dee2aaSAndroid Build Coastguard Worker     path->reset();
286*c8dee2aaSAndroid Build Coastguard Worker     path->moveTo(orig);
287*c8dee2aaSAndroid Build Coastguard Worker     path->cubicTo(p1, p2, p3);
288*c8dee2aaSAndroid Build Coastguard Worker     path->close();
289*c8dee2aaSAndroid Build Coastguard Worker }
290*c8dee2aaSAndroid Build Coastguard Worker 
test_path_crbugskia2820(skiatest::Reporter * reporter)291*c8dee2aaSAndroid Build Coastguard Worker static void test_path_crbugskia2820(skiatest::Reporter* reporter) {
292*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
293*c8dee2aaSAndroid Build Coastguard Worker     make_path_crbugskia2820(&path, reporter);
294*c8dee2aaSAndroid Build Coastguard Worker 
295*c8dee2aaSAndroid Build Coastguard Worker     SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
296*c8dee2aaSAndroid Build Coastguard Worker     stroke.setStrokeStyle(2 * SK_Scalar1);
297*c8dee2aaSAndroid Build Coastguard Worker     stroke.applyToPath(&path, path);
298*c8dee2aaSAndroid Build Coastguard Worker }
299*c8dee2aaSAndroid Build Coastguard Worker 
test_path_crbugskia5995()300*c8dee2aaSAndroid Build Coastguard Worker static void test_path_crbugskia5995() {
301*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
302*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x40303030), SkBits2Float(0x3e303030));  // 2.75294f, 0.172059f
303*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0x41d63030), SkBits2Float(0x30303030), SkBits2Float(0x41013030),
304*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x00000000));  // 26.7735f, 6.40969e-10f, 8.07426f, 0
305*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000));  // 0, 0
306*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(500, 500, path);
307*c8dee2aaSAndroid Build Coastguard Worker }
308*c8dee2aaSAndroid Build Coastguard Worker 
make_path0(SkPath * path)309*c8dee2aaSAndroid Build Coastguard Worker static void make_path0(SkPath* path) {
310*c8dee2aaSAndroid Build Coastguard Worker     // from  *  https://code.google.com/p/skia/issues/detail?id=1706
311*c8dee2aaSAndroid Build Coastguard Worker 
312*c8dee2aaSAndroid Build Coastguard Worker     path->moveTo(146.939f, 1012.84f);
313*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(181.747f, 1009.18f);
314*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(182.165f, 1013.16f);
315*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(147.357f, 1016.82f);
316*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(146.939f, 1012.84f);
317*c8dee2aaSAndroid Build Coastguard Worker     path->close();
318*c8dee2aaSAndroid Build Coastguard Worker }
319*c8dee2aaSAndroid Build Coastguard Worker 
make_path1(SkPath * path)320*c8dee2aaSAndroid Build Coastguard Worker static void make_path1(SkPath* path) {
321*c8dee2aaSAndroid Build Coastguard Worker     path->addRect(SkRect::MakeXYWH(10, 10, 10, 1));
322*c8dee2aaSAndroid Build Coastguard Worker }
323*c8dee2aaSAndroid Build Coastguard Worker 
324*c8dee2aaSAndroid Build Coastguard Worker typedef void (*PathProc)(SkPath*);
325*c8dee2aaSAndroid Build Coastguard Worker 
326*c8dee2aaSAndroid Build Coastguard Worker /*
327*c8dee2aaSAndroid Build Coastguard Worker  *  Regression test: we used to crash (overwrite internal storage) during
328*c8dee2aaSAndroid Build Coastguard Worker  *  construction of the region when the path was INVERSE. That is now fixed,
329*c8dee2aaSAndroid Build Coastguard Worker  *  so test these regions (which used to assert/crash).
330*c8dee2aaSAndroid Build Coastguard Worker  *
331*c8dee2aaSAndroid Build Coastguard Worker  *  https://code.google.com/p/skia/issues/detail?id=1706
332*c8dee2aaSAndroid Build Coastguard Worker  */
test_path_to_region(skiatest::Reporter * reporter)333*c8dee2aaSAndroid Build Coastguard Worker static void test_path_to_region(skiatest::Reporter* reporter) {
334*c8dee2aaSAndroid Build Coastguard Worker     PathProc procs[] = {
335*c8dee2aaSAndroid Build Coastguard Worker         make_path0,
336*c8dee2aaSAndroid Build Coastguard Worker         make_path1,
337*c8dee2aaSAndroid Build Coastguard Worker     };
338*c8dee2aaSAndroid Build Coastguard Worker 
339*c8dee2aaSAndroid Build Coastguard Worker     SkRegion clip;
340*c8dee2aaSAndroid Build Coastguard Worker     clip.setRect({0, 0, 1255, 1925});
341*c8dee2aaSAndroid Build Coastguard Worker 
342*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < std::size(procs); ++i) {
343*c8dee2aaSAndroid Build Coastguard Worker         SkPath path;
344*c8dee2aaSAndroid Build Coastguard Worker         procs[i](&path);
345*c8dee2aaSAndroid Build Coastguard Worker 
346*c8dee2aaSAndroid Build Coastguard Worker         SkRegion rgn;
347*c8dee2aaSAndroid Build Coastguard Worker         rgn.setPath(path, clip);
348*c8dee2aaSAndroid Build Coastguard Worker         path.toggleInverseFillType();
349*c8dee2aaSAndroid Build Coastguard Worker         rgn.setPath(path, clip);
350*c8dee2aaSAndroid Build Coastguard Worker     }
351*c8dee2aaSAndroid Build Coastguard Worker }
352*c8dee2aaSAndroid Build Coastguard Worker 
353*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_BUILD_FOR_WIN
354*c8dee2aaSAndroid Build Coastguard Worker     #define SUPPRESS_VISIBILITY_WARNING
355*c8dee2aaSAndroid Build Coastguard Worker #else
356*c8dee2aaSAndroid Build Coastguard Worker     #define SUPPRESS_VISIBILITY_WARNING __attribute__((visibility("hidden")))
357*c8dee2aaSAndroid Build Coastguard Worker #endif
358*c8dee2aaSAndroid Build Coastguard Worker 
test_path_close_issue1474(skiatest::Reporter * reporter)359*c8dee2aaSAndroid Build Coastguard Worker static void test_path_close_issue1474(skiatest::Reporter* reporter) {
360*c8dee2aaSAndroid Build Coastguard Worker     // This test checks that r{Line,Quad,Conic,Cubic}To following a close()
361*c8dee2aaSAndroid Build Coastguard Worker     // are relative to the point we close to, not relative to the point we close from.
362*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
363*c8dee2aaSAndroid Build Coastguard Worker     SkPoint last;
364*c8dee2aaSAndroid Build Coastguard Worker 
365*c8dee2aaSAndroid Build Coastguard Worker     // Test rLineTo().
366*c8dee2aaSAndroid Build Coastguard Worker     path.rLineTo(0, 100);
367*c8dee2aaSAndroid Build Coastguard Worker     path.rLineTo(100, 0);
368*c8dee2aaSAndroid Build Coastguard Worker     path.close();          // Returns us back to 0,0.
369*c8dee2aaSAndroid Build Coastguard Worker     path.rLineTo(50, 50);  // This should go to 50,50.
370*c8dee2aaSAndroid Build Coastguard Worker 
371*c8dee2aaSAndroid Build Coastguard Worker     path.getLastPt(&last);
372*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, 50 == last.fX);
373*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, 50 == last.fY);
374*c8dee2aaSAndroid Build Coastguard Worker 
375*c8dee2aaSAndroid Build Coastguard Worker     // Test rQuadTo().
376*c8dee2aaSAndroid Build Coastguard Worker     path.rewind();
377*c8dee2aaSAndroid Build Coastguard Worker     path.rLineTo(0, 100);
378*c8dee2aaSAndroid Build Coastguard Worker     path.rLineTo(100, 0);
379*c8dee2aaSAndroid Build Coastguard Worker     path.close();
380*c8dee2aaSAndroid Build Coastguard Worker     path.rQuadTo(50, 50, 75, 75);
381*c8dee2aaSAndroid Build Coastguard Worker 
382*c8dee2aaSAndroid Build Coastguard Worker     path.getLastPt(&last);
383*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, 75 == last.fX);
384*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, 75 == last.fY);
385*c8dee2aaSAndroid Build Coastguard Worker 
386*c8dee2aaSAndroid Build Coastguard Worker     // Test rConicTo().
387*c8dee2aaSAndroid Build Coastguard Worker     path.rewind();
388*c8dee2aaSAndroid Build Coastguard Worker     path.rLineTo(0, 100);
389*c8dee2aaSAndroid Build Coastguard Worker     path.rLineTo(100, 0);
390*c8dee2aaSAndroid Build Coastguard Worker     path.close();
391*c8dee2aaSAndroid Build Coastguard Worker     path.rConicTo(50, 50, 85, 85, 2);
392*c8dee2aaSAndroid Build Coastguard Worker 
393*c8dee2aaSAndroid Build Coastguard Worker     path.getLastPt(&last);
394*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, 85 == last.fX);
395*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, 85 == last.fY);
396*c8dee2aaSAndroid Build Coastguard Worker 
397*c8dee2aaSAndroid Build Coastguard Worker     // Test rCubicTo().
398*c8dee2aaSAndroid Build Coastguard Worker     path.rewind();
399*c8dee2aaSAndroid Build Coastguard Worker     path.rLineTo(0, 100);
400*c8dee2aaSAndroid Build Coastguard Worker     path.rLineTo(100, 0);
401*c8dee2aaSAndroid Build Coastguard Worker     path.close();
402*c8dee2aaSAndroid Build Coastguard Worker     path.rCubicTo(50, 50, 85, 85, 95, 95);
403*c8dee2aaSAndroid Build Coastguard Worker 
404*c8dee2aaSAndroid Build Coastguard Worker     path.getLastPt(&last);
405*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, 95 == last.fX);
406*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, 95 == last.fY);
407*c8dee2aaSAndroid Build Coastguard Worker }
408*c8dee2aaSAndroid Build Coastguard Worker 
test_gen_id(skiatest::Reporter * reporter)409*c8dee2aaSAndroid Build Coastguard Worker static void test_gen_id(skiatest::Reporter* reporter) {
410*c8dee2aaSAndroid Build Coastguard Worker     SkPath a, b;
411*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, a.getGenerationID() == b.getGenerationID());
412*c8dee2aaSAndroid Build Coastguard Worker 
413*c8dee2aaSAndroid Build Coastguard Worker     a.moveTo(0, 0);
414*c8dee2aaSAndroid Build Coastguard Worker     const uint32_t z = a.getGenerationID();
415*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, z != b.getGenerationID());
416*c8dee2aaSAndroid Build Coastguard Worker 
417*c8dee2aaSAndroid Build Coastguard Worker     a.reset();
418*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, a.getGenerationID() == b.getGenerationID());
419*c8dee2aaSAndroid Build Coastguard Worker 
420*c8dee2aaSAndroid Build Coastguard Worker     a.moveTo(1, 1);
421*c8dee2aaSAndroid Build Coastguard Worker     const uint32_t y = a.getGenerationID();
422*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, z != y);
423*c8dee2aaSAndroid Build Coastguard Worker 
424*c8dee2aaSAndroid Build Coastguard Worker     b.moveTo(2, 2);
425*c8dee2aaSAndroid Build Coastguard Worker     const uint32_t x = b.getGenerationID();
426*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, x != y && x != z);
427*c8dee2aaSAndroid Build Coastguard Worker 
428*c8dee2aaSAndroid Build Coastguard Worker     a.swap(b);
429*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, b.getGenerationID() == y && a.getGenerationID() == x);
430*c8dee2aaSAndroid Build Coastguard Worker 
431*c8dee2aaSAndroid Build Coastguard Worker     b = a;
432*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, b.getGenerationID() == x);
433*c8dee2aaSAndroid Build Coastguard Worker 
434*c8dee2aaSAndroid Build Coastguard Worker     SkPath c(a);
435*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, c.getGenerationID() == x);
436*c8dee2aaSAndroid Build Coastguard Worker 
437*c8dee2aaSAndroid Build Coastguard Worker     c.lineTo(3, 3);
438*c8dee2aaSAndroid Build Coastguard Worker     const uint32_t w = c.getGenerationID();
439*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, b.getGenerationID() == x);
440*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, a.getGenerationID() == x);
441*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, w != x);
442*c8dee2aaSAndroid Build Coastguard Worker 
443*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
444*c8dee2aaSAndroid Build Coastguard Worker     static bool kExpectGenIDToIgnoreFill = false;
445*c8dee2aaSAndroid Build Coastguard Worker #else
446*c8dee2aaSAndroid Build Coastguard Worker     static bool kExpectGenIDToIgnoreFill = true;
447*c8dee2aaSAndroid Build Coastguard Worker #endif
448*c8dee2aaSAndroid Build Coastguard Worker 
449*c8dee2aaSAndroid Build Coastguard Worker     c.toggleInverseFillType();
450*c8dee2aaSAndroid Build Coastguard Worker     const uint32_t v = c.getGenerationID();
451*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, (v == w) == kExpectGenIDToIgnoreFill);
452*c8dee2aaSAndroid Build Coastguard Worker 
453*c8dee2aaSAndroid Build Coastguard Worker     c.rewind();
454*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, v != c.getGenerationID());
455*c8dee2aaSAndroid Build Coastguard Worker }
456*c8dee2aaSAndroid Build Coastguard Worker 
457*c8dee2aaSAndroid Build Coastguard Worker // This used to assert in the debug build, as the edges did not all line-up.
test_bad_cubic_crbug234190()458*c8dee2aaSAndroid Build Coastguard Worker static void test_bad_cubic_crbug234190() {
459*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
460*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(13.8509f, 3.16858f);
461*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(-2.35893e+08f, -4.21044e+08f,
462*c8dee2aaSAndroid Build Coastguard Worker                  -2.38991e+08f, -4.26573e+08f,
463*c8dee2aaSAndroid Build Coastguard Worker                  -2.41016e+08f, -4.30188e+08f);
464*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(84, 88, path);
465*c8dee2aaSAndroid Build Coastguard Worker }
466*c8dee2aaSAndroid Build Coastguard Worker 
test_bad_cubic_crbug229478()467*c8dee2aaSAndroid Build Coastguard Worker static void test_bad_cubic_crbug229478() {
468*c8dee2aaSAndroid Build Coastguard Worker     const SkPoint pts[] = {
469*c8dee2aaSAndroid Build Coastguard Worker         { 4595.91064f,    -11596.9873f },
470*c8dee2aaSAndroid Build Coastguard Worker         { 4597.2168f,    -11595.9414f },
471*c8dee2aaSAndroid Build Coastguard Worker         { 4598.52344f,    -11594.8955f },
472*c8dee2aaSAndroid Build Coastguard Worker         { 4599.83008f,    -11593.8496f },
473*c8dee2aaSAndroid Build Coastguard Worker     };
474*c8dee2aaSAndroid Build Coastguard Worker 
475*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
476*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(pts[0]);
477*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(pts[1], pts[2], pts[3]);
478*c8dee2aaSAndroid Build Coastguard Worker 
479*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
480*c8dee2aaSAndroid Build Coastguard Worker     paint.setStyle(SkPaint::kStroke_Style);
481*c8dee2aaSAndroid Build Coastguard Worker     paint.setStrokeWidth(20);
482*c8dee2aaSAndroid Build Coastguard Worker 
483*c8dee2aaSAndroid Build Coastguard Worker     SkPath dst;
484*c8dee2aaSAndroid Build Coastguard Worker     // Before the fix, this would infinite-recurse, and run out of stack
485*c8dee2aaSAndroid Build Coastguard Worker     // because we would keep trying to subdivide a degenerate cubic segment.
486*c8dee2aaSAndroid Build Coastguard Worker     skpathutils::FillPathWithPaint(path, paint, &dst, nullptr);
487*c8dee2aaSAndroid Build Coastguard Worker }
488*c8dee2aaSAndroid Build Coastguard Worker 
build_path_170666(SkPath & path)489*c8dee2aaSAndroid Build Coastguard Worker static void build_path_170666(SkPath& path) {
490*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(17.9459f, 21.6344f);
491*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(139.545f, -47.8105f);
492*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(139.545f, -47.8105f);
493*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(131.07f, -47.3888f);
494*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(131.07f, -47.3888f);
495*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(122.586f, -46.9532f);
496*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(122.586f, -46.9532f);
497*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(18076.6f, 31390.9f);
498*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(18076.6f, 31390.9f);
499*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(18085.1f, 31390.5f);
500*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(18085.1f, 31390.5f);
501*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(18076.6f, 31390.9f);
502*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(18076.6f, 31390.9f);
503*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(17955, 31460.3f);
504*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(17955, 31460.3f);
505*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(17963.5f, 31459.9f);
506*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(17963.5f, 31459.9f);
507*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(17971.9f, 31459.5f);
508*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(17971.9f, 31459.5f);
509*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(17.9551f, 21.6205f);
510*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(17.9551f, 21.6205f);
511*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(9.47091f, 22.0561f);
512*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(9.47091f, 22.0561f);
513*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(17.9459f, 21.6344f);
514*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(17.9459f, 21.6344f);
515*c8dee2aaSAndroid Build Coastguard Worker     path.close();path.moveTo(0.995934f, 22.4779f);
516*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0.986725f, 22.4918f);
517*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0.986725f, 22.4918f);
518*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(17955, 31460.4f);
519*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(17955, 31460.4f);
520*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(17971.9f, 31459.5f);
521*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(17971.9f, 31459.5f);
522*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(18093.6f, 31390.1f);
523*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(18093.6f, 31390.1f);
524*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(18093.6f, 31390);
525*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(18093.6f, 31390);
526*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(139.555f, -47.8244f);
527*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(139.555f, -47.8244f);
528*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(122.595f, -46.9671f);
529*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(122.595f, -46.9671f);
530*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0.995934f, 22.4779f);
531*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0.995934f, 22.4779f);
532*c8dee2aaSAndroid Build Coastguard Worker     path.close();
533*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(5.43941f, 25.5223f);
534*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(798267, -28871.1f);
535*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(798267, -28871.1f);
536*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(3.12512e+06f, -113102);
537*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(3.12512e+06f, -113102);
538*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(5.16324e+06f, -186882, 8.15247e+06f, -295092, 1.1957e+07f, -432813);
539*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(1.95659e+07f, -708257, 3.04359e+07f, -1.10175e+06f, 4.34798e+07f, -1.57394e+06f);
540*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(6.95677e+07f, -2.51831e+06f, 1.04352e+08f, -3.77748e+06f, 1.39135e+08f, -5.03666e+06f);
541*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(1.73919e+08f, -6.29583e+06f, 2.08703e+08f, -7.555e+06f, 2.34791e+08f, -8.49938e+06f);
542*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(2.47835e+08f, -8.97157e+06f, 2.58705e+08f, -9.36506e+06f, 2.66314e+08f, -9.6405e+06f);
543*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(2.70118e+08f, -9.77823e+06f, 2.73108e+08f, -9.88644e+06f, 2.75146e+08f, -9.96022e+06f);
544*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(2.76165e+08f, -9.99711e+06f, 2.76946e+08f, -1.00254e+07f, 2.77473e+08f, -1.00444e+07f);
545*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(2.78271e+08f, -1.00733e+07f);
546*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(2.78271e+08f, -1.00733e+07f);
547*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(2.78271e+08f, -1.00733e+07f, 2.08703e+08f, -7.555e+06f, 135.238f, 23.3517f);
548*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(131.191f, 23.4981f, 125.995f, 23.7976f, 123.631f, 24.0206f);
549*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(121.267f, 24.2436f, 122.631f, 24.3056f, 126.677f, 24.1591f);
550*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(2.08703e+08f, -7.555e+06f, 2.78271e+08f, -1.00733e+07f, 2.78271e+08f, -1.00733e+07f);
551*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(2.77473e+08f, -1.00444e+07f);
552*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(2.77473e+08f, -1.00444e+07f);
553*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(2.76946e+08f, -1.00254e+07f, 2.76165e+08f, -9.99711e+06f, 2.75146e+08f, -9.96022e+06f);
554*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(2.73108e+08f, -9.88644e+06f, 2.70118e+08f, -9.77823e+06f, 2.66314e+08f, -9.6405e+06f);
555*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(2.58705e+08f, -9.36506e+06f, 2.47835e+08f, -8.97157e+06f, 2.34791e+08f, -8.49938e+06f);
556*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(2.08703e+08f, -7.555e+06f, 1.73919e+08f, -6.29583e+06f, 1.39135e+08f, -5.03666e+06f);
557*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(1.04352e+08f, -3.77749e+06f, 6.95677e+07f, -2.51831e+06f, 4.34798e+07f, -1.57394e+06f);
558*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(3.04359e+07f, -1.10175e+06f, 1.95659e+07f, -708258, 1.1957e+07f, -432814);
559*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(8.15248e+06f, -295092, 5.16324e+06f, -186883, 3.12513e+06f, -113103);
560*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(798284, -28872);
561*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(798284, -28872);
562*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(22.4044f, 24.6677f);
563*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(22.4044f, 24.6677f);
564*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(22.5186f, 24.5432f, 18.8134f, 24.6337f, 14.1287f, 24.8697f);
565*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(9.4439f, 25.1057f, 5.55359f, 25.3978f, 5.43941f, 25.5223f);
566*c8dee2aaSAndroid Build Coastguard Worker     path.close();
567*c8dee2aaSAndroid Build Coastguard Worker }
568*c8dee2aaSAndroid Build Coastguard Worker 
build_path_simple_170666(SkPath & path)569*c8dee2aaSAndroid Build Coastguard Worker static void build_path_simple_170666(SkPath& path) {
570*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(126.677f, 24.1591f);
571*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(2.08703e+08f, -7.555e+06f, 2.78271e+08f, -1.00733e+07f, 2.78271e+08f, -1.00733e+07f);
572*c8dee2aaSAndroid Build Coastguard Worker }
573*c8dee2aaSAndroid Build Coastguard Worker 
574*c8dee2aaSAndroid Build Coastguard Worker // This used to assert in the SK_DEBUG build, as the clip step would fail with
575*c8dee2aaSAndroid Build Coastguard Worker // too-few interations in our cubic-line intersection code. That code now runs
576*c8dee2aaSAndroid Build Coastguard Worker // 24 interations (instead of 16).
test_crbug_170666()577*c8dee2aaSAndroid Build Coastguard Worker static void test_crbug_170666() {
578*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
579*c8dee2aaSAndroid Build Coastguard Worker     build_path_simple_170666(path);
580*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(1000, 1000, path);
581*c8dee2aaSAndroid Build Coastguard Worker 
582*c8dee2aaSAndroid Build Coastguard Worker     build_path_170666(path);
583*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(1000, 1000, path);
584*c8dee2aaSAndroid Build Coastguard Worker }
585*c8dee2aaSAndroid Build Coastguard Worker 
586*c8dee2aaSAndroid Build Coastguard Worker 
test_tiny_path_convexity(skiatest::Reporter * reporter,const char * pathBug,SkScalar tx,SkScalar ty,SkScalar scale)587*c8dee2aaSAndroid Build Coastguard Worker static void test_tiny_path_convexity(skiatest::Reporter* reporter, const char* pathBug,
588*c8dee2aaSAndroid Build Coastguard Worker         SkScalar tx, SkScalar ty, SkScalar scale) {
589*c8dee2aaSAndroid Build Coastguard Worker     SkPath smallPath;
590*c8dee2aaSAndroid Build Coastguard Worker     SkAssertResult(SkParsePath::FromSVGString(pathBug, &smallPath));
591*c8dee2aaSAndroid Build Coastguard Worker     bool smallConvex = smallPath.isConvex();
592*c8dee2aaSAndroid Build Coastguard Worker     SkPath largePath;
593*c8dee2aaSAndroid Build Coastguard Worker     SkAssertResult(SkParsePath::FromSVGString(pathBug, &largePath));
594*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix matrix;
595*c8dee2aaSAndroid Build Coastguard Worker     matrix.reset();
596*c8dee2aaSAndroid Build Coastguard Worker     matrix.preTranslate(100, 100);
597*c8dee2aaSAndroid Build Coastguard Worker     matrix.preScale(scale, scale);
598*c8dee2aaSAndroid Build Coastguard Worker     largePath.transform(matrix);
599*c8dee2aaSAndroid Build Coastguard Worker     bool largeConvex = largePath.isConvex();
600*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, smallConvex == largeConvex);
601*c8dee2aaSAndroid Build Coastguard Worker }
602*c8dee2aaSAndroid Build Coastguard Worker 
test_crbug_493450(skiatest::Reporter * reporter)603*c8dee2aaSAndroid Build Coastguard Worker static void test_crbug_493450(skiatest::Reporter* reporter) {
604*c8dee2aaSAndroid Build Coastguard Worker     const char reducedCase[] =
605*c8dee2aaSAndroid Build Coastguard Worker         "M0,0"
606*c8dee2aaSAndroid Build Coastguard Worker         "L0.0002, 0"
607*c8dee2aaSAndroid Build Coastguard Worker         "L0.0002, 0.0002"
608*c8dee2aaSAndroid Build Coastguard Worker         "L0.0001, 0.0001"
609*c8dee2aaSAndroid Build Coastguard Worker         "L0,0.0002"
610*c8dee2aaSAndroid Build Coastguard Worker         "Z";
611*c8dee2aaSAndroid Build Coastguard Worker     test_tiny_path_convexity(reporter, reducedCase, 100, 100, 100000);
612*c8dee2aaSAndroid Build Coastguard Worker     const char originalFiddleData[] =
613*c8dee2aaSAndroid Build Coastguard Worker         "M-0.3383152268862998,-0.11217565719203619L-0.33846085183212765,-0.11212264406895281"
614*c8dee2aaSAndroid Build Coastguard Worker         "L-0.338509393480737,-0.11210607966681395L-0.33857792286700894,-0.1121889121487573"
615*c8dee2aaSAndroid Build Coastguard Worker         "L-0.3383866116636664,-0.11228834570924921L-0.33842087635680235,-0.11246078673250548"
616*c8dee2aaSAndroid Build Coastguard Worker         "L-0.33809536177201055,-0.11245415228342878L-0.33797257995493996,-0.11216571641452182"
617*c8dee2aaSAndroid Build Coastguard Worker         "L-0.33802112160354925,-0.11201996164188659L-0.33819815585141844,-0.11218559834671019Z";
618*c8dee2aaSAndroid Build Coastguard Worker     test_tiny_path_convexity(reporter, originalFiddleData, 280081.4116670522f, 93268.04618493588f,
619*c8dee2aaSAndroid Build Coastguard Worker             826357.3384828606f);
620*c8dee2aaSAndroid Build Coastguard Worker }
621*c8dee2aaSAndroid Build Coastguard Worker 
test_crbug_495894(skiatest::Reporter * reporter)622*c8dee2aaSAndroid Build Coastguard Worker static void test_crbug_495894(skiatest::Reporter* reporter) {
623*c8dee2aaSAndroid Build Coastguard Worker     const char originalFiddleData[] =
624*c8dee2aaSAndroid Build Coastguard Worker         "M-0.34004273849857214,-0.11332803232216355L-0.34008271397389744,-0.11324483772714951"
625*c8dee2aaSAndroid Build Coastguard Worker         "L-0.3401940742265893,-0.11324483772714951L-0.34017694188002134,-0.11329807920275889"
626*c8dee2aaSAndroid Build Coastguard Worker         "L-0.3402026403998733,-0.11333468903941245L-0.34029972369709194,-0.11334134592705701"
627*c8dee2aaSAndroid Build Coastguard Worker         "L-0.3403054344792813,-0.11344121970007795L-0.3403140006525653,-0.11351115418399343"
628*c8dee2aaSAndroid Build Coastguard Worker         "L-0.34024261587519866,-0.11353446986281181L-0.3402197727464413,-0.11360442946144192"
629*c8dee2aaSAndroid Build Coastguard Worker         "L-0.34013696640469604,-0.11359110237029302L-0.34009128014718143,-0.1135877707043939"
630*c8dee2aaSAndroid Build Coastguard Worker         "L-0.3400598708451401,-0.11360776134112742L-0.34004273849857214,-0.11355112520064405"
631*c8dee2aaSAndroid Build Coastguard Worker         "L-0.3400113291965308,-0.11355112520064405L-0.3399970522410575,-0.11359110237029302"
632*c8dee2aaSAndroid Build Coastguard Worker         "L-0.33997135372120546,-0.11355112520064405L-0.3399627875479215,-0.11353780084493197"
633*c8dee2aaSAndroid Build Coastguard Worker         "L-0.3399485105924481,-0.11350782354357004L-0.3400027630232468,-0.11346452910331437"
634*c8dee2aaSAndroid Build Coastguard Worker         "L-0.3399485105924481,-0.11340126558629839L-0.33993994441916414,-0.11340126558629839"
635*c8dee2aaSAndroid Build Coastguard Worker         "L-0.33988283659727087,-0.11331804756574679L-0.33989140277055485,-0.11324483772714951"
636*c8dee2aaSAndroid Build Coastguard Worker         "L-0.33997991989448945,-0.11324483772714951L-0.3399856306766788,-0.11324483772714951"
637*c8dee2aaSAndroid Build Coastguard Worker         "L-0.34002560615200417,-0.11334467443478255ZM-0.3400684370184241,-0.11338461985124307"
638*c8dee2aaSAndroid Build Coastguard Worker         "L-0.340154098751264,-0.11341791238732665L-0.340162664924548,-0.1134378899559977"
639*c8dee2aaSAndroid Build Coastguard Worker         "L-0.34017979727111597,-0.11340126558629839L-0.3401655203156427,-0.11338129083212668"
640*c8dee2aaSAndroid Build Coastguard Worker         "L-0.34012268944922275,-0.11332137577529414L-0.34007414780061346,-0.11334467443478255Z"
641*c8dee2aaSAndroid Build Coastguard Worker         "M-0.3400027630232468,-0.11290567901106024L-0.3400113291965308,-0.11298876531245433"
642*c8dee2aaSAndroid Build Coastguard Worker         "L-0.33997991989448945,-0.11301535852306784L-0.33990282433493346,-0.11296217481488612"
643*c8dee2aaSAndroid Build Coastguard Worker         "L-0.33993994441916414,-0.11288906492739594Z";
644*c8dee2aaSAndroid Build Coastguard Worker     test_tiny_path_convexity(reporter, originalFiddleData, 22682.240000000005f,7819.72220766405f,
645*c8dee2aaSAndroid Build Coastguard Worker             65536);
646*c8dee2aaSAndroid Build Coastguard Worker }
647*c8dee2aaSAndroid Build Coastguard Worker 
test_crbug_613918()648*c8dee2aaSAndroid Build Coastguard Worker static void test_crbug_613918() {
649*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
650*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(-6.62478e-08f, 4.13885e-08f, -6.36935e-08f, 3.97927e-08f, 0.729058f);
651*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(2.28206e-09f, -1.42572e-09f, 3.91919e-09f, -2.44852e-09f);
652*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(-16752.2f, -26792.9f, -21.4673f, 10.9347f, -8.57322f, -7.22739f);
653*c8dee2aaSAndroid Build Coastguard Worker 
654*c8dee2aaSAndroid Build Coastguard Worker     // This call could lead to an assert or uninitialized read due to a failure
655*c8dee2aaSAndroid Build Coastguard Worker     // to check the return value from SkCubicClipper::ChopMonoAtY.
656*c8dee2aaSAndroid Build Coastguard Worker     path.contains(-1.84817e-08f, 1.15465e-08f);
657*c8dee2aaSAndroid Build Coastguard Worker }
658*c8dee2aaSAndroid Build Coastguard Worker 
test_addrect(skiatest::Reporter * reporter)659*c8dee2aaSAndroid Build Coastguard Worker static void test_addrect(skiatest::Reporter* reporter) {
660*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
661*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0, 0);
662*c8dee2aaSAndroid Build Coastguard Worker     path.addRect(SkRect::MakeWH(50, 100));
663*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isRect(nullptr));
664*c8dee2aaSAndroid Build Coastguard Worker 
665*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
666*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(FLT_EPSILON, FLT_EPSILON);
667*c8dee2aaSAndroid Build Coastguard Worker     path.addRect(SkRect::MakeWH(50, 100));
668*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isRect(nullptr));
669*c8dee2aaSAndroid Build Coastguard Worker 
670*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
671*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(0, 0, 0, 0);
672*c8dee2aaSAndroid Build Coastguard Worker     path.addRect(SkRect::MakeWH(50, 100));
673*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isRect(nullptr));
674*c8dee2aaSAndroid Build Coastguard Worker 
675*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
676*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(0, 0, 0, 0, 0.5f);
677*c8dee2aaSAndroid Build Coastguard Worker     path.addRect(SkRect::MakeWH(50, 100));
678*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isRect(nullptr));
679*c8dee2aaSAndroid Build Coastguard Worker 
680*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
681*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(0, 0, 0, 0, 0, 0);
682*c8dee2aaSAndroid Build Coastguard Worker     path.addRect(SkRect::MakeWH(50, 100));
683*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isRect(nullptr));
684*c8dee2aaSAndroid Build Coastguard Worker }
685*c8dee2aaSAndroid Build Coastguard Worker 
686*c8dee2aaSAndroid Build Coastguard Worker // Make sure we stay non-finite once we get there (unless we reset or rewind).
test_addrect_isfinite(skiatest::Reporter * reporter)687*c8dee2aaSAndroid Build Coastguard Worker static void test_addrect_isfinite(skiatest::Reporter* reporter) {
688*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
689*c8dee2aaSAndroid Build Coastguard Worker 
690*c8dee2aaSAndroid Build Coastguard Worker     path.addRect(SkRect::MakeWH(50, 100));
691*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isFinite());
692*c8dee2aaSAndroid Build Coastguard Worker 
693*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0);
694*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SK_ScalarInfinity, 42);
695*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isFinite());
696*c8dee2aaSAndroid Build Coastguard Worker 
697*c8dee2aaSAndroid Build Coastguard Worker     path.addRect(SkRect::MakeWH(50, 100));
698*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isFinite());
699*c8dee2aaSAndroid Build Coastguard Worker 
700*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
701*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isFinite());
702*c8dee2aaSAndroid Build Coastguard Worker 
703*c8dee2aaSAndroid Build Coastguard Worker     path.addRect(SkRect::MakeWH(50, 100));
704*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isFinite());
705*c8dee2aaSAndroid Build Coastguard Worker }
706*c8dee2aaSAndroid Build Coastguard Worker 
build_big_path(SkPath * path,bool reducedCase)707*c8dee2aaSAndroid Build Coastguard Worker static void build_big_path(SkPath* path, bool reducedCase) {
708*c8dee2aaSAndroid Build Coastguard Worker     if (reducedCase) {
709*c8dee2aaSAndroid Build Coastguard Worker         path->moveTo(577330, 1971.72f);
710*c8dee2aaSAndroid Build Coastguard Worker         path->cubicTo(10.7082f, -116.596f, 262.057f, 45.6468f, 294.694f, 1.96237f);
711*c8dee2aaSAndroid Build Coastguard Worker     } else {
712*c8dee2aaSAndroid Build Coastguard Worker         path->moveTo(60.1631f, 7.70567f);
713*c8dee2aaSAndroid Build Coastguard Worker         path->quadTo(60.1631f, 7.70567f, 0.99474f, 0.901199f);
714*c8dee2aaSAndroid Build Coastguard Worker         path->lineTo(577379, 1977.77f);
715*c8dee2aaSAndroid Build Coastguard Worker         path->quadTo(577364, 1979.57f, 577325, 1980.26f);
716*c8dee2aaSAndroid Build Coastguard Worker         path->quadTo(577286, 1980.95f, 577245, 1980.13f);
717*c8dee2aaSAndroid Build Coastguard Worker         path->quadTo(577205, 1979.3f, 577187, 1977.45f);
718*c8dee2aaSAndroid Build Coastguard Worker         path->quadTo(577168, 1975.6f, 577183, 1973.8f);
719*c8dee2aaSAndroid Build Coastguard Worker         path->quadTo(577198, 1972, 577238, 1971.31f);
720*c8dee2aaSAndroid Build Coastguard Worker         path->quadTo(577277, 1970.62f, 577317, 1971.45f);
721*c8dee2aaSAndroid Build Coastguard Worker         path->quadTo(577330, 1971.72f, 577341, 1972.11f);
722*c8dee2aaSAndroid Build Coastguard Worker         path->cubicTo(10.7082f, -116.596f, 262.057f, 45.6468f, 294.694f, 1.96237f);
723*c8dee2aaSAndroid Build Coastguard Worker         path->moveTo(306.718f, -32.912f);
724*c8dee2aaSAndroid Build Coastguard Worker         path->cubicTo(30.531f, 10.0005f, 1502.47f, 13.2804f, 84.3088f, 9.99601f);
725*c8dee2aaSAndroid Build Coastguard Worker     }
726*c8dee2aaSAndroid Build Coastguard Worker }
727*c8dee2aaSAndroid Build Coastguard Worker 
test_clipped_cubic()728*c8dee2aaSAndroid Build Coastguard Worker static void test_clipped_cubic() {
729*c8dee2aaSAndroid Build Coastguard Worker     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(640, 480)));
730*c8dee2aaSAndroid Build Coastguard Worker 
731*c8dee2aaSAndroid Build Coastguard Worker     // This path used to assert, because our cubic-chopping code incorrectly
732*c8dee2aaSAndroid Build Coastguard Worker     // moved control points after the chop. This test should be run in SK_DEBUG
733*c8dee2aaSAndroid Build Coastguard Worker     // mode to ensure that we no long assert.
734*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
735*c8dee2aaSAndroid Build Coastguard Worker     for (int doReducedCase = 0; doReducedCase <= 1; ++doReducedCase) {
736*c8dee2aaSAndroid Build Coastguard Worker         build_big_path(&path, SkToBool(doReducedCase));
737*c8dee2aaSAndroid Build Coastguard Worker 
738*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
739*c8dee2aaSAndroid Build Coastguard Worker         for (int doAA = 0; doAA <= 1; ++doAA) {
740*c8dee2aaSAndroid Build Coastguard Worker             paint.setAntiAlias(SkToBool(doAA));
741*c8dee2aaSAndroid Build Coastguard Worker             surface->getCanvas()->drawPath(path, paint);
742*c8dee2aaSAndroid Build Coastguard Worker         }
743*c8dee2aaSAndroid Build Coastguard Worker     }
744*c8dee2aaSAndroid Build Coastguard Worker }
745*c8dee2aaSAndroid Build Coastguard Worker 
dump_if_ne(skiatest::Reporter * reporter,const SkRect & expected,const SkRect & bounds)746*c8dee2aaSAndroid Build Coastguard Worker static void dump_if_ne(skiatest::Reporter* reporter, const SkRect& expected, const SkRect& bounds) {
747*c8dee2aaSAndroid Build Coastguard Worker     if (expected != bounds) {
748*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "path.getBounds() returned [%g %g %g %g], but expected [%g %g %g %g]",
749*c8dee2aaSAndroid Build Coastguard Worker                bounds.left(), bounds.top(), bounds.right(), bounds.bottom(),
750*c8dee2aaSAndroid Build Coastguard Worker                expected.left(), expected.top(), expected.right(), expected.bottom());
751*c8dee2aaSAndroid Build Coastguard Worker     }
752*c8dee2aaSAndroid Build Coastguard Worker }
753*c8dee2aaSAndroid Build Coastguard Worker 
test_bounds_crbug_513799(skiatest::Reporter * reporter)754*c8dee2aaSAndroid Build Coastguard Worker static void test_bounds_crbug_513799(skiatest::Reporter* reporter) {
755*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
756*c8dee2aaSAndroid Build Coastguard Worker #if 0
757*c8dee2aaSAndroid Build Coastguard Worker     // As written these tests were failing on LLVM 4.2 MacMini Release mysteriously, so we've
758*c8dee2aaSAndroid Build Coastguard Worker     // rewritten them to avoid this (compiler-bug?).
759*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkRect::MakeLTRB(0, 0, 0, 0) == path.getBounds());
760*c8dee2aaSAndroid Build Coastguard Worker 
761*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(-5, -8);
762*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkRect::MakeLTRB(-5, -8, -5, -8) == path.getBounds());
763*c8dee2aaSAndroid Build Coastguard Worker 
764*c8dee2aaSAndroid Build Coastguard Worker     path.addRect(SkRect::MakeLTRB(1, 2, 3, 4));
765*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkRect::MakeLTRB(-5, -8, 3, 4) == path.getBounds());
766*c8dee2aaSAndroid Build Coastguard Worker 
767*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(1, 2);
768*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkRect::MakeLTRB(-5, -8, 3, 4) == path.getBounds());
769*c8dee2aaSAndroid Build Coastguard Worker #else
770*c8dee2aaSAndroid Build Coastguard Worker     dump_if_ne(reporter, SkRect::MakeLTRB(0, 0, 0, 0), path.getBounds());
771*c8dee2aaSAndroid Build Coastguard Worker 
772*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(-5, -8);    // should set the bounds
773*c8dee2aaSAndroid Build Coastguard Worker     dump_if_ne(reporter, SkRect::MakeLTRB(-5, -8, -5, -8), path.getBounds());
774*c8dee2aaSAndroid Build Coastguard Worker 
775*c8dee2aaSAndroid Build Coastguard Worker     path.addRect(SkRect::MakeLTRB(1, 2, 3, 4)); // should extend the bounds
776*c8dee2aaSAndroid Build Coastguard Worker     dump_if_ne(reporter, SkRect::MakeLTRB(-5, -8, 3, 4), path.getBounds());
777*c8dee2aaSAndroid Build Coastguard Worker 
778*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(1, 2);  // don't expect this to have changed the bounds
779*c8dee2aaSAndroid Build Coastguard Worker     dump_if_ne(reporter, SkRect::MakeLTRB(-5, -8, 3, 4), path.getBounds());
780*c8dee2aaSAndroid Build Coastguard Worker #endif
781*c8dee2aaSAndroid Build Coastguard Worker }
782*c8dee2aaSAndroid Build Coastguard Worker 
test_fuzz_crbug_627414(skiatest::Reporter * reporter)783*c8dee2aaSAndroid Build Coastguard Worker static void test_fuzz_crbug_627414(skiatest::Reporter* reporter) {
784*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
785*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0);
786*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(3.58732e-43f, 2.72084f, 3.00392f, 3.00392f, 8.46e+37f);
787*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(100, 100, path);
788*c8dee2aaSAndroid Build Coastguard Worker }
789*c8dee2aaSAndroid Build Coastguard Worker 
790*c8dee2aaSAndroid Build Coastguard Worker // Inspired by http://ie.microsoft.com/testdrive/Performance/Chalkboard/
791*c8dee2aaSAndroid Build Coastguard Worker // which triggered an assert, from a tricky cubic. This test replicates that
792*c8dee2aaSAndroid Build Coastguard Worker // example, so we can ensure that we handle it (in SkEdge.cpp), and don't
793*c8dee2aaSAndroid Build Coastguard Worker // assert in the SK_DEBUG build.
test_tricky_cubic()794*c8dee2aaSAndroid Build Coastguard Worker static void test_tricky_cubic() {
795*c8dee2aaSAndroid Build Coastguard Worker     const SkPoint pts[] = {
796*c8dee2aaSAndroid Build Coastguard Worker         { SkDoubleToScalar(18.8943768),    SkDoubleToScalar(129.121277) },
797*c8dee2aaSAndroid Build Coastguard Worker         { SkDoubleToScalar(18.8937435),    SkDoubleToScalar(129.121689) },
798*c8dee2aaSAndroid Build Coastguard Worker         { SkDoubleToScalar(18.8950119),    SkDoubleToScalar(129.120422) },
799*c8dee2aaSAndroid Build Coastguard Worker         { SkDoubleToScalar(18.5030727),    SkDoubleToScalar(129.13121)  },
800*c8dee2aaSAndroid Build Coastguard Worker     };
801*c8dee2aaSAndroid Build Coastguard Worker 
802*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
803*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(pts[0]);
804*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(pts[1], pts[2], pts[3]);
805*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(19, 130, path);
806*c8dee2aaSAndroid Build Coastguard Worker }
807*c8dee2aaSAndroid Build Coastguard Worker 
808*c8dee2aaSAndroid Build Coastguard Worker // Inspired by http://code.google.com/p/chromium/issues/detail?id=141651
809*c8dee2aaSAndroid Build Coastguard Worker //
test_isfinite_after_transform(skiatest::Reporter * reporter)810*c8dee2aaSAndroid Build Coastguard Worker static void test_isfinite_after_transform(skiatest::Reporter* reporter) {
811*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
812*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(157, 366, 286, 208);
813*c8dee2aaSAndroid Build Coastguard Worker     path.arcTo(37, 442, 315, 163, 957494590897113.0f);
814*c8dee2aaSAndroid Build Coastguard Worker 
815*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix matrix;
816*c8dee2aaSAndroid Build Coastguard Worker     matrix.setScale(1000*1000, 1000*1000);
817*c8dee2aaSAndroid Build Coastguard Worker 
818*c8dee2aaSAndroid Build Coastguard Worker     // Be sure that path::transform correctly updates isFinite and the bounds
819*c8dee2aaSAndroid Build Coastguard Worker     // if the transformation overflows. The previous bug was that isFinite was
820*c8dee2aaSAndroid Build Coastguard Worker     // set to true in this case, but the bounds were not set to empty (which
821*c8dee2aaSAndroid Build Coastguard Worker     // they should be).
822*c8dee2aaSAndroid Build Coastguard Worker     while (path.isFinite()) {
823*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, path.getBounds().isFinite());
824*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !path.getBounds().isEmpty());
825*c8dee2aaSAndroid Build Coastguard Worker         path.transform(matrix);
826*c8dee2aaSAndroid Build Coastguard Worker     }
827*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.getBounds().isEmpty());
828*c8dee2aaSAndroid Build Coastguard Worker 
829*c8dee2aaSAndroid Build Coastguard Worker     matrix.setTranslate(SK_Scalar1, SK_Scalar1);
830*c8dee2aaSAndroid Build Coastguard Worker     path.transform(matrix);
831*c8dee2aaSAndroid Build Coastguard Worker     // we need to still be non-finite
832*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isFinite());
833*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.getBounds().isEmpty());
834*c8dee2aaSAndroid Build Coastguard Worker }
835*c8dee2aaSAndroid Build Coastguard Worker 
add_corner_arc(SkPath * path,const SkRect & rect,SkScalar xIn,SkScalar yIn,int startAngle)836*c8dee2aaSAndroid Build Coastguard Worker static void add_corner_arc(SkPath* path, const SkRect& rect,
837*c8dee2aaSAndroid Build Coastguard Worker                            SkScalar xIn, SkScalar yIn,
838*c8dee2aaSAndroid Build Coastguard Worker                            int startAngle)
839*c8dee2aaSAndroid Build Coastguard Worker {
840*c8dee2aaSAndroid Build Coastguard Worker 
841*c8dee2aaSAndroid Build Coastguard Worker     SkScalar rx = std::min(rect.width(), xIn);
842*c8dee2aaSAndroid Build Coastguard Worker     SkScalar ry = std::min(rect.height(), yIn);
843*c8dee2aaSAndroid Build Coastguard Worker 
844*c8dee2aaSAndroid Build Coastguard Worker     SkRect arcRect;
845*c8dee2aaSAndroid Build Coastguard Worker     arcRect.setLTRB(-rx, -ry, rx, ry);
846*c8dee2aaSAndroid Build Coastguard Worker     switch (startAngle) {
847*c8dee2aaSAndroid Build Coastguard Worker     case 0:
848*c8dee2aaSAndroid Build Coastguard Worker         arcRect.offset(rect.fRight - arcRect.fRight, rect.fBottom - arcRect.fBottom);
849*c8dee2aaSAndroid Build Coastguard Worker         break;
850*c8dee2aaSAndroid Build Coastguard Worker     case 90:
851*c8dee2aaSAndroid Build Coastguard Worker         arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fBottom - arcRect.fBottom);
852*c8dee2aaSAndroid Build Coastguard Worker         break;
853*c8dee2aaSAndroid Build Coastguard Worker     case 180:
854*c8dee2aaSAndroid Build Coastguard Worker         arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fTop - arcRect.fTop);
855*c8dee2aaSAndroid Build Coastguard Worker         break;
856*c8dee2aaSAndroid Build Coastguard Worker     case 270:
857*c8dee2aaSAndroid Build Coastguard Worker         arcRect.offset(rect.fRight - arcRect.fRight, rect.fTop - arcRect.fTop);
858*c8dee2aaSAndroid Build Coastguard Worker         break;
859*c8dee2aaSAndroid Build Coastguard Worker     default:
860*c8dee2aaSAndroid Build Coastguard Worker         break;
861*c8dee2aaSAndroid Build Coastguard Worker     }
862*c8dee2aaSAndroid Build Coastguard Worker 
863*c8dee2aaSAndroid Build Coastguard Worker     path->arcTo(arcRect, SkIntToScalar(startAngle), SkIntToScalar(90), false);
864*c8dee2aaSAndroid Build Coastguard Worker }
865*c8dee2aaSAndroid Build Coastguard Worker 
make_arb_round_rect(SkPath * path,const SkRect & r,SkScalar xCorner,SkScalar yCorner)866*c8dee2aaSAndroid Build Coastguard Worker static void make_arb_round_rect(SkPath* path, const SkRect& r,
867*c8dee2aaSAndroid Build Coastguard Worker                                 SkScalar xCorner, SkScalar yCorner) {
868*c8dee2aaSAndroid Build Coastguard Worker     // we are lazy here and use the same x & y for each corner
869*c8dee2aaSAndroid Build Coastguard Worker     add_corner_arc(path, r, xCorner, yCorner, 270);
870*c8dee2aaSAndroid Build Coastguard Worker     add_corner_arc(path, r, xCorner, yCorner, 0);
871*c8dee2aaSAndroid Build Coastguard Worker     add_corner_arc(path, r, xCorner, yCorner, 90);
872*c8dee2aaSAndroid Build Coastguard Worker     add_corner_arc(path, r, xCorner, yCorner, 180);
873*c8dee2aaSAndroid Build Coastguard Worker     path->close();
874*c8dee2aaSAndroid Build Coastguard Worker }
875*c8dee2aaSAndroid Build Coastguard Worker 
876*c8dee2aaSAndroid Build Coastguard Worker // Chrome creates its own round rects with each corner possibly being different.
877*c8dee2aaSAndroid Build Coastguard Worker // Performance will suffer if they are not convex.
878*c8dee2aaSAndroid Build Coastguard Worker // Note: PathBench::ArbRoundRectBench performs almost exactly
879*c8dee2aaSAndroid Build Coastguard Worker // the same test (but with drawing)
test_arb_round_rect_is_convex(skiatest::Reporter * reporter)880*c8dee2aaSAndroid Build Coastguard Worker static void test_arb_round_rect_is_convex(skiatest::Reporter* reporter) {
881*c8dee2aaSAndroid Build Coastguard Worker     SkRandom rand;
882*c8dee2aaSAndroid Build Coastguard Worker     SkRect r;
883*c8dee2aaSAndroid Build Coastguard Worker 
884*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 5000; ++i) {
885*c8dee2aaSAndroid Build Coastguard Worker 
886*c8dee2aaSAndroid Build Coastguard Worker         SkScalar size = rand.nextUScalar1() * 30;
887*c8dee2aaSAndroid Build Coastguard Worker         if (size < SK_Scalar1) {
888*c8dee2aaSAndroid Build Coastguard Worker             continue;
889*c8dee2aaSAndroid Build Coastguard Worker         }
890*c8dee2aaSAndroid Build Coastguard Worker         r.fLeft = rand.nextUScalar1() * 300;
891*c8dee2aaSAndroid Build Coastguard Worker         r.fTop =  rand.nextUScalar1() * 300;
892*c8dee2aaSAndroid Build Coastguard Worker         r.fRight =  r.fLeft + 2 * size;
893*c8dee2aaSAndroid Build Coastguard Worker         r.fBottom = r.fTop + 2 * size;
894*c8dee2aaSAndroid Build Coastguard Worker 
895*c8dee2aaSAndroid Build Coastguard Worker         SkPath temp;
896*c8dee2aaSAndroid Build Coastguard Worker 
897*c8dee2aaSAndroid Build Coastguard Worker         make_arb_round_rect(&temp, r, r.width() / 10, r.height() / 15);
898*c8dee2aaSAndroid Build Coastguard Worker 
899*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, temp.isConvex());
900*c8dee2aaSAndroid Build Coastguard Worker     }
901*c8dee2aaSAndroid Build Coastguard Worker }
902*c8dee2aaSAndroid Build Coastguard Worker 
903*c8dee2aaSAndroid Build Coastguard Worker // Chrome will sometimes create a 0 radius round rect. The degenerate
904*c8dee2aaSAndroid Build Coastguard Worker // quads prevent the path from being converted to a rect
905*c8dee2aaSAndroid Build Coastguard Worker // Note: PathBench::ArbRoundRectBench performs almost exactly
906*c8dee2aaSAndroid Build Coastguard Worker // the same test (but with drawing)
test_arb_zero_rad_round_rect_is_rect(skiatest::Reporter * reporter)907*c8dee2aaSAndroid Build Coastguard Worker static void test_arb_zero_rad_round_rect_is_rect(skiatest::Reporter* reporter) {
908*c8dee2aaSAndroid Build Coastguard Worker     SkRandom rand;
909*c8dee2aaSAndroid Build Coastguard Worker     SkRect r;
910*c8dee2aaSAndroid Build Coastguard Worker 
911*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 5000; ++i) {
912*c8dee2aaSAndroid Build Coastguard Worker 
913*c8dee2aaSAndroid Build Coastguard Worker         SkScalar size = rand.nextUScalar1() * 30;
914*c8dee2aaSAndroid Build Coastguard Worker         if (size < SK_Scalar1) {
915*c8dee2aaSAndroid Build Coastguard Worker             continue;
916*c8dee2aaSAndroid Build Coastguard Worker         }
917*c8dee2aaSAndroid Build Coastguard Worker         r.fLeft = rand.nextUScalar1() * 300;
918*c8dee2aaSAndroid Build Coastguard Worker         r.fTop =  rand.nextUScalar1() * 300;
919*c8dee2aaSAndroid Build Coastguard Worker         r.fRight =  r.fLeft + 2 * size;
920*c8dee2aaSAndroid Build Coastguard Worker         r.fBottom = r.fTop + 2 * size;
921*c8dee2aaSAndroid Build Coastguard Worker 
922*c8dee2aaSAndroid Build Coastguard Worker         SkPath temp;
923*c8dee2aaSAndroid Build Coastguard Worker 
924*c8dee2aaSAndroid Build Coastguard Worker         make_arb_round_rect(&temp, r, 0, 0);
925*c8dee2aaSAndroid Build Coastguard Worker 
926*c8dee2aaSAndroid Build Coastguard Worker         SkRect result;
927*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, temp.isRect(&result));
928*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, r == result);
929*c8dee2aaSAndroid Build Coastguard Worker     }
930*c8dee2aaSAndroid Build Coastguard Worker }
931*c8dee2aaSAndroid Build Coastguard Worker 
test_rect_isfinite(skiatest::Reporter * reporter)932*c8dee2aaSAndroid Build Coastguard Worker static void test_rect_isfinite(skiatest::Reporter* reporter) {
933*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar inf = SK_ScalarInfinity;
934*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar negInf = SK_ScalarNegativeInfinity;
935*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar nan = SK_ScalarNaN;
936*c8dee2aaSAndroid Build Coastguard Worker 
937*c8dee2aaSAndroid Build Coastguard Worker     SkRect r;
938*c8dee2aaSAndroid Build Coastguard Worker     r.setEmpty();
939*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, r.isFinite());
940*c8dee2aaSAndroid Build Coastguard Worker     r.setLTRB(0, 0, inf, negInf);
941*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !r.isFinite());
942*c8dee2aaSAndroid Build Coastguard Worker     r.setLTRB(0, 0, nan, 0);
943*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !r.isFinite());
944*c8dee2aaSAndroid Build Coastguard Worker 
945*c8dee2aaSAndroid Build Coastguard Worker     SkPoint pts[] = {
946*c8dee2aaSAndroid Build Coastguard Worker         { 0, 0 },
947*c8dee2aaSAndroid Build Coastguard Worker         { SK_Scalar1, 0 },
948*c8dee2aaSAndroid Build Coastguard Worker         { 0, SK_Scalar1 },
949*c8dee2aaSAndroid Build Coastguard Worker     };
950*c8dee2aaSAndroid Build Coastguard Worker 
951*c8dee2aaSAndroid Build Coastguard Worker     bool isFine = r.setBoundsCheck(pts, 3);
952*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, isFine);
953*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !r.isEmpty());
954*c8dee2aaSAndroid Build Coastguard Worker 
955*c8dee2aaSAndroid Build Coastguard Worker     pts[1].set(inf, 0);
956*c8dee2aaSAndroid Build Coastguard Worker     isFine = r.setBoundsCheck(pts, 3);
957*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !isFine);
958*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, r.isEmpty());
959*c8dee2aaSAndroid Build Coastguard Worker 
960*c8dee2aaSAndroid Build Coastguard Worker     pts[1].set(nan, 0);
961*c8dee2aaSAndroid Build Coastguard Worker     isFine = r.setBoundsCheck(pts, 3);
962*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !isFine);
963*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, r.isEmpty());
964*c8dee2aaSAndroid Build Coastguard Worker }
965*c8dee2aaSAndroid Build Coastguard Worker 
test_path_isfinite(skiatest::Reporter * reporter)966*c8dee2aaSAndroid Build Coastguard Worker static void test_path_isfinite(skiatest::Reporter* reporter) {
967*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar inf = SK_ScalarInfinity;
968*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar negInf = SK_ScalarNegativeInfinity;
969*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar nan = SK_ScalarNaN;
970*c8dee2aaSAndroid Build Coastguard Worker 
971*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
972*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isFinite());
973*c8dee2aaSAndroid Build Coastguard Worker 
974*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
975*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isFinite());
976*c8dee2aaSAndroid Build Coastguard Worker 
977*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
978*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SK_Scalar1, 0);
979*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isFinite());
980*c8dee2aaSAndroid Build Coastguard Worker 
981*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
982*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(inf, negInf);
983*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isFinite());
984*c8dee2aaSAndroid Build Coastguard Worker 
985*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
986*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(nan, 0);
987*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isFinite());
988*c8dee2aaSAndroid Build Coastguard Worker }
989*c8dee2aaSAndroid Build Coastguard Worker 
test_isfinite(skiatest::Reporter * reporter)990*c8dee2aaSAndroid Build Coastguard Worker static void test_isfinite(skiatest::Reporter* reporter) {
991*c8dee2aaSAndroid Build Coastguard Worker     test_rect_isfinite(reporter);
992*c8dee2aaSAndroid Build Coastguard Worker     test_path_isfinite(reporter);
993*c8dee2aaSAndroid Build Coastguard Worker }
994*c8dee2aaSAndroid Build Coastguard Worker 
test_islastcontourclosed(skiatest::Reporter * reporter)995*c8dee2aaSAndroid Build Coastguard Worker static void test_islastcontourclosed(skiatest::Reporter* reporter) {
996*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
997*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isLastContourClosed());
998*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0);
999*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isLastContourClosed());
1000*c8dee2aaSAndroid Build Coastguard Worker     path.close();
1001*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isLastContourClosed());
1002*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(100, 100);
1003*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isLastContourClosed());
1004*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(200, 200);
1005*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isLastContourClosed());
1006*c8dee2aaSAndroid Build Coastguard Worker     path.close();
1007*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isLastContourClosed());
1008*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0);
1009*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isLastContourClosed());
1010*c8dee2aaSAndroid Build Coastguard Worker }
1011*c8dee2aaSAndroid Build Coastguard Worker 
1012*c8dee2aaSAndroid Build Coastguard Worker // assert that we always
1013*c8dee2aaSAndroid Build Coastguard Worker //  start with a moveTo
1014*c8dee2aaSAndroid Build Coastguard Worker //  only have 1 moveTo
1015*c8dee2aaSAndroid Build Coastguard Worker //  only have Lines after that
1016*c8dee2aaSAndroid Build Coastguard Worker //  end with a single close
1017*c8dee2aaSAndroid Build Coastguard Worker //  only have (at most) 1 close
1018*c8dee2aaSAndroid Build Coastguard Worker //
test_poly(skiatest::Reporter * reporter,const SkPath & path,const SkPoint srcPts[],bool expectClose)1019*c8dee2aaSAndroid Build Coastguard Worker static void test_poly(skiatest::Reporter* reporter, const SkPath& path,
1020*c8dee2aaSAndroid Build Coastguard Worker                       const SkPoint srcPts[], bool expectClose) {
1021*c8dee2aaSAndroid Build Coastguard Worker     bool firstTime = true;
1022*c8dee2aaSAndroid Build Coastguard Worker     bool foundClose = false;
1023*c8dee2aaSAndroid Build Coastguard Worker     for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
1024*c8dee2aaSAndroid Build Coastguard Worker         switch (verb) {
1025*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kMove:
1026*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, firstTime);
1027*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, pts[0] == srcPts[0]);
1028*c8dee2aaSAndroid Build Coastguard Worker                 srcPts++;
1029*c8dee2aaSAndroid Build Coastguard Worker                 firstTime = false;
1030*c8dee2aaSAndroid Build Coastguard Worker                 break;
1031*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kLine:
1032*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, !firstTime);
1033*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, pts[1] == srcPts[0]);
1034*c8dee2aaSAndroid Build Coastguard Worker                 srcPts++;
1035*c8dee2aaSAndroid Build Coastguard Worker                 break;
1036*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kQuad:
1037*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, false, "unexpected quad verb");
1038*c8dee2aaSAndroid Build Coastguard Worker                 break;
1039*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kConic:
1040*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, false, "unexpected conic verb");
1041*c8dee2aaSAndroid Build Coastguard Worker                 break;
1042*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kCubic:
1043*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, false, "unexpected cubic verb");
1044*c8dee2aaSAndroid Build Coastguard Worker                 break;
1045*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kClose:
1046*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, !firstTime);
1047*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, !foundClose);
1048*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, expectClose);
1049*c8dee2aaSAndroid Build Coastguard Worker                 foundClose = true;
1050*c8dee2aaSAndroid Build Coastguard Worker                 break;
1051*c8dee2aaSAndroid Build Coastguard Worker         }
1052*c8dee2aaSAndroid Build Coastguard Worker     }
1053*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, foundClose == expectClose);
1054*c8dee2aaSAndroid Build Coastguard Worker }
1055*c8dee2aaSAndroid Build Coastguard Worker 
test_addPoly(skiatest::Reporter * reporter)1056*c8dee2aaSAndroid Build Coastguard Worker static void test_addPoly(skiatest::Reporter* reporter) {
1057*c8dee2aaSAndroid Build Coastguard Worker     SkPoint pts[32];
1058*c8dee2aaSAndroid Build Coastguard Worker     SkRandom rand;
1059*c8dee2aaSAndroid Build Coastguard Worker 
1060*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < std::size(pts); ++i) {
1061*c8dee2aaSAndroid Build Coastguard Worker         pts[i].fX = rand.nextSScalar1();
1062*c8dee2aaSAndroid Build Coastguard Worker         pts[i].fY = rand.nextSScalar1();
1063*c8dee2aaSAndroid Build Coastguard Worker     }
1064*c8dee2aaSAndroid Build Coastguard Worker 
1065*c8dee2aaSAndroid Build Coastguard Worker     for (int doClose = 0; doClose <= 1; ++doClose) {
1066*c8dee2aaSAndroid Build Coastguard Worker         for (size_t count = 1; count <= std::size(pts); ++count) {
1067*c8dee2aaSAndroid Build Coastguard Worker             SkPath path;
1068*c8dee2aaSAndroid Build Coastguard Worker             path.addPoly(pts, SkToInt(count), SkToBool(doClose));
1069*c8dee2aaSAndroid Build Coastguard Worker             test_poly(reporter, path, pts, SkToBool(doClose));
1070*c8dee2aaSAndroid Build Coastguard Worker         }
1071*c8dee2aaSAndroid Build Coastguard Worker     }
1072*c8dee2aaSAndroid Build Coastguard Worker }
1073*c8dee2aaSAndroid Build Coastguard Worker 
test_strokerec(skiatest::Reporter * reporter)1074*c8dee2aaSAndroid Build Coastguard Worker static void test_strokerec(skiatest::Reporter* reporter) {
1075*c8dee2aaSAndroid Build Coastguard Worker     SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
1076*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rec.isFillStyle());
1077*c8dee2aaSAndroid Build Coastguard Worker 
1078*c8dee2aaSAndroid Build Coastguard Worker     rec.setHairlineStyle();
1079*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rec.isHairlineStyle());
1080*c8dee2aaSAndroid Build Coastguard Worker 
1081*c8dee2aaSAndroid Build Coastguard Worker     rec.setStrokeStyle(SK_Scalar1, false);
1082*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkStrokeRec::kStroke_Style == rec.getStyle());
1083*c8dee2aaSAndroid Build Coastguard Worker 
1084*c8dee2aaSAndroid Build Coastguard Worker     rec.setStrokeStyle(SK_Scalar1, true);
1085*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkStrokeRec::kStrokeAndFill_Style == rec.getStyle());
1086*c8dee2aaSAndroid Build Coastguard Worker 
1087*c8dee2aaSAndroid Build Coastguard Worker     rec.setStrokeStyle(0, false);
1088*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkStrokeRec::kHairline_Style == rec.getStyle());
1089*c8dee2aaSAndroid Build Coastguard Worker 
1090*c8dee2aaSAndroid Build Coastguard Worker     rec.setStrokeStyle(0, true);
1091*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkStrokeRec::kFill_Style == rec.getStyle());
1092*c8dee2aaSAndroid Build Coastguard Worker }
1093*c8dee2aaSAndroid Build Coastguard Worker 
1094*c8dee2aaSAndroid Build Coastguard Worker // Set this for paths that don't have a consistent direction such as a bowtie.
1095*c8dee2aaSAndroid Build Coastguard Worker // (cheapComputeDirection is not expected to catch these.)
1096*c8dee2aaSAndroid Build Coastguard Worker // Legal values are CW (0), CCW (1) and Unknown (2), leaving 3 as a convenient sentinel.
1097*c8dee2aaSAndroid Build Coastguard Worker const SkPathFirstDirection kDontCheckDir = static_cast<SkPathFirstDirection>(3);
1098*c8dee2aaSAndroid Build Coastguard Worker 
check_direction(skiatest::Reporter * reporter,const SkPath & path,SkPathFirstDirection expected)1099*c8dee2aaSAndroid Build Coastguard Worker static void check_direction(skiatest::Reporter* reporter, const SkPath& path,
1100*c8dee2aaSAndroid Build Coastguard Worker                             SkPathFirstDirection expected) {
1101*c8dee2aaSAndroid Build Coastguard Worker     if (expected == kDontCheckDir) {
1102*c8dee2aaSAndroid Build Coastguard Worker         return;
1103*c8dee2aaSAndroid Build Coastguard Worker     }
1104*c8dee2aaSAndroid Build Coastguard Worker     // We make a copy so that we don't cache the result on the passed in path.
1105*c8dee2aaSAndroid Build Coastguard Worker     SkPath copy(path);  // NOLINT(performance-unnecessary-copy-initialization)
1106*c8dee2aaSAndroid Build Coastguard Worker 
1107*c8dee2aaSAndroid Build Coastguard Worker     SkPathFirstDirection dir = SkPathPriv::ComputeFirstDirection(copy);
1108*c8dee2aaSAndroid Build Coastguard Worker     if (dir != SkPathFirstDirection::kUnknown) {
1109*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, dir == expected);
1110*c8dee2aaSAndroid Build Coastguard Worker     }
1111*c8dee2aaSAndroid Build Coastguard Worker }
1112*c8dee2aaSAndroid Build Coastguard Worker 
test_direction(skiatest::Reporter * reporter)1113*c8dee2aaSAndroid Build Coastguard Worker static void test_direction(skiatest::Reporter* reporter) {
1114*c8dee2aaSAndroid Build Coastguard Worker     size_t i;
1115*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
1116*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter,
1117*c8dee2aaSAndroid Build Coastguard Worker                     SkPathPriv::ComputeFirstDirection(path) == SkPathFirstDirection::kUnknown);
1118*c8dee2aaSAndroid Build Coastguard Worker 
1119*c8dee2aaSAndroid Build Coastguard Worker     static const char* gDegen[] = {
1120*c8dee2aaSAndroid Build Coastguard Worker         "M 10 10",
1121*c8dee2aaSAndroid Build Coastguard Worker         "M 10 10 M 20 20",
1122*c8dee2aaSAndroid Build Coastguard Worker         "M 10 10 L 20 20",
1123*c8dee2aaSAndroid Build Coastguard Worker         "M 10 10 L 10 10 L 10 10",
1124*c8dee2aaSAndroid Build Coastguard Worker         "M 10 10 Q 10 10 10 10",
1125*c8dee2aaSAndroid Build Coastguard Worker         "M 10 10 C 10 10 10 10 10 10",
1126*c8dee2aaSAndroid Build Coastguard Worker     };
1127*c8dee2aaSAndroid Build Coastguard Worker     for (i = 0; i < std::size(gDegen); ++i) {
1128*c8dee2aaSAndroid Build Coastguard Worker         path.reset();
1129*c8dee2aaSAndroid Build Coastguard Worker         bool valid = SkParsePath::FromSVGString(gDegen[i], &path);
1130*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, valid);
1131*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter,
1132*c8dee2aaSAndroid Build Coastguard Worker                         SkPathPriv::ComputeFirstDirection(path) == SkPathFirstDirection::kUnknown);
1133*c8dee2aaSAndroid Build Coastguard Worker     }
1134*c8dee2aaSAndroid Build Coastguard Worker 
1135*c8dee2aaSAndroid Build Coastguard Worker     static const char* gCW[] = {
1136*c8dee2aaSAndroid Build Coastguard Worker         "M 10 10 L 10 10 Q 20 10 20 20",
1137*c8dee2aaSAndroid Build Coastguard Worker         "M 10 10 C 20 10 20 20 20 20",
1138*c8dee2aaSAndroid Build Coastguard Worker         "M 20 10 Q 20 20 30 20 L 10 20", // test double-back at y-max
1139*c8dee2aaSAndroid Build Coastguard Worker         // rect with top two corners replaced by cubics with identical middle
1140*c8dee2aaSAndroid Build Coastguard Worker         // control points
1141*c8dee2aaSAndroid Build Coastguard Worker         "M 10 10 C 10 0 10 0 20 0 L 40 0 C 50 0 50 0 50 10",
1142*c8dee2aaSAndroid Build Coastguard Worker         "M 20 10 L 0 10 Q 10 10 20 0",  // left, degenerate serif
1143*c8dee2aaSAndroid Build Coastguard Worker     };
1144*c8dee2aaSAndroid Build Coastguard Worker     for (i = 0; i < std::size(gCW); ++i) {
1145*c8dee2aaSAndroid Build Coastguard Worker         path.reset();
1146*c8dee2aaSAndroid Build Coastguard Worker         bool valid = SkParsePath::FromSVGString(gCW[i], &path);
1147*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, valid);
1148*c8dee2aaSAndroid Build Coastguard Worker         check_direction(reporter, path, SkPathFirstDirection::kCW);
1149*c8dee2aaSAndroid Build Coastguard Worker     }
1150*c8dee2aaSAndroid Build Coastguard Worker 
1151*c8dee2aaSAndroid Build Coastguard Worker     static const char* gCCW[] = {
1152*c8dee2aaSAndroid Build Coastguard Worker         "M 10 10 L 10 10 Q 20 10 20 -20",
1153*c8dee2aaSAndroid Build Coastguard Worker         "M 10 10 C 20 10 20 -20 20 -20",
1154*c8dee2aaSAndroid Build Coastguard Worker         "M 20 10 Q 20 20 10 20 L 30 20", // test double-back at y-max
1155*c8dee2aaSAndroid Build Coastguard Worker         // rect with top two corners replaced by cubics with identical middle
1156*c8dee2aaSAndroid Build Coastguard Worker         // control points
1157*c8dee2aaSAndroid Build Coastguard Worker         "M 50 10 C 50 0 50 0 40 0 L 20 0 C 10 0 10 0 10 10",
1158*c8dee2aaSAndroid Build Coastguard Worker         "M 10 10 L 30 10 Q 20 10 10 0",  // right, degenerate serif
1159*c8dee2aaSAndroid Build Coastguard Worker     };
1160*c8dee2aaSAndroid Build Coastguard Worker     for (i = 0; i < std::size(gCCW); ++i) {
1161*c8dee2aaSAndroid Build Coastguard Worker         path.reset();
1162*c8dee2aaSAndroid Build Coastguard Worker         bool valid = SkParsePath::FromSVGString(gCCW[i], &path);
1163*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, valid);
1164*c8dee2aaSAndroid Build Coastguard Worker         check_direction(reporter, path, SkPathFirstDirection::kCCW);
1165*c8dee2aaSAndroid Build Coastguard Worker     }
1166*c8dee2aaSAndroid Build Coastguard Worker 
1167*c8dee2aaSAndroid Build Coastguard Worker     // Test two donuts, each wound a different direction. Only the outer contour
1168*c8dee2aaSAndroid Build Coastguard Worker     // determines the cheap direction
1169*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
1170*c8dee2aaSAndroid Build Coastguard Worker     path.addCircle(0, 0, SkIntToScalar(2), SkPathDirection::kCW);
1171*c8dee2aaSAndroid Build Coastguard Worker     path.addCircle(0, 0, SkIntToScalar(1), SkPathDirection::kCCW);
1172*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, path, SkPathFirstDirection::kCW);
1173*c8dee2aaSAndroid Build Coastguard Worker 
1174*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
1175*c8dee2aaSAndroid Build Coastguard Worker     path.addCircle(0, 0, SkIntToScalar(1), SkPathDirection::kCW);
1176*c8dee2aaSAndroid Build Coastguard Worker     path.addCircle(0, 0, SkIntToScalar(2), SkPathDirection::kCCW);
1177*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, path, SkPathFirstDirection::kCCW);
1178*c8dee2aaSAndroid Build Coastguard Worker 
1179*c8dee2aaSAndroid Build Coastguard Worker     // triangle with one point really far from the origin.
1180*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
1181*c8dee2aaSAndroid Build Coastguard Worker     // the first point is roughly 1.05e10, 1.05e10
1182*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x501c7652), SkBits2Float(0x501c7652));
1183*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(110 * SK_Scalar1, -10 * SK_Scalar1);
1184*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(-10 * SK_Scalar1, 60 * SK_Scalar1);
1185*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, path, SkPathFirstDirection::kCCW);
1186*c8dee2aaSAndroid Build Coastguard Worker 
1187*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
1188*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(20, 0, 20, 20, 0.5f);
1189*c8dee2aaSAndroid Build Coastguard Worker     path.close();
1190*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, path, SkPathFirstDirection::kCW);
1191*c8dee2aaSAndroid Build Coastguard Worker 
1192*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
1193*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(1, 1e7f);
1194*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(1e7f, 2e7f);
1195*c8dee2aaSAndroid Build Coastguard Worker     path.close();
1196*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isConvex());
1197*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, path, SkPathFirstDirection::kCCW);
1198*c8dee2aaSAndroid Build Coastguard Worker }
1199*c8dee2aaSAndroid Build Coastguard Worker 
add_rect(SkPath * path,const SkRect & r)1200*c8dee2aaSAndroid Build Coastguard Worker static void add_rect(SkPath* path, const SkRect& r) {
1201*c8dee2aaSAndroid Build Coastguard Worker     path->moveTo(r.fLeft, r.fTop);
1202*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(r.fRight, r.fTop);
1203*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(r.fRight, r.fBottom);
1204*c8dee2aaSAndroid Build Coastguard Worker     path->lineTo(r.fLeft, r.fBottom);
1205*c8dee2aaSAndroid Build Coastguard Worker     path->close();
1206*c8dee2aaSAndroid Build Coastguard Worker }
1207*c8dee2aaSAndroid Build Coastguard Worker 
test_bounds(skiatest::Reporter * reporter)1208*c8dee2aaSAndroid Build Coastguard Worker static void test_bounds(skiatest::Reporter* reporter) {
1209*c8dee2aaSAndroid Build Coastguard Worker     static const SkRect rects[] = {
1210*c8dee2aaSAndroid Build Coastguard Worker         { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(160) },
1211*c8dee2aaSAndroid Build Coastguard Worker         { SkIntToScalar(610), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(199) },
1212*c8dee2aaSAndroid Build Coastguard Worker         { SkIntToScalar(10), SkIntToScalar(198), SkIntToScalar(610), SkIntToScalar(199) },
1213*c8dee2aaSAndroid Build Coastguard Worker         { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(10), SkIntToScalar(199) },
1214*c8dee2aaSAndroid Build Coastguard Worker     };
1215*c8dee2aaSAndroid Build Coastguard Worker 
1216*c8dee2aaSAndroid Build Coastguard Worker     SkPath path0, path1;
1217*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < std::size(rects); ++i) {
1218*c8dee2aaSAndroid Build Coastguard Worker         path0.addRect(rects[i]);
1219*c8dee2aaSAndroid Build Coastguard Worker         add_rect(&path1, rects[i]);
1220*c8dee2aaSAndroid Build Coastguard Worker     }
1221*c8dee2aaSAndroid Build Coastguard Worker 
1222*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path0.getBounds() == path1.getBounds());
1223*c8dee2aaSAndroid Build Coastguard Worker }
1224*c8dee2aaSAndroid Build Coastguard Worker 
stroke_cubic(const SkPoint pts[4])1225*c8dee2aaSAndroid Build Coastguard Worker static void stroke_cubic(const SkPoint pts[4]) {
1226*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
1227*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(pts[0]);
1228*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(pts[1], pts[2], pts[3]);
1229*c8dee2aaSAndroid Build Coastguard Worker 
1230*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
1231*c8dee2aaSAndroid Build Coastguard Worker     paint.setStyle(SkPaint::kStroke_Style);
1232*c8dee2aaSAndroid Build Coastguard Worker     paint.setStrokeWidth(SK_Scalar1 * 2);
1233*c8dee2aaSAndroid Build Coastguard Worker 
1234*c8dee2aaSAndroid Build Coastguard Worker     SkPath fill;
1235*c8dee2aaSAndroid Build Coastguard Worker     skpathutils::FillPathWithPaint(path, paint, &fill);
1236*c8dee2aaSAndroid Build Coastguard Worker }
1237*c8dee2aaSAndroid Build Coastguard Worker 
1238*c8dee2aaSAndroid Build Coastguard Worker // just ensure this can run w/o any SkASSERTS firing in the debug build
1239*c8dee2aaSAndroid Build Coastguard Worker // we used to assert due to differences in how we determine a degenerate vector
1240*c8dee2aaSAndroid Build Coastguard Worker // but that was fixed with the introduction of SkPoint::CanNormalize
stroke_tiny_cubic()1241*c8dee2aaSAndroid Build Coastguard Worker static void stroke_tiny_cubic() {
1242*c8dee2aaSAndroid Build Coastguard Worker     SkPoint p0[] = {
1243*c8dee2aaSAndroid Build Coastguard Worker         { 372.0f,   92.0f },
1244*c8dee2aaSAndroid Build Coastguard Worker         { 372.0f,   92.0f },
1245*c8dee2aaSAndroid Build Coastguard Worker         { 372.0f,   92.0f },
1246*c8dee2aaSAndroid Build Coastguard Worker         { 372.0f,   92.0f },
1247*c8dee2aaSAndroid Build Coastguard Worker     };
1248*c8dee2aaSAndroid Build Coastguard Worker 
1249*c8dee2aaSAndroid Build Coastguard Worker     stroke_cubic(p0);
1250*c8dee2aaSAndroid Build Coastguard Worker 
1251*c8dee2aaSAndroid Build Coastguard Worker     SkPoint p1[] = {
1252*c8dee2aaSAndroid Build Coastguard Worker         { 372.0f,       92.0f },
1253*c8dee2aaSAndroid Build Coastguard Worker         { 372.0007f,    92.000755f },
1254*c8dee2aaSAndroid Build Coastguard Worker         { 371.99927f,   92.003922f },
1255*c8dee2aaSAndroid Build Coastguard Worker         { 371.99826f,   92.003899f },
1256*c8dee2aaSAndroid Build Coastguard Worker     };
1257*c8dee2aaSAndroid Build Coastguard Worker 
1258*c8dee2aaSAndroid Build Coastguard Worker     stroke_cubic(p1);
1259*c8dee2aaSAndroid Build Coastguard Worker }
1260*c8dee2aaSAndroid Build Coastguard Worker 
check_close(skiatest::Reporter * reporter,const SkPath & path)1261*c8dee2aaSAndroid Build Coastguard Worker static void check_close(skiatest::Reporter* reporter, const SkPath& path) {
1262*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 2; ++i) {
1263*c8dee2aaSAndroid Build Coastguard Worker         SkPath::Iter iter(path, SkToBool(i));
1264*c8dee2aaSAndroid Build Coastguard Worker         SkPoint mv;
1265*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pts[4];
1266*c8dee2aaSAndroid Build Coastguard Worker         SkPath::Verb v;
1267*c8dee2aaSAndroid Build Coastguard Worker         int nMT = 0;
1268*c8dee2aaSAndroid Build Coastguard Worker         int nCL = 0;
1269*c8dee2aaSAndroid Build Coastguard Worker         mv.set(0, 0);
1270*c8dee2aaSAndroid Build Coastguard Worker         while (SkPath::kDone_Verb != (v = iter.next(pts))) {
1271*c8dee2aaSAndroid Build Coastguard Worker             switch (v) {
1272*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kMove_Verb:
1273*c8dee2aaSAndroid Build Coastguard Worker                     mv = pts[0];
1274*c8dee2aaSAndroid Build Coastguard Worker                     ++nMT;
1275*c8dee2aaSAndroid Build Coastguard Worker                     break;
1276*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kClose_Verb:
1277*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, mv == pts[0]);
1278*c8dee2aaSAndroid Build Coastguard Worker                     ++nCL;
1279*c8dee2aaSAndroid Build Coastguard Worker                     break;
1280*c8dee2aaSAndroid Build Coastguard Worker                 default:
1281*c8dee2aaSAndroid Build Coastguard Worker                     break;
1282*c8dee2aaSAndroid Build Coastguard Worker             }
1283*c8dee2aaSAndroid Build Coastguard Worker         }
1284*c8dee2aaSAndroid Build Coastguard Worker         // if we force a close on the interator we should have a close
1285*c8dee2aaSAndroid Build Coastguard Worker         // for every moveTo
1286*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !i || nMT == nCL);
1287*c8dee2aaSAndroid Build Coastguard Worker     }
1288*c8dee2aaSAndroid Build Coastguard Worker }
1289*c8dee2aaSAndroid Build Coastguard Worker 
test_close(skiatest::Reporter * reporter)1290*c8dee2aaSAndroid Build Coastguard Worker static void test_close(skiatest::Reporter* reporter) {
1291*c8dee2aaSAndroid Build Coastguard Worker     SkPath closePt;
1292*c8dee2aaSAndroid Build Coastguard Worker     closePt.moveTo(0, 0);
1293*c8dee2aaSAndroid Build Coastguard Worker     closePt.close();
1294*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, closePt);
1295*c8dee2aaSAndroid Build Coastguard Worker 
1296*c8dee2aaSAndroid Build Coastguard Worker     SkPath openPt;
1297*c8dee2aaSAndroid Build Coastguard Worker     openPt.moveTo(0, 0);
1298*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, openPt);
1299*c8dee2aaSAndroid Build Coastguard Worker 
1300*c8dee2aaSAndroid Build Coastguard Worker     SkPath empty;
1301*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, empty);
1302*c8dee2aaSAndroid Build Coastguard Worker     empty.close();
1303*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, empty);
1304*c8dee2aaSAndroid Build Coastguard Worker 
1305*c8dee2aaSAndroid Build Coastguard Worker     SkPath rect;
1306*c8dee2aaSAndroid Build Coastguard Worker     rect.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
1307*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, rect);
1308*c8dee2aaSAndroid Build Coastguard Worker     rect.close();
1309*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, rect);
1310*c8dee2aaSAndroid Build Coastguard Worker 
1311*c8dee2aaSAndroid Build Coastguard Worker     SkPath quad;
1312*c8dee2aaSAndroid Build Coastguard Worker     quad.quadTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
1313*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, quad);
1314*c8dee2aaSAndroid Build Coastguard Worker     quad.close();
1315*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, quad);
1316*c8dee2aaSAndroid Build Coastguard Worker 
1317*c8dee2aaSAndroid Build Coastguard Worker     SkPath cubic;
1318*c8dee2aaSAndroid Build Coastguard Worker     quad.cubicTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1,
1319*c8dee2aaSAndroid Build Coastguard Worker                  10*SK_Scalar1, 20 * SK_Scalar1, 20*SK_Scalar1);
1320*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, cubic);
1321*c8dee2aaSAndroid Build Coastguard Worker     cubic.close();
1322*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, cubic);
1323*c8dee2aaSAndroid Build Coastguard Worker 
1324*c8dee2aaSAndroid Build Coastguard Worker     SkPath line;
1325*c8dee2aaSAndroid Build Coastguard Worker     line.moveTo(SK_Scalar1, SK_Scalar1);
1326*c8dee2aaSAndroid Build Coastguard Worker     line.lineTo(10 * SK_Scalar1, 10*SK_Scalar1);
1327*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, line);
1328*c8dee2aaSAndroid Build Coastguard Worker     line.close();
1329*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, line);
1330*c8dee2aaSAndroid Build Coastguard Worker 
1331*c8dee2aaSAndroid Build Coastguard Worker     SkPath rect2;
1332*c8dee2aaSAndroid Build Coastguard Worker     rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
1333*c8dee2aaSAndroid Build Coastguard Worker     rect2.close();
1334*c8dee2aaSAndroid Build Coastguard Worker     rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
1335*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, rect2);
1336*c8dee2aaSAndroid Build Coastguard Worker     rect2.close();
1337*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, rect2);
1338*c8dee2aaSAndroid Build Coastguard Worker 
1339*c8dee2aaSAndroid Build Coastguard Worker     SkPath oval3;
1340*c8dee2aaSAndroid Build Coastguard Worker     oval3.addOval(SkRect::MakeWH(SK_Scalar1*100,SK_Scalar1*100));
1341*c8dee2aaSAndroid Build Coastguard Worker     oval3.close();
1342*c8dee2aaSAndroid Build Coastguard Worker     oval3.addOval(SkRect::MakeWH(SK_Scalar1*200,SK_Scalar1*200));
1343*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, oval3);
1344*c8dee2aaSAndroid Build Coastguard Worker     oval3.close();
1345*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, oval3);
1346*c8dee2aaSAndroid Build Coastguard Worker 
1347*c8dee2aaSAndroid Build Coastguard Worker     SkPath moves;
1348*c8dee2aaSAndroid Build Coastguard Worker     moves.moveTo(SK_Scalar1, SK_Scalar1);
1349*c8dee2aaSAndroid Build Coastguard Worker     moves.moveTo(5 * SK_Scalar1, SK_Scalar1);
1350*c8dee2aaSAndroid Build Coastguard Worker     moves.moveTo(SK_Scalar1, 10 * SK_Scalar1);
1351*c8dee2aaSAndroid Build Coastguard Worker     moves.moveTo(10 *SK_Scalar1, SK_Scalar1);
1352*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, moves);
1353*c8dee2aaSAndroid Build Coastguard Worker 
1354*c8dee2aaSAndroid Build Coastguard Worker     stroke_tiny_cubic();
1355*c8dee2aaSAndroid Build Coastguard Worker }
1356*c8dee2aaSAndroid Build Coastguard Worker 
check_convexity(skiatest::Reporter * reporter,const SkPath & path,bool expectedConvexity)1357*c8dee2aaSAndroid Build Coastguard Worker static void check_convexity(skiatest::Reporter* reporter, const SkPath& path,
1358*c8dee2aaSAndroid Build Coastguard Worker                             bool expectedConvexity) {
1359*c8dee2aaSAndroid Build Coastguard Worker     // We make a copy so that we don't cache the result on the passed in path.
1360*c8dee2aaSAndroid Build Coastguard Worker     SkPath copy(path);  // NOLINT(performance-unnecessary-copy-initialization)
1361*c8dee2aaSAndroid Build Coastguard Worker     bool convexity = copy.isConvex();
1362*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, convexity == expectedConvexity);
1363*c8dee2aaSAndroid Build Coastguard Worker }
1364*c8dee2aaSAndroid Build Coastguard Worker 
test_path_crbug389050(skiatest::Reporter * reporter)1365*c8dee2aaSAndroid Build Coastguard Worker static void test_path_crbug389050(skiatest::Reporter* reporter) {
1366*c8dee2aaSAndroid Build Coastguard Worker     SkPath  tinyConvexPolygon;
1367*c8dee2aaSAndroid Build Coastguard Worker     tinyConvexPolygon.moveTo(600.131559f, 800.112512f);
1368*c8dee2aaSAndroid Build Coastguard Worker     tinyConvexPolygon.lineTo(600.161735f, 800.118627f);
1369*c8dee2aaSAndroid Build Coastguard Worker     tinyConvexPolygon.lineTo(600.148962f, 800.142338f);
1370*c8dee2aaSAndroid Build Coastguard Worker     tinyConvexPolygon.lineTo(600.134891f, 800.137724f);
1371*c8dee2aaSAndroid Build Coastguard Worker     tinyConvexPolygon.close();
1372*c8dee2aaSAndroid Build Coastguard Worker     tinyConvexPolygon.isConvex();
1373*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, tinyConvexPolygon, SkPathFirstDirection::kCW);
1374*c8dee2aaSAndroid Build Coastguard Worker 
1375*c8dee2aaSAndroid Build Coastguard Worker     SkPath  platTriangle;
1376*c8dee2aaSAndroid Build Coastguard Worker     platTriangle.moveTo(0, 0);
1377*c8dee2aaSAndroid Build Coastguard Worker     platTriangle.lineTo(200, 0);
1378*c8dee2aaSAndroid Build Coastguard Worker     platTriangle.lineTo(100, 0.04f);
1379*c8dee2aaSAndroid Build Coastguard Worker     platTriangle.close();
1380*c8dee2aaSAndroid Build Coastguard Worker     platTriangle.isConvex();
1381*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, platTriangle, SkPathFirstDirection::kCW);
1382*c8dee2aaSAndroid Build Coastguard Worker 
1383*c8dee2aaSAndroid Build Coastguard Worker     platTriangle.reset();
1384*c8dee2aaSAndroid Build Coastguard Worker     platTriangle.moveTo(0, 0);
1385*c8dee2aaSAndroid Build Coastguard Worker     platTriangle.lineTo(200, 0);
1386*c8dee2aaSAndroid Build Coastguard Worker     platTriangle.lineTo(100, 0.03f);
1387*c8dee2aaSAndroid Build Coastguard Worker     platTriangle.close();
1388*c8dee2aaSAndroid Build Coastguard Worker     platTriangle.isConvex();
1389*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, platTriangle, SkPathFirstDirection::kCW);
1390*c8dee2aaSAndroid Build Coastguard Worker }
1391*c8dee2aaSAndroid Build Coastguard Worker 
test_convexity2(skiatest::Reporter * reporter)1392*c8dee2aaSAndroid Build Coastguard Worker static void test_convexity2(skiatest::Reporter* reporter) {
1393*c8dee2aaSAndroid Build Coastguard Worker     SkPath pt;
1394*c8dee2aaSAndroid Build Coastguard Worker     pt.moveTo(0, 0);
1395*c8dee2aaSAndroid Build Coastguard Worker     pt.close();
1396*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, pt, true);
1397*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, pt, SkPathFirstDirection::kUnknown);
1398*c8dee2aaSAndroid Build Coastguard Worker 
1399*c8dee2aaSAndroid Build Coastguard Worker     SkPath line;
1400*c8dee2aaSAndroid Build Coastguard Worker     line.moveTo(12*SK_Scalar1, 20*SK_Scalar1);
1401*c8dee2aaSAndroid Build Coastguard Worker     line.lineTo(-12*SK_Scalar1, -20*SK_Scalar1);
1402*c8dee2aaSAndroid Build Coastguard Worker     line.close();
1403*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, line, true);
1404*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, line, SkPathFirstDirection::kUnknown);
1405*c8dee2aaSAndroid Build Coastguard Worker 
1406*c8dee2aaSAndroid Build Coastguard Worker     SkPath triLeft;
1407*c8dee2aaSAndroid Build Coastguard Worker     triLeft.moveTo(0, 0);
1408*c8dee2aaSAndroid Build Coastguard Worker     triLeft.lineTo(SK_Scalar1, 0);
1409*c8dee2aaSAndroid Build Coastguard Worker     triLeft.lineTo(SK_Scalar1, SK_Scalar1);
1410*c8dee2aaSAndroid Build Coastguard Worker     triLeft.close();
1411*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, triLeft, true);
1412*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, triLeft, SkPathFirstDirection::kCW);
1413*c8dee2aaSAndroid Build Coastguard Worker 
1414*c8dee2aaSAndroid Build Coastguard Worker     SkPath triRight;
1415*c8dee2aaSAndroid Build Coastguard Worker     triRight.moveTo(0, 0);
1416*c8dee2aaSAndroid Build Coastguard Worker     triRight.lineTo(-SK_Scalar1, 0);
1417*c8dee2aaSAndroid Build Coastguard Worker     triRight.lineTo(SK_Scalar1, SK_Scalar1);
1418*c8dee2aaSAndroid Build Coastguard Worker     triRight.close();
1419*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, triRight, true);
1420*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, triRight, SkPathFirstDirection::kCCW);
1421*c8dee2aaSAndroid Build Coastguard Worker 
1422*c8dee2aaSAndroid Build Coastguard Worker     SkPath square;
1423*c8dee2aaSAndroid Build Coastguard Worker     square.moveTo(0, 0);
1424*c8dee2aaSAndroid Build Coastguard Worker     square.lineTo(SK_Scalar1, 0);
1425*c8dee2aaSAndroid Build Coastguard Worker     square.lineTo(SK_Scalar1, SK_Scalar1);
1426*c8dee2aaSAndroid Build Coastguard Worker     square.lineTo(0, SK_Scalar1);
1427*c8dee2aaSAndroid Build Coastguard Worker     square.close();
1428*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, square, true);
1429*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, square, SkPathFirstDirection::kCW);
1430*c8dee2aaSAndroid Build Coastguard Worker 
1431*c8dee2aaSAndroid Build Coastguard Worker     SkPath redundantSquare;
1432*c8dee2aaSAndroid Build Coastguard Worker     redundantSquare.moveTo(0, 0);
1433*c8dee2aaSAndroid Build Coastguard Worker     redundantSquare.lineTo(0, 0);
1434*c8dee2aaSAndroid Build Coastguard Worker     redundantSquare.lineTo(0, 0);
1435*c8dee2aaSAndroid Build Coastguard Worker     redundantSquare.lineTo(SK_Scalar1, 0);
1436*c8dee2aaSAndroid Build Coastguard Worker     redundantSquare.lineTo(SK_Scalar1, 0);
1437*c8dee2aaSAndroid Build Coastguard Worker     redundantSquare.lineTo(SK_Scalar1, 0);
1438*c8dee2aaSAndroid Build Coastguard Worker     redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
1439*c8dee2aaSAndroid Build Coastguard Worker     redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
1440*c8dee2aaSAndroid Build Coastguard Worker     redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
1441*c8dee2aaSAndroid Build Coastguard Worker     redundantSquare.lineTo(0, SK_Scalar1);
1442*c8dee2aaSAndroid Build Coastguard Worker     redundantSquare.lineTo(0, SK_Scalar1);
1443*c8dee2aaSAndroid Build Coastguard Worker     redundantSquare.lineTo(0, SK_Scalar1);
1444*c8dee2aaSAndroid Build Coastguard Worker     redundantSquare.close();
1445*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, redundantSquare, true);
1446*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, redundantSquare, SkPathFirstDirection::kCW);
1447*c8dee2aaSAndroid Build Coastguard Worker 
1448*c8dee2aaSAndroid Build Coastguard Worker     SkPath bowTie;
1449*c8dee2aaSAndroid Build Coastguard Worker     bowTie.moveTo(0, 0);
1450*c8dee2aaSAndroid Build Coastguard Worker     bowTie.lineTo(0, 0);
1451*c8dee2aaSAndroid Build Coastguard Worker     bowTie.lineTo(0, 0);
1452*c8dee2aaSAndroid Build Coastguard Worker     bowTie.lineTo(SK_Scalar1, SK_Scalar1);
1453*c8dee2aaSAndroid Build Coastguard Worker     bowTie.lineTo(SK_Scalar1, SK_Scalar1);
1454*c8dee2aaSAndroid Build Coastguard Worker     bowTie.lineTo(SK_Scalar1, SK_Scalar1);
1455*c8dee2aaSAndroid Build Coastguard Worker     bowTie.lineTo(SK_Scalar1, 0);
1456*c8dee2aaSAndroid Build Coastguard Worker     bowTie.lineTo(SK_Scalar1, 0);
1457*c8dee2aaSAndroid Build Coastguard Worker     bowTie.lineTo(SK_Scalar1, 0);
1458*c8dee2aaSAndroid Build Coastguard Worker     bowTie.lineTo(0, SK_Scalar1);
1459*c8dee2aaSAndroid Build Coastguard Worker     bowTie.lineTo(0, SK_Scalar1);
1460*c8dee2aaSAndroid Build Coastguard Worker     bowTie.lineTo(0, SK_Scalar1);
1461*c8dee2aaSAndroid Build Coastguard Worker     bowTie.close();
1462*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, bowTie, false);
1463*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, bowTie, kDontCheckDir);
1464*c8dee2aaSAndroid Build Coastguard Worker 
1465*c8dee2aaSAndroid Build Coastguard Worker     SkPath spiral;
1466*c8dee2aaSAndroid Build Coastguard Worker     spiral.moveTo(0, 0);
1467*c8dee2aaSAndroid Build Coastguard Worker     spiral.lineTo(100*SK_Scalar1, 0);
1468*c8dee2aaSAndroid Build Coastguard Worker     spiral.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
1469*c8dee2aaSAndroid Build Coastguard Worker     spiral.lineTo(0, 100*SK_Scalar1);
1470*c8dee2aaSAndroid Build Coastguard Worker     spiral.lineTo(0, 50*SK_Scalar1);
1471*c8dee2aaSAndroid Build Coastguard Worker     spiral.lineTo(50*SK_Scalar1, 50*SK_Scalar1);
1472*c8dee2aaSAndroid Build Coastguard Worker     spiral.lineTo(50*SK_Scalar1, 75*SK_Scalar1);
1473*c8dee2aaSAndroid Build Coastguard Worker     spiral.close();
1474*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, spiral, false);
1475*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, spiral, kDontCheckDir);
1476*c8dee2aaSAndroid Build Coastguard Worker 
1477*c8dee2aaSAndroid Build Coastguard Worker     SkPath dent;
1478*c8dee2aaSAndroid Build Coastguard Worker     dent.moveTo(0, 0);
1479*c8dee2aaSAndroid Build Coastguard Worker     dent.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
1480*c8dee2aaSAndroid Build Coastguard Worker     dent.lineTo(0, 100*SK_Scalar1);
1481*c8dee2aaSAndroid Build Coastguard Worker     dent.lineTo(-50*SK_Scalar1, 200*SK_Scalar1);
1482*c8dee2aaSAndroid Build Coastguard Worker     dent.lineTo(-200*SK_Scalar1, 100*SK_Scalar1);
1483*c8dee2aaSAndroid Build Coastguard Worker     dent.close();
1484*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, dent, false);
1485*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, dent, SkPathFirstDirection::kCW);
1486*c8dee2aaSAndroid Build Coastguard Worker 
1487*c8dee2aaSAndroid Build Coastguard Worker     // https://bug.skia.org/2235
1488*c8dee2aaSAndroid Build Coastguard Worker     SkPath strokedSin;
1489*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 2000; i++) {
1490*c8dee2aaSAndroid Build Coastguard Worker         SkScalar x = SkIntToScalar(i) / 2;
1491*c8dee2aaSAndroid Build Coastguard Worker         SkScalar y = 500 - (x + SkScalarSin(x / 100) * 40) / 3;
1492*c8dee2aaSAndroid Build Coastguard Worker         if (0 == i) {
1493*c8dee2aaSAndroid Build Coastguard Worker             strokedSin.moveTo(x, y);
1494*c8dee2aaSAndroid Build Coastguard Worker         } else {
1495*c8dee2aaSAndroid Build Coastguard Worker             strokedSin.lineTo(x, y);
1496*c8dee2aaSAndroid Build Coastguard Worker         }
1497*c8dee2aaSAndroid Build Coastguard Worker     }
1498*c8dee2aaSAndroid Build Coastguard Worker     SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
1499*c8dee2aaSAndroid Build Coastguard Worker     stroke.setStrokeStyle(2 * SK_Scalar1);
1500*c8dee2aaSAndroid Build Coastguard Worker     stroke.applyToPath(&strokedSin, strokedSin);
1501*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, strokedSin, false);
1502*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, strokedSin, kDontCheckDir);
1503*c8dee2aaSAndroid Build Coastguard Worker 
1504*c8dee2aaSAndroid Build Coastguard Worker     // http://crbug.com/412640
1505*c8dee2aaSAndroid Build Coastguard Worker     SkPath degenerateConcave;
1506*c8dee2aaSAndroid Build Coastguard Worker     degenerateConcave.moveTo(148.67912f, 191.875f);
1507*c8dee2aaSAndroid Build Coastguard Worker     degenerateConcave.lineTo(470.37695f, 7.5f);
1508*c8dee2aaSAndroid Build Coastguard Worker     degenerateConcave.lineTo(148.67912f, 191.875f);
1509*c8dee2aaSAndroid Build Coastguard Worker     degenerateConcave.lineTo(41.446522f, 376.25f);
1510*c8dee2aaSAndroid Build Coastguard Worker     degenerateConcave.lineTo(-55.971577f, 460.0f);
1511*c8dee2aaSAndroid Build Coastguard Worker     degenerateConcave.lineTo(41.446522f, 376.25f);
1512*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, degenerateConcave, false);
1513*c8dee2aaSAndroid Build Coastguard Worker     check_direction(reporter, degenerateConcave, SkPathFirstDirection::kUnknown);
1514*c8dee2aaSAndroid Build Coastguard Worker 
1515*c8dee2aaSAndroid Build Coastguard Worker     // http://crbug.com/433683
1516*c8dee2aaSAndroid Build Coastguard Worker     SkPath badFirstVector;
1517*c8dee2aaSAndroid Build Coastguard Worker     badFirstVector.moveTo(501.087708f, 319.610352f);
1518*c8dee2aaSAndroid Build Coastguard Worker     badFirstVector.lineTo(501.087708f, 319.610352f);
1519*c8dee2aaSAndroid Build Coastguard Worker     badFirstVector.cubicTo(501.087677f, 319.610321f, 449.271606f, 258.078674f, 395.084564f, 198.711182f);
1520*c8dee2aaSAndroid Build Coastguard Worker     badFirstVector.cubicTo(358.967072f, 159.140717f, 321.910553f, 120.650436f, 298.442322f, 101.955399f);
1521*c8dee2aaSAndroid Build Coastguard Worker     badFirstVector.lineTo(301.557678f, 98.044601f);
1522*c8dee2aaSAndroid Build Coastguard Worker     badFirstVector.cubicTo(325.283844f, 116.945084f, 362.615204f, 155.720825f, 398.777557f, 195.340454f);
1523*c8dee2aaSAndroid Build Coastguard Worker     badFirstVector.cubicTo(453.031860f, 254.781662f, 504.912262f, 316.389618f, 504.912292f, 316.389648f);
1524*c8dee2aaSAndroid Build Coastguard Worker     badFirstVector.lineTo(504.912292f, 316.389648f);
1525*c8dee2aaSAndroid Build Coastguard Worker     badFirstVector.lineTo(501.087708f, 319.610352f);
1526*c8dee2aaSAndroid Build Coastguard Worker     badFirstVector.close();
1527*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, badFirstVector, false);
1528*c8dee2aaSAndroid Build Coastguard Worker 
1529*c8dee2aaSAndroid Build Coastguard Worker     // http://crbug.com/993330
1530*c8dee2aaSAndroid Build Coastguard Worker     SkPath falseBackEdge;
1531*c8dee2aaSAndroid Build Coastguard Worker     falseBackEdge.moveTo(-217.83430557928145f,      -382.14948768484857f);
1532*c8dee2aaSAndroid Build Coastguard Worker     falseBackEdge.lineTo(-227.73867866614847f,      -399.52485512718323f);
1533*c8dee2aaSAndroid Build Coastguard Worker     falseBackEdge.cubicTo(-158.3541047666846f,      -439.0757140459542f,
1534*c8dee2aaSAndroid Build Coastguard Worker                           -79.8654464485281f,       -459.875f,
1535*c8dee2aaSAndroid Build Coastguard Worker                           -1.1368683772161603e-13f, -459.875f);
1536*c8dee2aaSAndroid Build Coastguard Worker     falseBackEdge.lineTo(-8.08037266162413e-14f,    -439.875f);
1537*c8dee2aaSAndroid Build Coastguard Worker     falseBackEdge.lineTo(-8.526512829121202e-14f,   -439.87499999999994f);
1538*c8dee2aaSAndroid Build Coastguard Worker     falseBackEdge.cubicTo(-76.39209188702645f,      -439.87499999999994f,
1539*c8dee2aaSAndroid Build Coastguard Worker                           -151.46727226799754f,     -419.98027663161537f,
1540*c8dee2aaSAndroid Build Coastguard Worker                           -217.83430557928145f,     -382.14948768484857f);
1541*c8dee2aaSAndroid Build Coastguard Worker     falseBackEdge.close();
1542*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, falseBackEdge, false);
1543*c8dee2aaSAndroid Build Coastguard Worker }
1544*c8dee2aaSAndroid Build Coastguard Worker 
test_convexity_doubleback(skiatest::Reporter * reporter)1545*c8dee2aaSAndroid Build Coastguard Worker static void test_convexity_doubleback(skiatest::Reporter* reporter) {
1546*c8dee2aaSAndroid Build Coastguard Worker     SkPath doubleback;
1547*c8dee2aaSAndroid Build Coastguard Worker     doubleback.lineTo(1, 1);
1548*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, doubleback, true);
1549*c8dee2aaSAndroid Build Coastguard Worker     doubleback.lineTo(2, 2);
1550*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, doubleback, true);
1551*c8dee2aaSAndroid Build Coastguard Worker     doubleback.reset();
1552*c8dee2aaSAndroid Build Coastguard Worker     doubleback.lineTo(1, 0);
1553*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, doubleback, true);
1554*c8dee2aaSAndroid Build Coastguard Worker     doubleback.lineTo(2, 0);
1555*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, doubleback, true);
1556*c8dee2aaSAndroid Build Coastguard Worker     doubleback.lineTo(1, 0);
1557*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, doubleback, true);
1558*c8dee2aaSAndroid Build Coastguard Worker     doubleback.reset();
1559*c8dee2aaSAndroid Build Coastguard Worker     doubleback.quadTo(1, 1, 2, 2);
1560*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, doubleback, true);
1561*c8dee2aaSAndroid Build Coastguard Worker     doubleback.reset();
1562*c8dee2aaSAndroid Build Coastguard Worker     doubleback.quadTo(1, 0, 2, 0);
1563*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, doubleback, true);
1564*c8dee2aaSAndroid Build Coastguard Worker     doubleback.quadTo(1, 0, 0, 0);
1565*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, doubleback, true);
1566*c8dee2aaSAndroid Build Coastguard Worker 
1567*c8dee2aaSAndroid Build Coastguard Worker     doubleback.reset();
1568*c8dee2aaSAndroid Build Coastguard Worker     doubleback.lineTo(1, 0);
1569*c8dee2aaSAndroid Build Coastguard Worker     doubleback.lineTo(1, 0);
1570*c8dee2aaSAndroid Build Coastguard Worker     doubleback.lineTo(1, 1);
1571*c8dee2aaSAndroid Build Coastguard Worker     doubleback.lineTo(1, 1);
1572*c8dee2aaSAndroid Build Coastguard Worker     doubleback.lineTo(1, 0);
1573*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, doubleback, false);
1574*c8dee2aaSAndroid Build Coastguard Worker 
1575*c8dee2aaSAndroid Build Coastguard Worker     doubleback.reset();
1576*c8dee2aaSAndroid Build Coastguard Worker     doubleback.lineTo(-1, 0);
1577*c8dee2aaSAndroid Build Coastguard Worker     doubleback.lineTo(-1, 1);
1578*c8dee2aaSAndroid Build Coastguard Worker     doubleback.lineTo(-1, 0);
1579*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, doubleback, false);
1580*c8dee2aaSAndroid Build Coastguard Worker 
1581*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 4; ++i) {
1582*c8dee2aaSAndroid Build Coastguard Worker         doubleback.reset();
1583*c8dee2aaSAndroid Build Coastguard Worker         doubleback.moveTo(0, 0);
1584*c8dee2aaSAndroid Build Coastguard Worker         if (i == 0) {
1585*c8dee2aaSAndroid Build Coastguard Worker             doubleback.lineTo(-1, -1);
1586*c8dee2aaSAndroid Build Coastguard Worker             doubleback.lineTo(0, 0);
1587*c8dee2aaSAndroid Build Coastguard Worker         }
1588*c8dee2aaSAndroid Build Coastguard Worker         doubleback.lineTo(0, 1);
1589*c8dee2aaSAndroid Build Coastguard Worker         if (i == 1) {
1590*c8dee2aaSAndroid Build Coastguard Worker             doubleback.lineTo(0, 2);
1591*c8dee2aaSAndroid Build Coastguard Worker             doubleback.lineTo(0, 1);
1592*c8dee2aaSAndroid Build Coastguard Worker         }
1593*c8dee2aaSAndroid Build Coastguard Worker         doubleback.lineTo(1, 1);
1594*c8dee2aaSAndroid Build Coastguard Worker         if (i == 2) {
1595*c8dee2aaSAndroid Build Coastguard Worker             doubleback.lineTo(2, 2);
1596*c8dee2aaSAndroid Build Coastguard Worker             doubleback.lineTo(1, 1);
1597*c8dee2aaSAndroid Build Coastguard Worker         }
1598*c8dee2aaSAndroid Build Coastguard Worker         doubleback.lineTo(0, 0);
1599*c8dee2aaSAndroid Build Coastguard Worker         if (i == 3) {
1600*c8dee2aaSAndroid Build Coastguard Worker             doubleback.lineTo(-1, -1);
1601*c8dee2aaSAndroid Build Coastguard Worker             doubleback.lineTo(0, 0);
1602*c8dee2aaSAndroid Build Coastguard Worker         }
1603*c8dee2aaSAndroid Build Coastguard Worker         check_convexity(reporter, doubleback, false);
1604*c8dee2aaSAndroid Build Coastguard Worker     }
1605*c8dee2aaSAndroid Build Coastguard Worker }
1606*c8dee2aaSAndroid Build Coastguard Worker 
check_convex_bounds(skiatest::Reporter * reporter,const SkPath & p,const SkRect & bounds)1607*c8dee2aaSAndroid Build Coastguard Worker static void check_convex_bounds(skiatest::Reporter* reporter, const SkPath& p,
1608*c8dee2aaSAndroid Build Coastguard Worker                                 const SkRect& bounds) {
1609*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.isConvex());
1610*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.getBounds() == bounds);
1611*c8dee2aaSAndroid Build Coastguard Worker 
1612*c8dee2aaSAndroid Build Coastguard Worker     SkPath p2(p);
1613*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p2.isConvex());
1614*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p2.getBounds() == bounds);
1615*c8dee2aaSAndroid Build Coastguard Worker 
1616*c8dee2aaSAndroid Build Coastguard Worker     SkPath other;
1617*c8dee2aaSAndroid Build Coastguard Worker     other.swap(p2);
1618*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, other.isConvex());
1619*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, other.getBounds() == bounds);
1620*c8dee2aaSAndroid Build Coastguard Worker }
1621*c8dee2aaSAndroid Build Coastguard Worker 
setFromString(SkPath * path,const char str[])1622*c8dee2aaSAndroid Build Coastguard Worker static void setFromString(SkPath* path, const char str[]) {
1623*c8dee2aaSAndroid Build Coastguard Worker     bool first = true;
1624*c8dee2aaSAndroid Build Coastguard Worker     while (str) {
1625*c8dee2aaSAndroid Build Coastguard Worker         SkScalar x, y;
1626*c8dee2aaSAndroid Build Coastguard Worker         str = SkParse::FindScalar(str, &x);
1627*c8dee2aaSAndroid Build Coastguard Worker         if (nullptr == str) {
1628*c8dee2aaSAndroid Build Coastguard Worker             break;
1629*c8dee2aaSAndroid Build Coastguard Worker         }
1630*c8dee2aaSAndroid Build Coastguard Worker         str = SkParse::FindScalar(str, &y);
1631*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(str);
1632*c8dee2aaSAndroid Build Coastguard Worker         if (first) {
1633*c8dee2aaSAndroid Build Coastguard Worker             path->moveTo(x, y);
1634*c8dee2aaSAndroid Build Coastguard Worker             first = false;
1635*c8dee2aaSAndroid Build Coastguard Worker         } else {
1636*c8dee2aaSAndroid Build Coastguard Worker             path->lineTo(x, y);
1637*c8dee2aaSAndroid Build Coastguard Worker         }
1638*c8dee2aaSAndroid Build Coastguard Worker     }
1639*c8dee2aaSAndroid Build Coastguard Worker }
1640*c8dee2aaSAndroid Build Coastguard Worker 
test_convexity(skiatest::Reporter * reporter)1641*c8dee2aaSAndroid Build Coastguard Worker static void test_convexity(skiatest::Reporter* reporter) {
1642*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
1643*c8dee2aaSAndroid Build Coastguard Worker 
1644*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, path, true);
1645*c8dee2aaSAndroid Build Coastguard Worker     path.addCircle(0, 0, SkIntToScalar(10));
1646*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, path, true);
1647*c8dee2aaSAndroid Build Coastguard Worker     path.addCircle(0, 0, SkIntToScalar(10));   // 2nd circle
1648*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, path, false);
1649*c8dee2aaSAndroid Build Coastguard Worker 
1650*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
1651*c8dee2aaSAndroid Build Coastguard Worker     path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPathDirection::kCCW);
1652*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, path, true);
1653*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathPriv::ComputeFirstDirection(path) == SkPathFirstDirection::kCCW);
1654*c8dee2aaSAndroid Build Coastguard Worker 
1655*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
1656*c8dee2aaSAndroid Build Coastguard Worker     path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPathDirection::kCW);
1657*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, path, true);
1658*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathPriv::ComputeFirstDirection(path) == SkPathFirstDirection::kCW);
1659*c8dee2aaSAndroid Build Coastguard Worker 
1660*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
1661*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(100, 100, 50, 50); // This from GM:convexpaths
1662*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, path, true);
1663*c8dee2aaSAndroid Build Coastguard Worker 
1664*c8dee2aaSAndroid Build Coastguard Worker     static const struct {
1665*c8dee2aaSAndroid Build Coastguard Worker         const char*           fPathStr;
1666*c8dee2aaSAndroid Build Coastguard Worker         bool                  fExpectedIsConvex;
1667*c8dee2aaSAndroid Build Coastguard Worker         SkPathFirstDirection  fExpectedDirection;
1668*c8dee2aaSAndroid Build Coastguard Worker     } gRec[] = {
1669*c8dee2aaSAndroid Build Coastguard Worker         { "", true, SkPathFirstDirection::kUnknown },
1670*c8dee2aaSAndroid Build Coastguard Worker         { "0 0", true, SkPathFirstDirection::kUnknown },
1671*c8dee2aaSAndroid Build Coastguard Worker         { "0 0 10 10", true, SkPathFirstDirection::kUnknown },
1672*c8dee2aaSAndroid Build Coastguard Worker         { "0 0 10 10 20 20 0 0 10 10", false, SkPathFirstDirection::kUnknown },
1673*c8dee2aaSAndroid Build Coastguard Worker         { "0 0 10 10 10 20", true, SkPathFirstDirection::kCW },
1674*c8dee2aaSAndroid Build Coastguard Worker         { "0 0 10 10 10 0", true, SkPathFirstDirection::kCCW },
1675*c8dee2aaSAndroid Build Coastguard Worker         { "0 0 10 10 10 0 0 10", false, kDontCheckDir },
1676*c8dee2aaSAndroid Build Coastguard Worker         { "0 0 10 0 0 10 -10 -10", false, SkPathFirstDirection::kCW },
1677*c8dee2aaSAndroid Build Coastguard Worker     };
1678*c8dee2aaSAndroid Build Coastguard Worker 
1679*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < std::size(gRec); ++i) {
1680*c8dee2aaSAndroid Build Coastguard Worker         path.reset();
1681*c8dee2aaSAndroid Build Coastguard Worker         setFromString(&path, gRec[i].fPathStr);
1682*c8dee2aaSAndroid Build Coastguard Worker         check_convexity(reporter, path, gRec[i].fExpectedIsConvex);
1683*c8dee2aaSAndroid Build Coastguard Worker         check_direction(reporter, path, gRec[i].fExpectedDirection);
1684*c8dee2aaSAndroid Build Coastguard Worker         // check after setting the initial convex and direction
1685*c8dee2aaSAndroid Build Coastguard Worker         if (kDontCheckDir != gRec[i].fExpectedDirection) {
1686*c8dee2aaSAndroid Build Coastguard Worker             // We make a copy so that we don't cache the result on the passed in path.
1687*c8dee2aaSAndroid Build Coastguard Worker             SkPath copy(path);  // NOLINT(performance-unnecessary-copy-initialization)
1688*c8dee2aaSAndroid Build Coastguard Worker             SkPathFirstDirection dir = SkPathPriv::ComputeFirstDirection(copy);
1689*c8dee2aaSAndroid Build Coastguard Worker             bool foundDir = dir != SkPathFirstDirection::kUnknown;
1690*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, (gRec[i].fExpectedDirection == SkPathFirstDirection::kUnknown)
1691*c8dee2aaSAndroid Build Coastguard Worker                     ^ foundDir);
1692*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !foundDir || gRec[i].fExpectedDirection == dir);
1693*c8dee2aaSAndroid Build Coastguard Worker             check_convexity(reporter, copy, gRec[i].fExpectedIsConvex);
1694*c8dee2aaSAndroid Build Coastguard Worker         }
1695*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, gRec[i].fExpectedIsConvex == path.isConvex());
1696*c8dee2aaSAndroid Build Coastguard Worker         check_direction(reporter, path, gRec[i].fExpectedDirection);
1697*c8dee2aaSAndroid Build Coastguard Worker     }
1698*c8dee2aaSAndroid Build Coastguard Worker 
1699*c8dee2aaSAndroid Build Coastguard Worker     static const SkPoint nonFinitePts[] = {
1700*c8dee2aaSAndroid Build Coastguard Worker         { SK_ScalarInfinity, 0 },
1701*c8dee2aaSAndroid Build Coastguard Worker         { 0, SK_ScalarInfinity },
1702*c8dee2aaSAndroid Build Coastguard Worker         { SK_ScalarInfinity, SK_ScalarInfinity },
1703*c8dee2aaSAndroid Build Coastguard Worker         { SK_ScalarNegativeInfinity, 0},
1704*c8dee2aaSAndroid Build Coastguard Worker         { 0, SK_ScalarNegativeInfinity },
1705*c8dee2aaSAndroid Build Coastguard Worker         { SK_ScalarNegativeInfinity, SK_ScalarNegativeInfinity },
1706*c8dee2aaSAndroid Build Coastguard Worker         { SK_ScalarNegativeInfinity, SK_ScalarInfinity },
1707*c8dee2aaSAndroid Build Coastguard Worker         { SK_ScalarInfinity, SK_ScalarNegativeInfinity },
1708*c8dee2aaSAndroid Build Coastguard Worker         { SK_ScalarNaN, 0 },
1709*c8dee2aaSAndroid Build Coastguard Worker         { 0, SK_ScalarNaN },
1710*c8dee2aaSAndroid Build Coastguard Worker         { SK_ScalarNaN, SK_ScalarNaN },
1711*c8dee2aaSAndroid Build Coastguard Worker     };
1712*c8dee2aaSAndroid Build Coastguard Worker 
1713*c8dee2aaSAndroid Build Coastguard Worker     const size_t nonFinitePtsCount = sizeof(nonFinitePts) / sizeof(nonFinitePts[0]);
1714*c8dee2aaSAndroid Build Coastguard Worker 
1715*c8dee2aaSAndroid Build Coastguard Worker     static const SkPoint axisAlignedPts[] = {
1716*c8dee2aaSAndroid Build Coastguard Worker         { SK_ScalarMax, 0 },
1717*c8dee2aaSAndroid Build Coastguard Worker         { 0, SK_ScalarMax },
1718*c8dee2aaSAndroid Build Coastguard Worker         { SK_ScalarMin, 0 },
1719*c8dee2aaSAndroid Build Coastguard Worker         { 0, SK_ScalarMin },
1720*c8dee2aaSAndroid Build Coastguard Worker     };
1721*c8dee2aaSAndroid Build Coastguard Worker 
1722*c8dee2aaSAndroid Build Coastguard Worker     const size_t axisAlignedPtsCount = sizeof(axisAlignedPts) / sizeof(axisAlignedPts[0]);
1723*c8dee2aaSAndroid Build Coastguard Worker 
1724*c8dee2aaSAndroid Build Coastguard Worker     for (int index = 0; index < (int) (13 * nonFinitePtsCount * axisAlignedPtsCount); ++index) {
1725*c8dee2aaSAndroid Build Coastguard Worker         int i = (int) (index % nonFinitePtsCount);
1726*c8dee2aaSAndroid Build Coastguard Worker         int f = (int) (index % axisAlignedPtsCount);
1727*c8dee2aaSAndroid Build Coastguard Worker         int g = (int) ((f + 1) % axisAlignedPtsCount);
1728*c8dee2aaSAndroid Build Coastguard Worker         path.reset();
1729*c8dee2aaSAndroid Build Coastguard Worker         switch (index % 13) {
1730*c8dee2aaSAndroid Build Coastguard Worker             case 0: path.lineTo(nonFinitePts[i]); break;
1731*c8dee2aaSAndroid Build Coastguard Worker             case 1: path.quadTo(nonFinitePts[i], nonFinitePts[i]); break;
1732*c8dee2aaSAndroid Build Coastguard Worker             case 2: path.quadTo(nonFinitePts[i], axisAlignedPts[f]); break;
1733*c8dee2aaSAndroid Build Coastguard Worker             case 3: path.quadTo(axisAlignedPts[f], nonFinitePts[i]); break;
1734*c8dee2aaSAndroid Build Coastguard Worker             case 4: path.cubicTo(nonFinitePts[i], axisAlignedPts[f], axisAlignedPts[f]); break;
1735*c8dee2aaSAndroid Build Coastguard Worker             case 5: path.cubicTo(axisAlignedPts[f], nonFinitePts[i], axisAlignedPts[f]); break;
1736*c8dee2aaSAndroid Build Coastguard Worker             case 6: path.cubicTo(axisAlignedPts[f], axisAlignedPts[f], nonFinitePts[i]); break;
1737*c8dee2aaSAndroid Build Coastguard Worker             case 7: path.cubicTo(nonFinitePts[i], nonFinitePts[i], axisAlignedPts[f]); break;
1738*c8dee2aaSAndroid Build Coastguard Worker             case 8: path.cubicTo(nonFinitePts[i], axisAlignedPts[f], nonFinitePts[i]); break;
1739*c8dee2aaSAndroid Build Coastguard Worker             case 9: path.cubicTo(axisAlignedPts[f], nonFinitePts[i], nonFinitePts[i]); break;
1740*c8dee2aaSAndroid Build Coastguard Worker             case 10: path.cubicTo(nonFinitePts[i], nonFinitePts[i], nonFinitePts[i]); break;
1741*c8dee2aaSAndroid Build Coastguard Worker             case 11: path.cubicTo(nonFinitePts[i], axisAlignedPts[f], axisAlignedPts[g]); break;
1742*c8dee2aaSAndroid Build Coastguard Worker             case 12: path.moveTo(nonFinitePts[i]); break;
1743*c8dee2aaSAndroid Build Coastguard Worker         }
1744*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter,
1745*c8dee2aaSAndroid Build Coastguard Worker                     SkPathPriv::GetConvexityOrUnknown(path) == SkPathConvexity::kUnknown);
1746*c8dee2aaSAndroid Build Coastguard Worker     }
1747*c8dee2aaSAndroid Build Coastguard Worker 
1748*c8dee2aaSAndroid Build Coastguard Worker     for (int index = 0; index < (int) (11 * axisAlignedPtsCount); ++index) {
1749*c8dee2aaSAndroid Build Coastguard Worker         int f = (int) (index % axisAlignedPtsCount);
1750*c8dee2aaSAndroid Build Coastguard Worker         int g = (int) ((f + 1) % axisAlignedPtsCount);
1751*c8dee2aaSAndroid Build Coastguard Worker         path.reset();
1752*c8dee2aaSAndroid Build Coastguard Worker         int curveSelect = index % 11;
1753*c8dee2aaSAndroid Build Coastguard Worker         switch (curveSelect) {
1754*c8dee2aaSAndroid Build Coastguard Worker             case 0: path.moveTo(axisAlignedPts[f]); break;
1755*c8dee2aaSAndroid Build Coastguard Worker             case 1: path.lineTo(axisAlignedPts[f]); break;
1756*c8dee2aaSAndroid Build Coastguard Worker             case 2: path.quadTo(axisAlignedPts[f], axisAlignedPts[f]); break;
1757*c8dee2aaSAndroid Build Coastguard Worker             case 3: path.quadTo(axisAlignedPts[f], axisAlignedPts[g]); break;
1758*c8dee2aaSAndroid Build Coastguard Worker             case 4: path.quadTo(axisAlignedPts[g], axisAlignedPts[f]); break;
1759*c8dee2aaSAndroid Build Coastguard Worker             case 5: path.cubicTo(axisAlignedPts[f], axisAlignedPts[f], axisAlignedPts[f]); break;
1760*c8dee2aaSAndroid Build Coastguard Worker             case 6: path.cubicTo(axisAlignedPts[f], axisAlignedPts[f], axisAlignedPts[g]); break;
1761*c8dee2aaSAndroid Build Coastguard Worker             case 7: path.cubicTo(axisAlignedPts[f], axisAlignedPts[g], axisAlignedPts[f]); break;
1762*c8dee2aaSAndroid Build Coastguard Worker             case 8: path.cubicTo(axisAlignedPts[f], axisAlignedPts[g], axisAlignedPts[g]); break;
1763*c8dee2aaSAndroid Build Coastguard Worker             case 9: path.cubicTo(axisAlignedPts[g], axisAlignedPts[f], axisAlignedPts[f]); break;
1764*c8dee2aaSAndroid Build Coastguard Worker             case 10: path.cubicTo(axisAlignedPts[g], axisAlignedPts[f], axisAlignedPts[g]); break;
1765*c8dee2aaSAndroid Build Coastguard Worker         }
1766*c8dee2aaSAndroid Build Coastguard Worker         if (curveSelect == 0 || curveSelect == 1 || curveSelect == 2 || curveSelect == 5) {
1767*c8dee2aaSAndroid Build Coastguard Worker             check_convexity(reporter, path, true);
1768*c8dee2aaSAndroid Build Coastguard Worker         } else {
1769*c8dee2aaSAndroid Build Coastguard Worker             // We make a copy so that we don't cache the result on the passed in path.
1770*c8dee2aaSAndroid Build Coastguard Worker             SkPath copy(path);  // NOLINT(performance-unnecessary-copy-initialization)
1771*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !copy.isConvex());
1772*c8dee2aaSAndroid Build Coastguard Worker         }
1773*c8dee2aaSAndroid Build Coastguard Worker     }
1774*c8dee2aaSAndroid Build Coastguard Worker 
1775*c8dee2aaSAndroid Build Coastguard Worker     static const SkPoint diagonalPts[] = {
1776*c8dee2aaSAndroid Build Coastguard Worker         { SK_ScalarMax, SK_ScalarMax },
1777*c8dee2aaSAndroid Build Coastguard Worker         { SK_ScalarMin, SK_ScalarMin },
1778*c8dee2aaSAndroid Build Coastguard Worker     };
1779*c8dee2aaSAndroid Build Coastguard Worker 
1780*c8dee2aaSAndroid Build Coastguard Worker     const size_t diagonalPtsCount = sizeof(diagonalPts) / sizeof(diagonalPts[0]);
1781*c8dee2aaSAndroid Build Coastguard Worker 
1782*c8dee2aaSAndroid Build Coastguard Worker     for (int index = 0; index < (int) (7 * diagonalPtsCount); ++index) {
1783*c8dee2aaSAndroid Build Coastguard Worker         int f = (int) (index % diagonalPtsCount);
1784*c8dee2aaSAndroid Build Coastguard Worker         int g = (int) ((f + 1) % diagonalPtsCount);
1785*c8dee2aaSAndroid Build Coastguard Worker         path.reset();
1786*c8dee2aaSAndroid Build Coastguard Worker         int curveSelect = index % 11;
1787*c8dee2aaSAndroid Build Coastguard Worker         switch (curveSelect) {
1788*c8dee2aaSAndroid Build Coastguard Worker             case 0: path.moveTo(diagonalPts[f]); break;
1789*c8dee2aaSAndroid Build Coastguard Worker             case 1: path.lineTo(diagonalPts[f]); break;
1790*c8dee2aaSAndroid Build Coastguard Worker             case 2: path.quadTo(diagonalPts[f], diagonalPts[f]); break;
1791*c8dee2aaSAndroid Build Coastguard Worker             case 3: path.quadTo(axisAlignedPts[f], diagonalPts[g]); break;
1792*c8dee2aaSAndroid Build Coastguard Worker             case 4: path.quadTo(diagonalPts[g], axisAlignedPts[f]); break;
1793*c8dee2aaSAndroid Build Coastguard Worker             case 5: path.cubicTo(diagonalPts[f], diagonalPts[f], diagonalPts[f]); break;
1794*c8dee2aaSAndroid Build Coastguard Worker             case 6: path.cubicTo(diagonalPts[f], diagonalPts[f], axisAlignedPts[g]); break;
1795*c8dee2aaSAndroid Build Coastguard Worker             case 7: path.cubicTo(diagonalPts[f], axisAlignedPts[g], diagonalPts[f]); break;
1796*c8dee2aaSAndroid Build Coastguard Worker             case 8: path.cubicTo(axisAlignedPts[f], diagonalPts[g], diagonalPts[g]); break;
1797*c8dee2aaSAndroid Build Coastguard Worker             case 9: path.cubicTo(diagonalPts[g], diagonalPts[f], axisAlignedPts[f]); break;
1798*c8dee2aaSAndroid Build Coastguard Worker             case 10: path.cubicTo(diagonalPts[g], axisAlignedPts[f], diagonalPts[g]); break;
1799*c8dee2aaSAndroid Build Coastguard Worker         }
1800*c8dee2aaSAndroid Build Coastguard Worker         if (curveSelect == 0) {
1801*c8dee2aaSAndroid Build Coastguard Worker             check_convexity(reporter, path, true);
1802*c8dee2aaSAndroid Build Coastguard Worker         } else {
1803*c8dee2aaSAndroid Build Coastguard Worker             // We make a copy so that we don't cache the result on the passed in path.
1804*c8dee2aaSAndroid Build Coastguard Worker             SkPath copy(path);  // NOLINT(performance-unnecessary-copy-initialization)
1805*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !copy.isConvex());
1806*c8dee2aaSAndroid Build Coastguard Worker         }
1807*c8dee2aaSAndroid Build Coastguard Worker     }
1808*c8dee2aaSAndroid Build Coastguard Worker 
1809*c8dee2aaSAndroid Build Coastguard Worker 
1810*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
1811*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0xbe9171db), SkBits2Float(0xbd7eeb5d));  // -0.284072f, -0.0622362f
1812*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xbe9171db), SkBits2Float(0xbd7eea38));  // -0.284072f, -0.0622351f
1813*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xbe9171a0), SkBits2Float(0xbd7ee5a7));  // -0.28407f, -0.0622307f
1814*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xbe917147), SkBits2Float(0xbd7ed886));  // -0.284067f, -0.0622182f
1815*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xbe917378), SkBits2Float(0xbd7ee1a9));  // -0.284084f, -0.0622269f
1816*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xbe9171db), SkBits2Float(0xbd7eeb5d));  // -0.284072f, -0.0622362f
1817*c8dee2aaSAndroid Build Coastguard Worker     path.close();
1818*c8dee2aaSAndroid Build Coastguard Worker     check_convexity(reporter, path, false);
1819*c8dee2aaSAndroid Build Coastguard Worker 
1820*c8dee2aaSAndroid Build Coastguard Worker }
1821*c8dee2aaSAndroid Build Coastguard Worker 
test_isLine(skiatest::Reporter * reporter)1822*c8dee2aaSAndroid Build Coastguard Worker static void test_isLine(skiatest::Reporter* reporter) {
1823*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
1824*c8dee2aaSAndroid Build Coastguard Worker     SkPoint pts[2];
1825*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar value = SkIntToScalar(5);
1826*c8dee2aaSAndroid Build Coastguard Worker 
1827*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isLine(nullptr));
1828*c8dee2aaSAndroid Build Coastguard Worker 
1829*c8dee2aaSAndroid Build Coastguard Worker     // set some non-zero values
1830*c8dee2aaSAndroid Build Coastguard Worker     pts[0].set(value, value);
1831*c8dee2aaSAndroid Build Coastguard Worker     pts[1].set(value, value);
1832*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isLine(pts));
1833*c8dee2aaSAndroid Build Coastguard Worker     // check that pts was untouched
1834*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pts[0].equals(value, value));
1835*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pts[1].equals(value, value));
1836*c8dee2aaSAndroid Build Coastguard Worker 
1837*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar moveX = SkIntToScalar(1);
1838*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar moveY = SkIntToScalar(2);
1839*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, value != moveX && value != moveY);
1840*c8dee2aaSAndroid Build Coastguard Worker 
1841*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(moveX, moveY);
1842*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isLine(nullptr));
1843*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isLine(pts));
1844*c8dee2aaSAndroid Build Coastguard Worker     // check that pts was untouched
1845*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pts[0].equals(value, value));
1846*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pts[1].equals(value, value));
1847*c8dee2aaSAndroid Build Coastguard Worker 
1848*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar lineX = SkIntToScalar(2);
1849*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar lineY = SkIntToScalar(2);
1850*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, value != lineX && value != lineY);
1851*c8dee2aaSAndroid Build Coastguard Worker 
1852*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(lineX, lineY);
1853*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isLine(nullptr));
1854*c8dee2aaSAndroid Build Coastguard Worker 
1855*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !pts[0].equals(moveX, moveY));
1856*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !pts[1].equals(lineX, lineY));
1857*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isLine(pts));
1858*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pts[0].equals(moveX, moveY));
1859*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pts[1].equals(lineX, lineY));
1860*c8dee2aaSAndroid Build Coastguard Worker 
1861*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0, 0);  // too many points/verbs
1862*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isLine(nullptr));
1863*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isLine(pts));
1864*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pts[0].equals(moveX, moveY));
1865*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pts[1].equals(lineX, lineY));
1866*c8dee2aaSAndroid Build Coastguard Worker 
1867*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
1868*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(1, 1, 2, 2);
1869*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isLine(nullptr));
1870*c8dee2aaSAndroid Build Coastguard Worker }
1871*c8dee2aaSAndroid Build Coastguard Worker 
test_conservativelyContains(skiatest::Reporter * reporter)1872*c8dee2aaSAndroid Build Coastguard Worker static void test_conservativelyContains(skiatest::Reporter* reporter) {
1873*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
1874*c8dee2aaSAndroid Build Coastguard Worker 
1875*c8dee2aaSAndroid Build Coastguard Worker     // kBaseRect is used to construct most our test paths: a rect, a circle, and a round-rect.
1876*c8dee2aaSAndroid Build Coastguard Worker     static const SkRect kBaseRect = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
1877*c8dee2aaSAndroid Build Coastguard Worker 
1878*c8dee2aaSAndroid Build Coastguard Worker     // A circle that bounds kBaseRect (with a significant amount of slop)
1879*c8dee2aaSAndroid Build Coastguard Worker     SkScalar circleR = std::max(kBaseRect.width(), kBaseRect.height());
1880*c8dee2aaSAndroid Build Coastguard Worker     circleR *= 1.75f / 2;
1881*c8dee2aaSAndroid Build Coastguard Worker     static const SkPoint kCircleC = {kBaseRect.centerX(), kBaseRect.centerY()};
1882*c8dee2aaSAndroid Build Coastguard Worker 
1883*c8dee2aaSAndroid Build Coastguard Worker     // round-rect radii
1884*c8dee2aaSAndroid Build Coastguard Worker     static const SkScalar kRRRadii[] = {SkIntToScalar(5), SkIntToScalar(3)};
1885*c8dee2aaSAndroid Build Coastguard Worker 
1886*c8dee2aaSAndroid Build Coastguard Worker     static const struct SUPPRESS_VISIBILITY_WARNING {
1887*c8dee2aaSAndroid Build Coastguard Worker         SkRect fQueryRect;
1888*c8dee2aaSAndroid Build Coastguard Worker         bool   fInRect;
1889*c8dee2aaSAndroid Build Coastguard Worker         bool   fInCircle;
1890*c8dee2aaSAndroid Build Coastguard Worker         bool   fInRR;
1891*c8dee2aaSAndroid Build Coastguard Worker         bool   fInCubicRR;
1892*c8dee2aaSAndroid Build Coastguard Worker     } kQueries[] = {
1893*c8dee2aaSAndroid Build Coastguard Worker         {kBaseRect, true, true, false, false},
1894*c8dee2aaSAndroid Build Coastguard Worker 
1895*c8dee2aaSAndroid Build Coastguard Worker         // rect well inside of kBaseRect
1896*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeLTRB(kBaseRect.fLeft + 0.25f*kBaseRect.width(),
1897*c8dee2aaSAndroid Build Coastguard Worker                           kBaseRect.fTop + 0.25f*kBaseRect.height(),
1898*c8dee2aaSAndroid Build Coastguard Worker                           kBaseRect.fRight - 0.25f*kBaseRect.width(),
1899*c8dee2aaSAndroid Build Coastguard Worker                           kBaseRect.fBottom - 0.25f*kBaseRect.height()),
1900*c8dee2aaSAndroid Build Coastguard Worker                           true, true, true, true},
1901*c8dee2aaSAndroid Build Coastguard Worker 
1902*c8dee2aaSAndroid Build Coastguard Worker         // rects with edges off by one from kBaseRect's edges
1903*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop,
1904*c8dee2aaSAndroid Build Coastguard Worker                           kBaseRect.width(), kBaseRect.height() + 1),
1905*c8dee2aaSAndroid Build Coastguard Worker          false, true, false, false},
1906*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop,
1907*c8dee2aaSAndroid Build Coastguard Worker                           kBaseRect.width() + 1, kBaseRect.height()),
1908*c8dee2aaSAndroid Build Coastguard Worker          false, true, false, false},
1909*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop,
1910*c8dee2aaSAndroid Build Coastguard Worker                           kBaseRect.width() + 1, kBaseRect.height() + 1),
1911*c8dee2aaSAndroid Build Coastguard Worker          false, true, false, false},
1912*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(kBaseRect.fLeft - 1, kBaseRect.fTop,
1913*c8dee2aaSAndroid Build Coastguard Worker                           kBaseRect.width(), kBaseRect.height()),
1914*c8dee2aaSAndroid Build Coastguard Worker          false, true, false, false},
1915*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop - 1,
1916*c8dee2aaSAndroid Build Coastguard Worker                           kBaseRect.width(), kBaseRect.height()),
1917*c8dee2aaSAndroid Build Coastguard Worker          false, true, false, false},
1918*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(kBaseRect.fLeft - 1, kBaseRect.fTop,
1919*c8dee2aaSAndroid Build Coastguard Worker                           kBaseRect.width() + 2, kBaseRect.height()),
1920*c8dee2aaSAndroid Build Coastguard Worker          false, true, false, false},
1921*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop - 1,
1922*c8dee2aaSAndroid Build Coastguard Worker                           kBaseRect.width() + 2, kBaseRect.height()),
1923*c8dee2aaSAndroid Build Coastguard Worker          false, true, false, false},
1924*c8dee2aaSAndroid Build Coastguard Worker 
1925*c8dee2aaSAndroid Build Coastguard Worker         // zero-w/h rects at each corner of kBaseRect
1926*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop, 0, 0), true, true, false, false},
1927*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(kBaseRect.fRight, kBaseRect.fTop, 0, 0), true, true, false, true},
1928*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fBottom, 0, 0), true, true, false, true},
1929*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(kBaseRect.fRight, kBaseRect.fBottom, 0, 0), true, true, false, true},
1930*c8dee2aaSAndroid Build Coastguard Worker 
1931*c8dee2aaSAndroid Build Coastguard Worker         // far away rect
1932*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(10 * kBaseRect.fRight, 10 * kBaseRect.fBottom,
1933*c8dee2aaSAndroid Build Coastguard Worker                           SkIntToScalar(10), SkIntToScalar(10)),
1934*c8dee2aaSAndroid Build Coastguard Worker          false, false, false, false},
1935*c8dee2aaSAndroid Build Coastguard Worker 
1936*c8dee2aaSAndroid Build Coastguard Worker         // very large rect containing kBaseRect
1937*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(kBaseRect.fLeft - 5 * kBaseRect.width(),
1938*c8dee2aaSAndroid Build Coastguard Worker                           kBaseRect.fTop - 5 * kBaseRect.height(),
1939*c8dee2aaSAndroid Build Coastguard Worker                           11 * kBaseRect.width(), 11 * kBaseRect.height()),
1940*c8dee2aaSAndroid Build Coastguard Worker          false, false, false, false},
1941*c8dee2aaSAndroid Build Coastguard Worker 
1942*c8dee2aaSAndroid Build Coastguard Worker         // skinny rect that spans same y-range as kBaseRect
1943*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(kBaseRect.centerX(), kBaseRect.fTop,
1944*c8dee2aaSAndroid Build Coastguard Worker                           SkIntToScalar(1), kBaseRect.height()),
1945*c8dee2aaSAndroid Build Coastguard Worker          true, true, true, true},
1946*c8dee2aaSAndroid Build Coastguard Worker 
1947*c8dee2aaSAndroid Build Coastguard Worker         // short rect that spans same x-range as kBaseRect
1948*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.centerY(), kBaseRect.width(), SkScalar(1)),
1949*c8dee2aaSAndroid Build Coastguard Worker          true, true, true, true},
1950*c8dee2aaSAndroid Build Coastguard Worker 
1951*c8dee2aaSAndroid Build Coastguard Worker         // skinny rect that spans slightly larger y-range than kBaseRect
1952*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(kBaseRect.centerX(), kBaseRect.fTop,
1953*c8dee2aaSAndroid Build Coastguard Worker                           SkIntToScalar(1), kBaseRect.height() + 1),
1954*c8dee2aaSAndroid Build Coastguard Worker          false, true, false, false},
1955*c8dee2aaSAndroid Build Coastguard Worker 
1956*c8dee2aaSAndroid Build Coastguard Worker         // short rect that spans slightly larger x-range than kBaseRect
1957*c8dee2aaSAndroid Build Coastguard Worker         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.centerY(),
1958*c8dee2aaSAndroid Build Coastguard Worker                           kBaseRect.width() + 1, SkScalar(1)),
1959*c8dee2aaSAndroid Build Coastguard Worker          false, true, false, false},
1960*c8dee2aaSAndroid Build Coastguard Worker     };
1961*c8dee2aaSAndroid Build Coastguard Worker 
1962*c8dee2aaSAndroid Build Coastguard Worker     for (int inv = 0; inv < 4; ++inv) {
1963*c8dee2aaSAndroid Build Coastguard Worker         for (size_t q = 0; q < std::size(kQueries); ++q) {
1964*c8dee2aaSAndroid Build Coastguard Worker             SkRect qRect = kQueries[q].fQueryRect;
1965*c8dee2aaSAndroid Build Coastguard Worker             if (inv & 0x1) {
1966*c8dee2aaSAndroid Build Coastguard Worker                 using std::swap;
1967*c8dee2aaSAndroid Build Coastguard Worker                 swap(qRect.fLeft, qRect.fRight);
1968*c8dee2aaSAndroid Build Coastguard Worker             }
1969*c8dee2aaSAndroid Build Coastguard Worker             if (inv & 0x2) {
1970*c8dee2aaSAndroid Build Coastguard Worker                 using std::swap;
1971*c8dee2aaSAndroid Build Coastguard Worker                 swap(qRect.fTop, qRect.fBottom);
1972*c8dee2aaSAndroid Build Coastguard Worker             }
1973*c8dee2aaSAndroid Build Coastguard Worker             for (int d = 0; d < 2; ++d) {
1974*c8dee2aaSAndroid Build Coastguard Worker                 SkPathDirection dir = d ? SkPathDirection::kCCW : SkPathDirection::kCW;
1975*c8dee2aaSAndroid Build Coastguard Worker                 path.reset();
1976*c8dee2aaSAndroid Build Coastguard Worker                 path.addRect(kBaseRect, dir);
1977*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, kQueries[q].fInRect ==
1978*c8dee2aaSAndroid Build Coastguard Worker                                           path.conservativelyContainsRect(qRect));
1979*c8dee2aaSAndroid Build Coastguard Worker 
1980*c8dee2aaSAndroid Build Coastguard Worker                 path.reset();
1981*c8dee2aaSAndroid Build Coastguard Worker                 path.addCircle(kCircleC.fX, kCircleC.fY, circleR, dir);
1982*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, kQueries[q].fInCircle ==
1983*c8dee2aaSAndroid Build Coastguard Worker                                           path.conservativelyContainsRect(qRect));
1984*c8dee2aaSAndroid Build Coastguard Worker 
1985*c8dee2aaSAndroid Build Coastguard Worker                 path.reset();
1986*c8dee2aaSAndroid Build Coastguard Worker                 path.addRoundRect(kBaseRect, kRRRadii[0], kRRRadii[1], dir);
1987*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, kQueries[q].fInRR ==
1988*c8dee2aaSAndroid Build Coastguard Worker                                           path.conservativelyContainsRect(qRect));
1989*c8dee2aaSAndroid Build Coastguard Worker 
1990*c8dee2aaSAndroid Build Coastguard Worker                 path.reset();
1991*c8dee2aaSAndroid Build Coastguard Worker                 path.moveTo(kBaseRect.fLeft + kRRRadii[0], kBaseRect.fTop);
1992*c8dee2aaSAndroid Build Coastguard Worker                 path.cubicTo(kBaseRect.fLeft + kRRRadii[0] / 2, kBaseRect.fTop,
1993*c8dee2aaSAndroid Build Coastguard Worker                              kBaseRect.fLeft, kBaseRect.fTop + kRRRadii[1] / 2,
1994*c8dee2aaSAndroid Build Coastguard Worker                              kBaseRect.fLeft, kBaseRect.fTop + kRRRadii[1]);
1995*c8dee2aaSAndroid Build Coastguard Worker                 path.lineTo(kBaseRect.fLeft, kBaseRect.fBottom);
1996*c8dee2aaSAndroid Build Coastguard Worker                 path.lineTo(kBaseRect.fRight, kBaseRect.fBottom);
1997*c8dee2aaSAndroid Build Coastguard Worker                 path.lineTo(kBaseRect.fRight, kBaseRect.fTop);
1998*c8dee2aaSAndroid Build Coastguard Worker                 path.close();
1999*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, kQueries[q].fInCubicRR ==
2000*c8dee2aaSAndroid Build Coastguard Worker                                           path.conservativelyContainsRect(qRect));
2001*c8dee2aaSAndroid Build Coastguard Worker 
2002*c8dee2aaSAndroid Build Coastguard Worker             }
2003*c8dee2aaSAndroid Build Coastguard Worker             // Slightly non-convex shape, shouldn't contain any rects.
2004*c8dee2aaSAndroid Build Coastguard Worker             path.reset();
2005*c8dee2aaSAndroid Build Coastguard Worker             path.moveTo(0, 0);
2006*c8dee2aaSAndroid Build Coastguard Worker             path.lineTo(SkIntToScalar(50), 0.05f);
2007*c8dee2aaSAndroid Build Coastguard Worker             path.lineTo(SkIntToScalar(100), 0);
2008*c8dee2aaSAndroid Build Coastguard Worker             path.lineTo(SkIntToScalar(100), SkIntToScalar(100));
2009*c8dee2aaSAndroid Build Coastguard Worker             path.lineTo(0, SkIntToScalar(100));
2010*c8dee2aaSAndroid Build Coastguard Worker             path.close();
2011*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(qRect));
2012*c8dee2aaSAndroid Build Coastguard Worker         }
2013*c8dee2aaSAndroid Build Coastguard Worker     }
2014*c8dee2aaSAndroid Build Coastguard Worker 
2015*c8dee2aaSAndroid Build Coastguard Worker     // make sure a minimal convex shape works, a right tri with edges along pos x and y axes.
2016*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
2017*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0);
2018*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkIntToScalar(100), 0);
2019*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0, SkIntToScalar(100));
2020*c8dee2aaSAndroid Build Coastguard Worker 
2021*c8dee2aaSAndroid Build Coastguard Worker     // inside, on along top edge
2022*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(50), 0,
2023*c8dee2aaSAndroid Build Coastguard Worker                                                                                SkIntToScalar(10),
2024*c8dee2aaSAndroid Build Coastguard Worker                                                                                SkIntToScalar(10))));
2025*c8dee2aaSAndroid Build Coastguard Worker     // above
2026*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(
2027*c8dee2aaSAndroid Build Coastguard Worker         SkRect::MakeXYWH(SkIntToScalar(50),
2028*c8dee2aaSAndroid Build Coastguard Worker                          SkIntToScalar(-10),
2029*c8dee2aaSAndroid Build Coastguard Worker                          SkIntToScalar(10),
2030*c8dee2aaSAndroid Build Coastguard Worker                          SkIntToScalar(10))));
2031*c8dee2aaSAndroid Build Coastguard Worker     // to the left
2032*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(-10),
2033*c8dee2aaSAndroid Build Coastguard Worker                                                                                 SkIntToScalar(5),
2034*c8dee2aaSAndroid Build Coastguard Worker                                                                                 SkIntToScalar(5),
2035*c8dee2aaSAndroid Build Coastguard Worker                                                                                 SkIntToScalar(5))));
2036*c8dee2aaSAndroid Build Coastguard Worker 
2037*c8dee2aaSAndroid Build Coastguard Worker     // outside the diagonal edge
2038*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(10),
2039*c8dee2aaSAndroid Build Coastguard Worker                                                                                 SkIntToScalar(200),
2040*c8dee2aaSAndroid Build Coastguard Worker                                                                                 SkIntToScalar(20),
2041*c8dee2aaSAndroid Build Coastguard Worker                                                                                 SkIntToScalar(5))));
2042*c8dee2aaSAndroid Build Coastguard Worker 
2043*c8dee2aaSAndroid Build Coastguard Worker 
2044*c8dee2aaSAndroid Build Coastguard Worker     // Test that multiple move commands do not cause asserts.
2045*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkIntToScalar(100), SkIntToScalar(100));
2046*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(50), 0,
2047*c8dee2aaSAndroid Build Coastguard Worker                                                                                SkIntToScalar(10),
2048*c8dee2aaSAndroid Build Coastguard Worker                                                                                SkIntToScalar(10))));
2049*c8dee2aaSAndroid Build Coastguard Worker 
2050*c8dee2aaSAndroid Build Coastguard Worker     // Same as above path and first test but with an extra moveTo.
2051*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
2052*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(100, 100);
2053*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0);
2054*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkIntToScalar(100), 0);
2055*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0, SkIntToScalar(100));
2056*c8dee2aaSAndroid Build Coastguard Worker     // Convexity logic treats a path as filled and closed, so that multiple (non-trailing) moveTos
2057*c8dee2aaSAndroid Build Coastguard Worker     // have no effect on convexity
2058*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.conservativelyContainsRect(
2059*c8dee2aaSAndroid Build Coastguard Worker         SkRect::MakeXYWH(SkIntToScalar(50), 0,
2060*c8dee2aaSAndroid Build Coastguard Worker                          SkIntToScalar(10),
2061*c8dee2aaSAndroid Build Coastguard Worker                          SkIntToScalar(10))));
2062*c8dee2aaSAndroid Build Coastguard Worker 
2063*c8dee2aaSAndroid Build Coastguard Worker     // Same as above path and first test but with the extra moveTo making a degenerate sub-path
2064*c8dee2aaSAndroid Build Coastguard Worker     // following the non-empty sub-path. Verifies that this does not trigger assertions.
2065*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
2066*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0);
2067*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkIntToScalar(100), 0);
2068*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0, SkIntToScalar(100));
2069*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(100, 100);
2070*c8dee2aaSAndroid Build Coastguard Worker 
2071*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(50), 0,
2072*c8dee2aaSAndroid Build Coastguard Worker                                                                                SkIntToScalar(10),
2073*c8dee2aaSAndroid Build Coastguard Worker                                                                                SkIntToScalar(10))));
2074*c8dee2aaSAndroid Build Coastguard Worker 
2075*c8dee2aaSAndroid Build Coastguard Worker     // Test that multiple move commands do not cause asserts and that the function
2076*c8dee2aaSAndroid Build Coastguard Worker     // is not confused by the multiple moves.
2077*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
2078*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0);
2079*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkIntToScalar(100), 0);
2080*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0, SkIntToScalar(100));
2081*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, SkIntToScalar(200));
2082*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkIntToScalar(100), SkIntToScalar(200));
2083*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0, SkIntToScalar(300));
2084*c8dee2aaSAndroid Build Coastguard Worker 
2085*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(
2086*c8dee2aaSAndroid Build Coastguard Worker                                                             SkRect::MakeXYWH(SkIntToScalar(50), 0,
2087*c8dee2aaSAndroid Build Coastguard Worker                                                                              SkIntToScalar(10),
2088*c8dee2aaSAndroid Build Coastguard Worker                                                                              SkIntToScalar(10))));
2089*c8dee2aaSAndroid Build Coastguard Worker 
2090*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
2091*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(100, 100);
2092*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeXYWH(0, 0, 1, 1)));
2093*c8dee2aaSAndroid Build Coastguard Worker 
2094*c8dee2aaSAndroid Build Coastguard Worker     // An empty path should not contain any rectangle. It's questionable whether an empty path
2095*c8dee2aaSAndroid Build Coastguard Worker     // contains an empty rectangle. However, since it is a conservative test it is ok to
2096*c8dee2aaSAndroid Build Coastguard Worker     // return false.
2097*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
2098*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeWH(1,1)));
2099*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeWH(0,0)));
2100*c8dee2aaSAndroid Build Coastguard Worker 
2101*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
2102*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(50, 50);
2103*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(0, 0, 100, 0, 50, 50);
2104*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeWH(100, 100)));
2105*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeWH(30, 30)));
2106*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeWH(1,1)));
2107*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeWH(0,0)));
2108*c8dee2aaSAndroid Build Coastguard Worker 
2109*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
2110*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(50, 50);
2111*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(100, 100, 50, 50);
2112*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeWH(1,1)));
2113*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeWH(0,0)));
2114*c8dee2aaSAndroid Build Coastguard Worker }
2115*c8dee2aaSAndroid Build Coastguard Worker 
test_isRect_open_close(skiatest::Reporter * reporter)2116*c8dee2aaSAndroid Build Coastguard Worker static void test_isRect_open_close(skiatest::Reporter* reporter) {
2117*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
2118*c8dee2aaSAndroid Build Coastguard Worker     bool isClosed;
2119*c8dee2aaSAndroid Build Coastguard Worker 
2120*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0); path.lineTo(1, 0); path.lineTo(1, 1); path.lineTo(0, 1);
2121*c8dee2aaSAndroid Build Coastguard Worker     path.close();
2122*c8dee2aaSAndroid Build Coastguard Worker 
2123*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isRect(nullptr, &isClosed, nullptr));
2124*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, isClosed);
2125*c8dee2aaSAndroid Build Coastguard Worker }
2126*c8dee2aaSAndroid Build Coastguard Worker 
2127*c8dee2aaSAndroid Build Coastguard Worker // Simple isRect test is inline TestPath, below.
2128*c8dee2aaSAndroid Build Coastguard Worker // test_isRect provides more extensive testing.
test_isRect(skiatest::Reporter * reporter)2129*c8dee2aaSAndroid Build Coastguard Worker static void test_isRect(skiatest::Reporter* reporter) {
2130*c8dee2aaSAndroid Build Coastguard Worker     test_isRect_open_close(reporter);
2131*c8dee2aaSAndroid Build Coastguard Worker 
2132*c8dee2aaSAndroid Build Coastguard Worker     // passing tests (all moveTo / lineTo...
2133*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
2134*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
2135*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
2136*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
2137*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
2138*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
2139*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
2140*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
2141*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
2142*c8dee2aaSAndroid Build Coastguard Worker     SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f}, {1, 0}, {.5f, 0}};
2143*c8dee2aaSAndroid Build Coastguard Worker     SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1}, {0, 1}, {0, .5f}};
2144*c8dee2aaSAndroid Build Coastguard Worker     SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}};
2145*c8dee2aaSAndroid Build Coastguard Worker     SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
2146*c8dee2aaSAndroid Build Coastguard Worker     SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}};
2147*c8dee2aaSAndroid Build Coastguard Worker     SkPoint rf[] = {{1, 0}, {8, 0}, {8, 8}, {0, 8}, {0, 0}};
2148*c8dee2aaSAndroid Build Coastguard Worker 
2149*c8dee2aaSAndroid Build Coastguard Worker     // failing tests
2150*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
2151*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
2152*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
2153*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
2154*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
2155*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
2156*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
2157*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
2158*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f9[] = {{1, 0}, {8, 0}, {8, 8}, {0, 8}, {0, 0}, {2, 0}}; // overlaps
2159*c8dee2aaSAndroid Build Coastguard Worker     SkPoint fa[] = {{1, 0}, {8, 0}, {8, 8}, {0, 8}, {0, -1}, {1, -1}}; // non colinear gap
2160*c8dee2aaSAndroid Build Coastguard Worker     SkPoint fb[] = {{1, 0}, {8, 0}, {8, 8}, {0, 8}, {0, 1}}; // falls short
2161*c8dee2aaSAndroid Build Coastguard Worker 
2162*c8dee2aaSAndroid Build Coastguard Worker     // no close, but we should detect them as fillably the same as a rect
2163*c8dee2aaSAndroid Build Coastguard Worker     SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
2164*c8dee2aaSAndroid Build Coastguard Worker     SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}};
2165*c8dee2aaSAndroid Build Coastguard Worker     SkPoint c3[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}, {0, 0}}; // hit the start
2166*c8dee2aaSAndroid Build Coastguard Worker 
2167*c8dee2aaSAndroid Build Coastguard Worker     // like c2, but we double-back on ourselves
2168*c8dee2aaSAndroid Build Coastguard Worker     SkPoint d1[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}, {0, 2}};
2169*c8dee2aaSAndroid Build Coastguard Worker     // like c2, but we overshoot the start point
2170*c8dee2aaSAndroid Build Coastguard Worker     SkPoint d2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, -1}};
2171*c8dee2aaSAndroid Build Coastguard Worker     SkPoint d3[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, -1}, {0, 0}};
2172*c8dee2aaSAndroid Build Coastguard Worker 
2173*c8dee2aaSAndroid Build Coastguard Worker     struct IsRectTest {
2174*c8dee2aaSAndroid Build Coastguard Worker         SkPoint *fPoints;
2175*c8dee2aaSAndroid Build Coastguard Worker         int fPointCount;
2176*c8dee2aaSAndroid Build Coastguard Worker         bool fClose;
2177*c8dee2aaSAndroid Build Coastguard Worker         bool fIsRect;
2178*c8dee2aaSAndroid Build Coastguard Worker     } tests[] = {
2179*c8dee2aaSAndroid Build Coastguard Worker         { r1, std::size(r1), true, true },
2180*c8dee2aaSAndroid Build Coastguard Worker         { r2, std::size(r2), true, true },
2181*c8dee2aaSAndroid Build Coastguard Worker         { r3, std::size(r3), true, true },
2182*c8dee2aaSAndroid Build Coastguard Worker         { r4, std::size(r4), true, true },
2183*c8dee2aaSAndroid Build Coastguard Worker         { r5, std::size(r5), true, true },
2184*c8dee2aaSAndroid Build Coastguard Worker         { r6, std::size(r6), true, true },
2185*c8dee2aaSAndroid Build Coastguard Worker         { r7, std::size(r7), true, true },
2186*c8dee2aaSAndroid Build Coastguard Worker         { r8, std::size(r8), true, true },
2187*c8dee2aaSAndroid Build Coastguard Worker         { r9, std::size(r9), true, true },
2188*c8dee2aaSAndroid Build Coastguard Worker         { ra, std::size(ra), true, true },
2189*c8dee2aaSAndroid Build Coastguard Worker         { rb, std::size(rb), true, true },
2190*c8dee2aaSAndroid Build Coastguard Worker         { rc, std::size(rc), true, true },
2191*c8dee2aaSAndroid Build Coastguard Worker         { rd, std::size(rd), true, true },
2192*c8dee2aaSAndroid Build Coastguard Worker         { re, std::size(re), true, true },
2193*c8dee2aaSAndroid Build Coastguard Worker         { rf, std::size(rf), true, true },
2194*c8dee2aaSAndroid Build Coastguard Worker 
2195*c8dee2aaSAndroid Build Coastguard Worker         { f1, std::size(f1), true, false },
2196*c8dee2aaSAndroid Build Coastguard Worker         { f2, std::size(f2), true, false },
2197*c8dee2aaSAndroid Build Coastguard Worker         { f3, std::size(f3), true, false },
2198*c8dee2aaSAndroid Build Coastguard Worker         { f4, std::size(f4), true, false },
2199*c8dee2aaSAndroid Build Coastguard Worker         { f5, std::size(f5), true, false },
2200*c8dee2aaSAndroid Build Coastguard Worker         { f6, std::size(f6), true, false },
2201*c8dee2aaSAndroid Build Coastguard Worker         { f7, std::size(f7), true, false },
2202*c8dee2aaSAndroid Build Coastguard Worker         { f8, std::size(f8), true, false },
2203*c8dee2aaSAndroid Build Coastguard Worker         { f9, std::size(f9), true, false },
2204*c8dee2aaSAndroid Build Coastguard Worker         { fa, std::size(fa), true, false },
2205*c8dee2aaSAndroid Build Coastguard Worker         { fb, std::size(fb), true, false },
2206*c8dee2aaSAndroid Build Coastguard Worker 
2207*c8dee2aaSAndroid Build Coastguard Worker         { c1, std::size(c1), false, true },
2208*c8dee2aaSAndroid Build Coastguard Worker         { c2, std::size(c2), false, true },
2209*c8dee2aaSAndroid Build Coastguard Worker         { c3, std::size(c3), false, true },
2210*c8dee2aaSAndroid Build Coastguard Worker 
2211*c8dee2aaSAndroid Build Coastguard Worker         { d1, std::size(d1), false, false },
2212*c8dee2aaSAndroid Build Coastguard Worker         { d2, std::size(d2), false, true },
2213*c8dee2aaSAndroid Build Coastguard Worker         { d3, std::size(d3), false, false },
2214*c8dee2aaSAndroid Build Coastguard Worker     };
2215*c8dee2aaSAndroid Build Coastguard Worker 
2216*c8dee2aaSAndroid Build Coastguard Worker     const size_t testCount = std::size(tests);
2217*c8dee2aaSAndroid Build Coastguard Worker     int index;
2218*c8dee2aaSAndroid Build Coastguard Worker     for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
2219*c8dee2aaSAndroid Build Coastguard Worker         SkPath path;
2220*c8dee2aaSAndroid Build Coastguard Worker         path.moveTo(tests[testIndex].fPoints[0].fX, tests[testIndex].fPoints[0].fY);
2221*c8dee2aaSAndroid Build Coastguard Worker         for (index = 1; index < tests[testIndex].fPointCount; ++index) {
2222*c8dee2aaSAndroid Build Coastguard Worker             path.lineTo(tests[testIndex].fPoints[index].fX, tests[testIndex].fPoints[index].fY);
2223*c8dee2aaSAndroid Build Coastguard Worker         }
2224*c8dee2aaSAndroid Build Coastguard Worker         if (tests[testIndex].fClose) {
2225*c8dee2aaSAndroid Build Coastguard Worker             path.close();
2226*c8dee2aaSAndroid Build Coastguard Worker         }
2227*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, tests[testIndex].fIsRect == path.isRect(nullptr));
2228*c8dee2aaSAndroid Build Coastguard Worker 
2229*c8dee2aaSAndroid Build Coastguard Worker         if (tests[testIndex].fIsRect) {
2230*c8dee2aaSAndroid Build Coastguard Worker             SkRect computed, expected;
2231*c8dee2aaSAndroid Build Coastguard Worker             bool isClosed;
2232*c8dee2aaSAndroid Build Coastguard Worker             SkPathDirection direction;
2233*c8dee2aaSAndroid Build Coastguard Worker             int pointCount = tests[testIndex].fPointCount - (d2 == tests[testIndex].fPoints);
2234*c8dee2aaSAndroid Build Coastguard Worker             expected.setBounds(tests[testIndex].fPoints, pointCount);
2235*c8dee2aaSAndroid Build Coastguard Worker             SkPathFirstDirection cheapDirection = SkPathPriv::ComputeFirstDirection(path);
2236*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, cheapDirection != SkPathFirstDirection::kUnknown);
2237*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, path.isRect(&computed, &isClosed, &direction));
2238*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, expected == computed);
2239*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, isClosed == tests[testIndex].fClose);
2240*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, SkPathPriv::AsFirstDirection(direction) == cheapDirection);
2241*c8dee2aaSAndroid Build Coastguard Worker         } else {
2242*c8dee2aaSAndroid Build Coastguard Worker             SkRect computed;
2243*c8dee2aaSAndroid Build Coastguard Worker             computed.setLTRB(123, 456, 789, 1011);
2244*c8dee2aaSAndroid Build Coastguard Worker             for (auto c : {true, false})
2245*c8dee2aaSAndroid Build Coastguard Worker             for (auto d : {SkPathDirection::kCW, SkPathDirection::kCCW}) {
2246*c8dee2aaSAndroid Build Coastguard Worker               bool isClosed = c;
2247*c8dee2aaSAndroid Build Coastguard Worker               SkPathDirection direction = d;
2248*c8dee2aaSAndroid Build Coastguard Worker               REPORTER_ASSERT(reporter, !path.isRect(&computed, &isClosed, &direction));
2249*c8dee2aaSAndroid Build Coastguard Worker               REPORTER_ASSERT(reporter, computed.fLeft == 123 && computed.fTop == 456);
2250*c8dee2aaSAndroid Build Coastguard Worker               REPORTER_ASSERT(reporter, computed.fRight == 789 && computed.fBottom == 1011);
2251*c8dee2aaSAndroid Build Coastguard Worker               REPORTER_ASSERT(reporter, isClosed == c);
2252*c8dee2aaSAndroid Build Coastguard Worker               REPORTER_ASSERT(reporter, direction == d);
2253*c8dee2aaSAndroid Build Coastguard Worker             }
2254*c8dee2aaSAndroid Build Coastguard Worker         }
2255*c8dee2aaSAndroid Build Coastguard Worker     }
2256*c8dee2aaSAndroid Build Coastguard Worker 
2257*c8dee2aaSAndroid Build Coastguard Worker     // fail, close then line
2258*c8dee2aaSAndroid Build Coastguard Worker     SkPath path1;
2259*c8dee2aaSAndroid Build Coastguard Worker     path1.moveTo(r1[0].fX, r1[0].fY);
2260*c8dee2aaSAndroid Build Coastguard Worker     for (index = 1; index < SkToInt(std::size(r1)); ++index) {
2261*c8dee2aaSAndroid Build Coastguard Worker         path1.lineTo(r1[index].fX, r1[index].fY);
2262*c8dee2aaSAndroid Build Coastguard Worker     }
2263*c8dee2aaSAndroid Build Coastguard Worker     path1.close();
2264*c8dee2aaSAndroid Build Coastguard Worker     path1.lineTo(1, 0);
2265*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path1.isRect(nullptr));
2266*c8dee2aaSAndroid Build Coastguard Worker 
2267*c8dee2aaSAndroid Build Coastguard Worker     // fail, move in the middle
2268*c8dee2aaSAndroid Build Coastguard Worker     path1.reset();
2269*c8dee2aaSAndroid Build Coastguard Worker     path1.moveTo(r1[0].fX, r1[0].fY);
2270*c8dee2aaSAndroid Build Coastguard Worker     for (index = 1; index < SkToInt(std::size(r1)); ++index) {
2271*c8dee2aaSAndroid Build Coastguard Worker         if (index == 2) {
2272*c8dee2aaSAndroid Build Coastguard Worker             path1.moveTo(1, .5f);
2273*c8dee2aaSAndroid Build Coastguard Worker         }
2274*c8dee2aaSAndroid Build Coastguard Worker         path1.lineTo(r1[index].fX, r1[index].fY);
2275*c8dee2aaSAndroid Build Coastguard Worker     }
2276*c8dee2aaSAndroid Build Coastguard Worker     path1.close();
2277*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path1.isRect(nullptr));
2278*c8dee2aaSAndroid Build Coastguard Worker 
2279*c8dee2aaSAndroid Build Coastguard Worker     // fail, move on the edge
2280*c8dee2aaSAndroid Build Coastguard Worker     path1.reset();
2281*c8dee2aaSAndroid Build Coastguard Worker     for (index = 1; index < SkToInt(std::size(r1)); ++index) {
2282*c8dee2aaSAndroid Build Coastguard Worker         path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
2283*c8dee2aaSAndroid Build Coastguard Worker         path1.lineTo(r1[index].fX, r1[index].fY);
2284*c8dee2aaSAndroid Build Coastguard Worker     }
2285*c8dee2aaSAndroid Build Coastguard Worker     path1.close();
2286*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path1.isRect(nullptr));
2287*c8dee2aaSAndroid Build Coastguard Worker 
2288*c8dee2aaSAndroid Build Coastguard Worker     // fail, quad
2289*c8dee2aaSAndroid Build Coastguard Worker     path1.reset();
2290*c8dee2aaSAndroid Build Coastguard Worker     path1.moveTo(r1[0].fX, r1[0].fY);
2291*c8dee2aaSAndroid Build Coastguard Worker     for (index = 1; index < SkToInt(std::size(r1)); ++index) {
2292*c8dee2aaSAndroid Build Coastguard Worker         if (index == 2) {
2293*c8dee2aaSAndroid Build Coastguard Worker             path1.quadTo(1, .5f, 1, .5f);
2294*c8dee2aaSAndroid Build Coastguard Worker         }
2295*c8dee2aaSAndroid Build Coastguard Worker         path1.lineTo(r1[index].fX, r1[index].fY);
2296*c8dee2aaSAndroid Build Coastguard Worker     }
2297*c8dee2aaSAndroid Build Coastguard Worker     path1.close();
2298*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path1.isRect(nullptr));
2299*c8dee2aaSAndroid Build Coastguard Worker 
2300*c8dee2aaSAndroid Build Coastguard Worker     // fail, cubic
2301*c8dee2aaSAndroid Build Coastguard Worker     path1.reset();
2302*c8dee2aaSAndroid Build Coastguard Worker     path1.moveTo(r1[0].fX, r1[0].fY);
2303*c8dee2aaSAndroid Build Coastguard Worker     for (index = 1; index < SkToInt(std::size(r1)); ++index) {
2304*c8dee2aaSAndroid Build Coastguard Worker         if (index == 2) {
2305*c8dee2aaSAndroid Build Coastguard Worker             path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
2306*c8dee2aaSAndroid Build Coastguard Worker         }
2307*c8dee2aaSAndroid Build Coastguard Worker         path1.lineTo(r1[index].fX, r1[index].fY);
2308*c8dee2aaSAndroid Build Coastguard Worker     }
2309*c8dee2aaSAndroid Build Coastguard Worker     path1.close();
2310*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path1.isRect(nullptr));
2311*c8dee2aaSAndroid Build Coastguard Worker }
2312*c8dee2aaSAndroid Build Coastguard Worker 
check_simple_rect(skiatest::Reporter * reporter,const SkPath & path,bool isClosed,const SkRect & rect,SkPathDirection dir,unsigned start)2313*c8dee2aaSAndroid Build Coastguard Worker static void check_simple_rect(skiatest::Reporter* reporter, const SkPath& path, bool isClosed,
2314*c8dee2aaSAndroid Build Coastguard Worker                               const SkRect& rect, SkPathDirection dir, unsigned start) {
2315*c8dee2aaSAndroid Build Coastguard Worker     SkRect r = SkRect::MakeEmpty();
2316*c8dee2aaSAndroid Build Coastguard Worker     SkPathDirection d = SkPathDirection::kCCW;
2317*c8dee2aaSAndroid Build Coastguard Worker     unsigned s = ~0U;
2318*c8dee2aaSAndroid Build Coastguard Worker 
2319*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathPriv::IsSimpleRect(path, false, &r, &d, &s) == isClosed);
2320*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathPriv::IsSimpleRect(path, true, &r, &d, &s));
2321*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, r == rect);
2322*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, d == dir);
2323*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, s == start);
2324*c8dee2aaSAndroid Build Coastguard Worker }
2325*c8dee2aaSAndroid Build Coastguard Worker 
test_is_closed_rect(skiatest::Reporter * reporter)2326*c8dee2aaSAndroid Build Coastguard Worker static void test_is_closed_rect(skiatest::Reporter* reporter) {
2327*c8dee2aaSAndroid Build Coastguard Worker     using std::swap;
2328*c8dee2aaSAndroid Build Coastguard Worker     SkRect r = SkRect::MakeEmpty();
2329*c8dee2aaSAndroid Build Coastguard Worker     SkPathDirection d = SkPathDirection::kCCW;
2330*c8dee2aaSAndroid Build Coastguard Worker     unsigned s = ~0U;
2331*c8dee2aaSAndroid Build Coastguard Worker 
2332*c8dee2aaSAndroid Build Coastguard Worker     const SkRect testRect = SkRect::MakeXYWH(10, 10, 50, 70);
2333*c8dee2aaSAndroid Build Coastguard Worker     const SkRect emptyRect = SkRect::MakeEmpty();
2334*c8dee2aaSAndroid Build Coastguard Worker     for (int start = 0; start < 4; ++start) {
2335*c8dee2aaSAndroid Build Coastguard Worker         for (auto dir : {SkPathDirection::kCCW, SkPathDirection::kCW}) {
2336*c8dee2aaSAndroid Build Coastguard Worker             SkPath path;
2337*c8dee2aaSAndroid Build Coastguard Worker             path.addRect(testRect, dir, start);
2338*c8dee2aaSAndroid Build Coastguard Worker             check_simple_rect(reporter, path, true, testRect, dir, start);
2339*c8dee2aaSAndroid Build Coastguard Worker             path.close();
2340*c8dee2aaSAndroid Build Coastguard Worker             check_simple_rect(reporter, path, true, testRect, dir, start);
2341*c8dee2aaSAndroid Build Coastguard Worker             SkPath path2 = path;
2342*c8dee2aaSAndroid Build Coastguard Worker             path2.lineTo(10, 10);
2343*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path2, false, &r, &d, &s));
2344*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path2, true, &r, &d, &s));
2345*c8dee2aaSAndroid Build Coastguard Worker             path2 = path;
2346*c8dee2aaSAndroid Build Coastguard Worker             path2.moveTo(10, 10);
2347*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path2, false, &r, &d, &s));
2348*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path2, true, &r, &d, &s));
2349*c8dee2aaSAndroid Build Coastguard Worker             path2 = path;
2350*c8dee2aaSAndroid Build Coastguard Worker             path2.addRect(testRect, dir, start);
2351*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path2, false, &r, &d, &s));
2352*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path2, true, &r, &d, &s));
2353*c8dee2aaSAndroid Build Coastguard Worker             // Make the path by hand, manually closing it.
2354*c8dee2aaSAndroid Build Coastguard Worker             path2.reset();
2355*c8dee2aaSAndroid Build Coastguard Worker             SkPoint firstPt = {0.f, 0.f};
2356*c8dee2aaSAndroid Build Coastguard Worker             for (auto [v, verbPts, w] : SkPathPriv::Iterate(path)) {
2357*c8dee2aaSAndroid Build Coastguard Worker                 switch(v) {
2358*c8dee2aaSAndroid Build Coastguard Worker                     case SkPathVerb::kMove:
2359*c8dee2aaSAndroid Build Coastguard Worker                         firstPt = verbPts[0];
2360*c8dee2aaSAndroid Build Coastguard Worker                         path2.moveTo(verbPts[0]);
2361*c8dee2aaSAndroid Build Coastguard Worker                         break;
2362*c8dee2aaSAndroid Build Coastguard Worker                     case SkPathVerb::kLine:
2363*c8dee2aaSAndroid Build Coastguard Worker                         path2.lineTo(verbPts[1]);
2364*c8dee2aaSAndroid Build Coastguard Worker                         break;
2365*c8dee2aaSAndroid Build Coastguard Worker                     default:
2366*c8dee2aaSAndroid Build Coastguard Worker                         break;
2367*c8dee2aaSAndroid Build Coastguard Worker                 }
2368*c8dee2aaSAndroid Build Coastguard Worker             }
2369*c8dee2aaSAndroid Build Coastguard Worker             // We haven't closed it yet...
2370*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path2, false, &r, &d, &s));
2371*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path2, true, &r, &d, &s));
2372*c8dee2aaSAndroid Build Coastguard Worker             // ... now we do and test again.
2373*c8dee2aaSAndroid Build Coastguard Worker             path2.lineTo(firstPt);
2374*c8dee2aaSAndroid Build Coastguard Worker             check_simple_rect(reporter, path2, false, testRect, dir, start);
2375*c8dee2aaSAndroid Build Coastguard Worker             // A redundant close shouldn't cause a failure.
2376*c8dee2aaSAndroid Build Coastguard Worker             path2.close();
2377*c8dee2aaSAndroid Build Coastguard Worker             check_simple_rect(reporter, path2, true, testRect, dir, start);
2378*c8dee2aaSAndroid Build Coastguard Worker             // Degenerate point and line rects are not allowed
2379*c8dee2aaSAndroid Build Coastguard Worker             path2.reset();
2380*c8dee2aaSAndroid Build Coastguard Worker             path2.addRect(emptyRect, dir, start);
2381*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path2, false, &r, &d, &s));
2382*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path2, true, &r, &d, &s));
2383*c8dee2aaSAndroid Build Coastguard Worker             SkRect degenRect = testRect;
2384*c8dee2aaSAndroid Build Coastguard Worker             degenRect.fLeft = degenRect.fRight;
2385*c8dee2aaSAndroid Build Coastguard Worker             path2.reset();
2386*c8dee2aaSAndroid Build Coastguard Worker             path2.addRect(degenRect, dir, start);
2387*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path2, false, &r, &d, &s));
2388*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path2, true, &r, &d, &s));
2389*c8dee2aaSAndroid Build Coastguard Worker             degenRect = testRect;
2390*c8dee2aaSAndroid Build Coastguard Worker             degenRect.fTop = degenRect.fBottom;
2391*c8dee2aaSAndroid Build Coastguard Worker             path2.reset();
2392*c8dee2aaSAndroid Build Coastguard Worker             path2.addRect(degenRect, dir, start);
2393*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path2, false, &r, &d, &s));
2394*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path2, true, &r, &d, &s));
2395*c8dee2aaSAndroid Build Coastguard Worker             // An inverted rect makes a rect path, but changes the winding dir and start point.
2396*c8dee2aaSAndroid Build Coastguard Worker             SkPathDirection swapDir = (dir == SkPathDirection::kCW)
2397*c8dee2aaSAndroid Build Coastguard Worker                                             ? SkPathDirection::kCCW
2398*c8dee2aaSAndroid Build Coastguard Worker                                             : SkPathDirection::kCW;
2399*c8dee2aaSAndroid Build Coastguard Worker             static constexpr unsigned kXSwapStarts[] = { 1, 0, 3, 2 };
2400*c8dee2aaSAndroid Build Coastguard Worker             static constexpr unsigned kYSwapStarts[] = { 3, 2, 1, 0 };
2401*c8dee2aaSAndroid Build Coastguard Worker             SkRect swapRect = testRect;
2402*c8dee2aaSAndroid Build Coastguard Worker             swap(swapRect.fLeft, swapRect.fRight);
2403*c8dee2aaSAndroid Build Coastguard Worker             path2.reset();
2404*c8dee2aaSAndroid Build Coastguard Worker             path2.addRect(swapRect, dir, start);
2405*c8dee2aaSAndroid Build Coastguard Worker             check_simple_rect(reporter, path2, true, testRect, swapDir, kXSwapStarts[start]);
2406*c8dee2aaSAndroid Build Coastguard Worker             swapRect = testRect;
2407*c8dee2aaSAndroid Build Coastguard Worker             swap(swapRect.fTop, swapRect.fBottom);
2408*c8dee2aaSAndroid Build Coastguard Worker             path2.reset();
2409*c8dee2aaSAndroid Build Coastguard Worker             path2.addRect(swapRect, dir, start);
2410*c8dee2aaSAndroid Build Coastguard Worker             check_simple_rect(reporter, path2, true, testRect, swapDir, kYSwapStarts[start]);
2411*c8dee2aaSAndroid Build Coastguard Worker         }
2412*c8dee2aaSAndroid Build Coastguard Worker     }
2413*c8dee2aaSAndroid Build Coastguard Worker     // down, up, left, close
2414*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
2415*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(1, 1);
2416*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(1, 2);
2417*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(1, 1);
2418*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0, 1);
2419*c8dee2aaSAndroid Build Coastguard Worker     SkRect rect;
2420*c8dee2aaSAndroid Build Coastguard Worker     SkPathDirection  dir;
2421*c8dee2aaSAndroid Build Coastguard Worker     unsigned start;
2422*c8dee2aaSAndroid Build Coastguard Worker     path.close();
2423*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path, false, &rect, &dir, &start));
2424*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path, true, &rect, &dir, &start));
2425*c8dee2aaSAndroid Build Coastguard Worker     // right, left, up, close
2426*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
2427*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(1, 1);
2428*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(2, 1);
2429*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(1, 1);
2430*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(1, 0);
2431*c8dee2aaSAndroid Build Coastguard Worker     path.close();
2432*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path, false, &rect, &dir, &start));
2433*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path, true, &rect, &dir, &start));
2434*c8dee2aaSAndroid Build Coastguard Worker     // parallelogram with horizontal edges
2435*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
2436*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(1, 0);
2437*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(3, 0);
2438*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(2, 1);
2439*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0, 1);
2440*c8dee2aaSAndroid Build Coastguard Worker     path.close();
2441*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path, false, &rect, &dir, &start));
2442*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path, true, &rect, &dir, &start));
2443*c8dee2aaSAndroid Build Coastguard Worker     // parallelogram with vertical edges
2444*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
2445*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 1);
2446*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0, 3);
2447*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(1, 2);
2448*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(1, 0);
2449*c8dee2aaSAndroid Build Coastguard Worker     path.close();
2450*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path, false, &rect, &dir, &start));
2451*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !SkPathPriv::IsSimpleRect(path, true, &rect, &dir, &start));
2452*c8dee2aaSAndroid Build Coastguard Worker 
2453*c8dee2aaSAndroid Build Coastguard Worker }
2454*c8dee2aaSAndroid Build Coastguard Worker 
test_isArc(skiatest::Reporter * reporter)2455*c8dee2aaSAndroid Build Coastguard Worker static void test_isArc(skiatest::Reporter* reporter) {
2456*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
2457*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isArc(nullptr));
2458*c8dee2aaSAndroid Build Coastguard Worker 
2459*c8dee2aaSAndroid Build Coastguard Worker     // One circle, one oval:
2460*c8dee2aaSAndroid Build Coastguard Worker     const SkRect kOvals[] = { SkRect::MakeWH(100, 100), SkRect::MakeWH(100, 200)};
2461*c8dee2aaSAndroid Build Coastguard Worker 
2462*c8dee2aaSAndroid Build Coastguard Worker     // Various start and sweep angles. Note that we can't test with more than a full revolution,
2463*c8dee2aaSAndroid Build Coastguard Worker     // those cases are automatically converted to ovals by SkPath.
2464*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar kStartAngles[] = { -270, -135, -45, 0, 10, 70, 180, 350 };
2465*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar kSweepAngles[] = { -350, -190, -90, -5, 5, 89, 180, 270, 350 };
2466*c8dee2aaSAndroid Build Coastguard Worker 
2467*c8dee2aaSAndroid Build Coastguard Worker     int mutator = 0;
2468*c8dee2aaSAndroid Build Coastguard Worker 
2469*c8dee2aaSAndroid Build Coastguard Worker     for (SkRect oval : kOvals) {
2470*c8dee2aaSAndroid Build Coastguard Worker         for (SkScalar startAngle : kStartAngles) {
2471*c8dee2aaSAndroid Build Coastguard Worker             for (SkScalar sweepAngle : kSweepAngles) {
2472*c8dee2aaSAndroid Build Coastguard Worker                 // For now, isArc only works for arcs where useCenter is false!
2473*c8dee2aaSAndroid Build Coastguard Worker                 // TODO: When that's fixed, add more tests cases here.
2474*c8dee2aaSAndroid Build Coastguard Worker                 path.rewind();
2475*c8dee2aaSAndroid Build Coastguard Worker                 // Include an extra moveTo at the start - this should not interfere with isArc
2476*c8dee2aaSAndroid Build Coastguard Worker                 path.moveTo(oval.center());
2477*c8dee2aaSAndroid Build Coastguard Worker                 path.addArc(oval, startAngle, sweepAngle);
2478*c8dee2aaSAndroid Build Coastguard Worker 
2479*c8dee2aaSAndroid Build Coastguard Worker                 SkArc arc;
2480*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, path.isArc(&arc));
2481*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter,
2482*c8dee2aaSAndroid Build Coastguard Worker                                 oval == arc.fOval &&
2483*c8dee2aaSAndroid Build Coastguard Worker                                 startAngle == arc.fStartAngle &&
2484*c8dee2aaSAndroid Build Coastguard Worker                                 sweepAngle == arc.fSweepAngle &&
2485*c8dee2aaSAndroid Build Coastguard Worker                                 !arc.isWedge());
2486*c8dee2aaSAndroid Build Coastguard Worker 
2487*c8dee2aaSAndroid Build Coastguard Worker                 // Apply some mutation. All of these should cause the path to no longer be an arc:
2488*c8dee2aaSAndroid Build Coastguard Worker                 switch (mutator) {
2489*c8dee2aaSAndroid Build Coastguard Worker                     case 0:
2490*c8dee2aaSAndroid Build Coastguard Worker                         path.addArc(oval, startAngle, sweepAngle);
2491*c8dee2aaSAndroid Build Coastguard Worker                         break;
2492*c8dee2aaSAndroid Build Coastguard Worker                     case 1:
2493*c8dee2aaSAndroid Build Coastguard Worker                         path.lineTo(oval.center());
2494*c8dee2aaSAndroid Build Coastguard Worker                         break;
2495*c8dee2aaSAndroid Build Coastguard Worker                     case 2:
2496*c8dee2aaSAndroid Build Coastguard Worker                         path.lineTo(path.getPoint(0));
2497*c8dee2aaSAndroid Build Coastguard Worker                         break;
2498*c8dee2aaSAndroid Build Coastguard Worker                     case 3:
2499*c8dee2aaSAndroid Build Coastguard Worker                         path.close();
2500*c8dee2aaSAndroid Build Coastguard Worker                         break;
2501*c8dee2aaSAndroid Build Coastguard Worker                     case 4:
2502*c8dee2aaSAndroid Build Coastguard Worker                         path.moveTo(oval.center());
2503*c8dee2aaSAndroid Build Coastguard Worker                         break;
2504*c8dee2aaSAndroid Build Coastguard Worker                     default:
2505*c8dee2aaSAndroid Build Coastguard Worker                         SkUNREACHABLE;
2506*c8dee2aaSAndroid Build Coastguard Worker                 }
2507*c8dee2aaSAndroid Build Coastguard Worker                 mutator = (mutator + 1) % 5;
2508*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, !path.isArc(nullptr));
2509*c8dee2aaSAndroid Build Coastguard Worker             }
2510*c8dee2aaSAndroid Build Coastguard Worker         }
2511*c8dee2aaSAndroid Build Coastguard Worker     }
2512*c8dee2aaSAndroid Build Coastguard Worker 
2513*c8dee2aaSAndroid Build Coastguard Worker     // Having any non-move verb before the arc should cause isArc to return false:
2514*c8dee2aaSAndroid Build Coastguard Worker     path.rewind();
2515*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(kOvals[0].center());
2516*c8dee2aaSAndroid Build Coastguard Worker     path.addArc(kOvals[0], kStartAngles[0], kSweepAngles[0]);
2517*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isArc(nullptr));
2518*c8dee2aaSAndroid Build Coastguard Worker 
2519*c8dee2aaSAndroid Build Coastguard Worker     // Finally, transforming an arc path by a non-identity should always result in a non-arc path:
2520*c8dee2aaSAndroid Build Coastguard Worker     // TODO: We could clearly preserve arcs for translation, and for scale/rotation with extra work.
2521*c8dee2aaSAndroid Build Coastguard Worker     for (SkMatrix m :
2522*c8dee2aaSAndroid Build Coastguard Worker          {SkMatrix::Translate(10, 10), SkMatrix::RotateDeg(90), SkMatrix::Scale(2, 2)}) {
2523*c8dee2aaSAndroid Build Coastguard Worker         path.rewind();
2524*c8dee2aaSAndroid Build Coastguard Worker         path.addArc(kOvals[0], kStartAngles[0], kSweepAngles[0]);
2525*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, path.isArc(nullptr));
2526*c8dee2aaSAndroid Build Coastguard Worker         path.transform(SkMatrix::I());
2527*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, path.isArc(nullptr));
2528*c8dee2aaSAndroid Build Coastguard Worker         path.transform(m);
2529*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !path.isArc(nullptr));
2530*c8dee2aaSAndroid Build Coastguard Worker     }
2531*c8dee2aaSAndroid Build Coastguard Worker }
2532*c8dee2aaSAndroid Build Coastguard Worker 
test_isNestedFillRects(skiatest::Reporter * reporter)2533*c8dee2aaSAndroid Build Coastguard Worker static void test_isNestedFillRects(skiatest::Reporter* reporter) {
2534*c8dee2aaSAndroid Build Coastguard Worker     // passing tests (all moveTo / lineTo...
2535*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // CW
2536*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
2537*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
2538*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
2539*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}}; // CCW
2540*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
2541*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
2542*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
2543*c8dee2aaSAndroid Build Coastguard Worker     SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
2544*c8dee2aaSAndroid Build Coastguard Worker     SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f}, {1, 0}, {.5f, 0}}; // CCW
2545*c8dee2aaSAndroid Build Coastguard Worker     SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1}, {0, 1}, {0, .5f}}; // CW
2546*c8dee2aaSAndroid Build Coastguard Worker     SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}}; // CW
2547*c8dee2aaSAndroid Build Coastguard Worker     SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}}; // CCW
2548*c8dee2aaSAndroid Build Coastguard Worker     SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}}; // CW
2549*c8dee2aaSAndroid Build Coastguard Worker 
2550*c8dee2aaSAndroid Build Coastguard Worker     // failing tests
2551*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
2552*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
2553*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
2554*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
2555*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
2556*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
2557*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
2558*c8dee2aaSAndroid Build Coastguard Worker     SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
2559*c8dee2aaSAndroid Build Coastguard Worker 
2560*c8dee2aaSAndroid Build Coastguard Worker     // success, no close is OK
2561*c8dee2aaSAndroid Build Coastguard Worker     SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match
2562*c8dee2aaSAndroid Build Coastguard Worker     SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto
2563*c8dee2aaSAndroid Build Coastguard Worker 
2564*c8dee2aaSAndroid Build Coastguard Worker     struct IsNestedRectTest {
2565*c8dee2aaSAndroid Build Coastguard Worker         SkPoint *fPoints;
2566*c8dee2aaSAndroid Build Coastguard Worker         int fPointCount;
2567*c8dee2aaSAndroid Build Coastguard Worker         SkPathFirstDirection fDirection;
2568*c8dee2aaSAndroid Build Coastguard Worker         bool fClose;
2569*c8dee2aaSAndroid Build Coastguard Worker         bool fIsNestedRect; // nests with path.addRect(-1, -1, 2, 2);
2570*c8dee2aaSAndroid Build Coastguard Worker     } tests[] = {
2571*c8dee2aaSAndroid Build Coastguard Worker         { r1, std::size(r1), SkPathFirstDirection::kCW , true, true },
2572*c8dee2aaSAndroid Build Coastguard Worker         { r2, std::size(r2), SkPathFirstDirection::kCW , true, true },
2573*c8dee2aaSAndroid Build Coastguard Worker         { r3, std::size(r3), SkPathFirstDirection::kCW , true, true },
2574*c8dee2aaSAndroid Build Coastguard Worker         { r4, std::size(r4), SkPathFirstDirection::kCW , true, true },
2575*c8dee2aaSAndroid Build Coastguard Worker         { r5, std::size(r5), SkPathFirstDirection::kCCW, true, true },
2576*c8dee2aaSAndroid Build Coastguard Worker         { r6, std::size(r6), SkPathFirstDirection::kCCW, true, true },
2577*c8dee2aaSAndroid Build Coastguard Worker         { r7, std::size(r7), SkPathFirstDirection::kCCW, true, true },
2578*c8dee2aaSAndroid Build Coastguard Worker         { r8, std::size(r8), SkPathFirstDirection::kCCW, true, true },
2579*c8dee2aaSAndroid Build Coastguard Worker         { r9, std::size(r9), SkPathFirstDirection::kCCW, true, true },
2580*c8dee2aaSAndroid Build Coastguard Worker         { ra, std::size(ra), SkPathFirstDirection::kCCW, true, true },
2581*c8dee2aaSAndroid Build Coastguard Worker         { rb, std::size(rb), SkPathFirstDirection::kCW,  true, true },
2582*c8dee2aaSAndroid Build Coastguard Worker         { rc, std::size(rc), SkPathFirstDirection::kCW,  true, true },
2583*c8dee2aaSAndroid Build Coastguard Worker         { rd, std::size(rd), SkPathFirstDirection::kCCW, true, true },
2584*c8dee2aaSAndroid Build Coastguard Worker         { re, std::size(re), SkPathFirstDirection::kCW,  true, true },
2585*c8dee2aaSAndroid Build Coastguard Worker 
2586*c8dee2aaSAndroid Build Coastguard Worker         { f1, std::size(f1), SkPathFirstDirection::kUnknown, true, false },
2587*c8dee2aaSAndroid Build Coastguard Worker         { f2, std::size(f2), SkPathFirstDirection::kUnknown, true, false },
2588*c8dee2aaSAndroid Build Coastguard Worker         { f3, std::size(f3), SkPathFirstDirection::kUnknown, true, false },
2589*c8dee2aaSAndroid Build Coastguard Worker         { f4, std::size(f4), SkPathFirstDirection::kUnknown, true, false },
2590*c8dee2aaSAndroid Build Coastguard Worker         { f5, std::size(f5), SkPathFirstDirection::kUnknown, true, false },
2591*c8dee2aaSAndroid Build Coastguard Worker         { f6, std::size(f6), SkPathFirstDirection::kUnknown, true, false },
2592*c8dee2aaSAndroid Build Coastguard Worker         { f7, std::size(f7), SkPathFirstDirection::kUnknown, true, false },
2593*c8dee2aaSAndroid Build Coastguard Worker         { f8, std::size(f8), SkPathFirstDirection::kUnknown, true, false },
2594*c8dee2aaSAndroid Build Coastguard Worker 
2595*c8dee2aaSAndroid Build Coastguard Worker         { c1, std::size(c1), SkPathFirstDirection::kCW, false, true },
2596*c8dee2aaSAndroid Build Coastguard Worker         { c2, std::size(c2), SkPathFirstDirection::kCW, false, true },
2597*c8dee2aaSAndroid Build Coastguard Worker     };
2598*c8dee2aaSAndroid Build Coastguard Worker 
2599*c8dee2aaSAndroid Build Coastguard Worker     const size_t testCount = std::size(tests);
2600*c8dee2aaSAndroid Build Coastguard Worker     int index;
2601*c8dee2aaSAndroid Build Coastguard Worker     for (int rectFirst = 0; rectFirst <= 1; ++rectFirst) {
2602*c8dee2aaSAndroid Build Coastguard Worker         for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
2603*c8dee2aaSAndroid Build Coastguard Worker             SkPath path;
2604*c8dee2aaSAndroid Build Coastguard Worker             if (rectFirst) {
2605*c8dee2aaSAndroid Build Coastguard Worker                 path.addRect(-1, -1, 2, 2, SkPathDirection::kCW);
2606*c8dee2aaSAndroid Build Coastguard Worker             }
2607*c8dee2aaSAndroid Build Coastguard Worker             path.moveTo(tests[testIndex].fPoints[0].fX, tests[testIndex].fPoints[0].fY);
2608*c8dee2aaSAndroid Build Coastguard Worker             for (index = 1; index < tests[testIndex].fPointCount; ++index) {
2609*c8dee2aaSAndroid Build Coastguard Worker                 path.lineTo(tests[testIndex].fPoints[index].fX, tests[testIndex].fPoints[index].fY);
2610*c8dee2aaSAndroid Build Coastguard Worker             }
2611*c8dee2aaSAndroid Build Coastguard Worker             if (tests[testIndex].fClose) {
2612*c8dee2aaSAndroid Build Coastguard Worker                 path.close();
2613*c8dee2aaSAndroid Build Coastguard Worker             }
2614*c8dee2aaSAndroid Build Coastguard Worker             if (!rectFirst) {
2615*c8dee2aaSAndroid Build Coastguard Worker                 path.addRect(-1, -1, 2, 2, SkPathDirection::kCCW);
2616*c8dee2aaSAndroid Build Coastguard Worker             }
2617*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter,
2618*c8dee2aaSAndroid Build Coastguard Worker                             tests[testIndex].fIsNestedRect == SkPathPriv::IsNestedFillRects(path, nullptr));
2619*c8dee2aaSAndroid Build Coastguard Worker             if (tests[testIndex].fIsNestedRect) {
2620*c8dee2aaSAndroid Build Coastguard Worker                 SkRect expected[2], computed[2];
2621*c8dee2aaSAndroid Build Coastguard Worker                 SkPathFirstDirection expectedDirs[2];
2622*c8dee2aaSAndroid Build Coastguard Worker                 SkPathDirection computedDirs[2];
2623*c8dee2aaSAndroid Build Coastguard Worker                 SkRect testBounds;
2624*c8dee2aaSAndroid Build Coastguard Worker                 testBounds.setBounds(tests[testIndex].fPoints, tests[testIndex].fPointCount);
2625*c8dee2aaSAndroid Build Coastguard Worker                 expected[0] = SkRect::MakeLTRB(-1, -1, 2, 2);
2626*c8dee2aaSAndroid Build Coastguard Worker                 expected[1] = testBounds;
2627*c8dee2aaSAndroid Build Coastguard Worker                 if (rectFirst) {
2628*c8dee2aaSAndroid Build Coastguard Worker                     expectedDirs[0] = SkPathFirstDirection::kCW;
2629*c8dee2aaSAndroid Build Coastguard Worker                 } else {
2630*c8dee2aaSAndroid Build Coastguard Worker                     expectedDirs[0] = SkPathFirstDirection::kCCW;
2631*c8dee2aaSAndroid Build Coastguard Worker                 }
2632*c8dee2aaSAndroid Build Coastguard Worker                 expectedDirs[1] = tests[testIndex].fDirection;
2633*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, SkPathPriv::IsNestedFillRects(path, computed, computedDirs));
2634*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, expected[0] == computed[0]);
2635*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, expected[1] == computed[1]);
2636*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, expectedDirs[0] == SkPathPriv::AsFirstDirection(computedDirs[0]));
2637*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, expectedDirs[1] == SkPathPriv::AsFirstDirection(computedDirs[1]));
2638*c8dee2aaSAndroid Build Coastguard Worker             }
2639*c8dee2aaSAndroid Build Coastguard Worker         }
2640*c8dee2aaSAndroid Build Coastguard Worker 
2641*c8dee2aaSAndroid Build Coastguard Worker         // fail, close then line
2642*c8dee2aaSAndroid Build Coastguard Worker         SkPath path1;
2643*c8dee2aaSAndroid Build Coastguard Worker         if (rectFirst) {
2644*c8dee2aaSAndroid Build Coastguard Worker             path1.addRect(-1, -1, 2, 2, SkPathDirection::kCW);
2645*c8dee2aaSAndroid Build Coastguard Worker         }
2646*c8dee2aaSAndroid Build Coastguard Worker         path1.moveTo(r1[0].fX, r1[0].fY);
2647*c8dee2aaSAndroid Build Coastguard Worker         for (index = 1; index < SkToInt(std::size(r1)); ++index) {
2648*c8dee2aaSAndroid Build Coastguard Worker             path1.lineTo(r1[index].fX, r1[index].fY);
2649*c8dee2aaSAndroid Build Coastguard Worker         }
2650*c8dee2aaSAndroid Build Coastguard Worker         path1.close();
2651*c8dee2aaSAndroid Build Coastguard Worker         path1.lineTo(1, 0);
2652*c8dee2aaSAndroid Build Coastguard Worker         if (!rectFirst) {
2653*c8dee2aaSAndroid Build Coastguard Worker             path1.addRect(-1, -1, 2, 2, SkPathDirection::kCCW);
2654*c8dee2aaSAndroid Build Coastguard Worker         }
2655*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !SkPathPriv::IsNestedFillRects(path1, nullptr));
2656*c8dee2aaSAndroid Build Coastguard Worker 
2657*c8dee2aaSAndroid Build Coastguard Worker         // fail, move in the middle
2658*c8dee2aaSAndroid Build Coastguard Worker         path1.reset();
2659*c8dee2aaSAndroid Build Coastguard Worker         if (rectFirst) {
2660*c8dee2aaSAndroid Build Coastguard Worker             path1.addRect(-1, -1, 2, 2, SkPathDirection::kCW);
2661*c8dee2aaSAndroid Build Coastguard Worker         }
2662*c8dee2aaSAndroid Build Coastguard Worker         path1.moveTo(r1[0].fX, r1[0].fY);
2663*c8dee2aaSAndroid Build Coastguard Worker         for (index = 1; index < SkToInt(std::size(r1)); ++index) {
2664*c8dee2aaSAndroid Build Coastguard Worker             if (index == 2) {
2665*c8dee2aaSAndroid Build Coastguard Worker                 path1.moveTo(1, .5f);
2666*c8dee2aaSAndroid Build Coastguard Worker             }
2667*c8dee2aaSAndroid Build Coastguard Worker             path1.lineTo(r1[index].fX, r1[index].fY);
2668*c8dee2aaSAndroid Build Coastguard Worker         }
2669*c8dee2aaSAndroid Build Coastguard Worker         path1.close();
2670*c8dee2aaSAndroid Build Coastguard Worker         if (!rectFirst) {
2671*c8dee2aaSAndroid Build Coastguard Worker             path1.addRect(-1, -1, 2, 2, SkPathDirection::kCCW);
2672*c8dee2aaSAndroid Build Coastguard Worker         }
2673*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !SkPathPriv::IsNestedFillRects(path1, nullptr));
2674*c8dee2aaSAndroid Build Coastguard Worker 
2675*c8dee2aaSAndroid Build Coastguard Worker         // fail, move on the edge
2676*c8dee2aaSAndroid Build Coastguard Worker         path1.reset();
2677*c8dee2aaSAndroid Build Coastguard Worker         if (rectFirst) {
2678*c8dee2aaSAndroid Build Coastguard Worker             path1.addRect(-1, -1, 2, 2, SkPathDirection::kCW);
2679*c8dee2aaSAndroid Build Coastguard Worker         }
2680*c8dee2aaSAndroid Build Coastguard Worker         for (index = 1; index < SkToInt(std::size(r1)); ++index) {
2681*c8dee2aaSAndroid Build Coastguard Worker             path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
2682*c8dee2aaSAndroid Build Coastguard Worker             path1.lineTo(r1[index].fX, r1[index].fY);
2683*c8dee2aaSAndroid Build Coastguard Worker         }
2684*c8dee2aaSAndroid Build Coastguard Worker         path1.close();
2685*c8dee2aaSAndroid Build Coastguard Worker         if (!rectFirst) {
2686*c8dee2aaSAndroid Build Coastguard Worker             path1.addRect(-1, -1, 2, 2, SkPathDirection::kCCW);
2687*c8dee2aaSAndroid Build Coastguard Worker         }
2688*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !SkPathPriv::IsNestedFillRects(path1, nullptr));
2689*c8dee2aaSAndroid Build Coastguard Worker 
2690*c8dee2aaSAndroid Build Coastguard Worker         // fail, quad
2691*c8dee2aaSAndroid Build Coastguard Worker         path1.reset();
2692*c8dee2aaSAndroid Build Coastguard Worker         if (rectFirst) {
2693*c8dee2aaSAndroid Build Coastguard Worker             path1.addRect(-1, -1, 2, 2, SkPathDirection::kCW);
2694*c8dee2aaSAndroid Build Coastguard Worker         }
2695*c8dee2aaSAndroid Build Coastguard Worker         path1.moveTo(r1[0].fX, r1[0].fY);
2696*c8dee2aaSAndroid Build Coastguard Worker         for (index = 1; index < SkToInt(std::size(r1)); ++index) {
2697*c8dee2aaSAndroid Build Coastguard Worker             if (index == 2) {
2698*c8dee2aaSAndroid Build Coastguard Worker                 path1.quadTo(1, .5f, 1, .5f);
2699*c8dee2aaSAndroid Build Coastguard Worker             }
2700*c8dee2aaSAndroid Build Coastguard Worker             path1.lineTo(r1[index].fX, r1[index].fY);
2701*c8dee2aaSAndroid Build Coastguard Worker         }
2702*c8dee2aaSAndroid Build Coastguard Worker         path1.close();
2703*c8dee2aaSAndroid Build Coastguard Worker         if (!rectFirst) {
2704*c8dee2aaSAndroid Build Coastguard Worker             path1.addRect(-1, -1, 2, 2, SkPathDirection::kCCW);
2705*c8dee2aaSAndroid Build Coastguard Worker         }
2706*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !SkPathPriv::IsNestedFillRects(path1, nullptr));
2707*c8dee2aaSAndroid Build Coastguard Worker 
2708*c8dee2aaSAndroid Build Coastguard Worker         // fail, cubic
2709*c8dee2aaSAndroid Build Coastguard Worker         path1.reset();
2710*c8dee2aaSAndroid Build Coastguard Worker         if (rectFirst) {
2711*c8dee2aaSAndroid Build Coastguard Worker             path1.addRect(-1, -1, 2, 2, SkPathDirection::kCW);
2712*c8dee2aaSAndroid Build Coastguard Worker         }
2713*c8dee2aaSAndroid Build Coastguard Worker         path1.moveTo(r1[0].fX, r1[0].fY);
2714*c8dee2aaSAndroid Build Coastguard Worker         for (index = 1; index < SkToInt(std::size(r1)); ++index) {
2715*c8dee2aaSAndroid Build Coastguard Worker             if (index == 2) {
2716*c8dee2aaSAndroid Build Coastguard Worker                 path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
2717*c8dee2aaSAndroid Build Coastguard Worker             }
2718*c8dee2aaSAndroid Build Coastguard Worker             path1.lineTo(r1[index].fX, r1[index].fY);
2719*c8dee2aaSAndroid Build Coastguard Worker         }
2720*c8dee2aaSAndroid Build Coastguard Worker         path1.close();
2721*c8dee2aaSAndroid Build Coastguard Worker         if (!rectFirst) {
2722*c8dee2aaSAndroid Build Coastguard Worker             path1.addRect(-1, -1, 2, 2, SkPathDirection::kCCW);
2723*c8dee2aaSAndroid Build Coastguard Worker         }
2724*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !SkPathPriv::IsNestedFillRects(path1, nullptr));
2725*c8dee2aaSAndroid Build Coastguard Worker 
2726*c8dee2aaSAndroid Build Coastguard Worker         // fail,  not nested
2727*c8dee2aaSAndroid Build Coastguard Worker         path1.reset();
2728*c8dee2aaSAndroid Build Coastguard Worker         path1.addRect(1, 1, 3, 3, SkPathDirection::kCW);
2729*c8dee2aaSAndroid Build Coastguard Worker         path1.addRect(2, 2, 4, 4, SkPathDirection::kCW);
2730*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !SkPathPriv::IsNestedFillRects(path1, nullptr));
2731*c8dee2aaSAndroid Build Coastguard Worker     }
2732*c8dee2aaSAndroid Build Coastguard Worker 
2733*c8dee2aaSAndroid Build Coastguard Worker     //  pass, constructed explicitly from manually closed rects specified as moves/lines.
2734*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
2735*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0);
2736*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(10, 0);
2737*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(10, 10);
2738*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0, 10);
2739*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0, 0);
2740*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(1, 1);
2741*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(9, 1);
2742*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(9, 9);
2743*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(1, 9);
2744*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(1, 1);
2745*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathPriv::IsNestedFillRects(path, nullptr));
2746*c8dee2aaSAndroid Build Coastguard Worker 
2747*c8dee2aaSAndroid Build Coastguard Worker     // pass, stroke rect
2748*c8dee2aaSAndroid Build Coastguard Worker     SkPath src, dst;
2749*c8dee2aaSAndroid Build Coastguard Worker     src.addRect(1, 1, 7, 7, SkPathDirection::kCW);
2750*c8dee2aaSAndroid Build Coastguard Worker     SkPaint strokePaint;
2751*c8dee2aaSAndroid Build Coastguard Worker     strokePaint.setStyle(SkPaint::kStroke_Style);
2752*c8dee2aaSAndroid Build Coastguard Worker     strokePaint.setStrokeWidth(2);
2753*c8dee2aaSAndroid Build Coastguard Worker     skpathutils::FillPathWithPaint(src, strokePaint, &dst);
2754*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathPriv::IsNestedFillRects(dst, nullptr));
2755*c8dee2aaSAndroid Build Coastguard Worker }
2756*c8dee2aaSAndroid Build Coastguard Worker 
write_and_read_back(skiatest::Reporter * reporter,const SkPath & p)2757*c8dee2aaSAndroid Build Coastguard Worker static void write_and_read_back(skiatest::Reporter* reporter,
2758*c8dee2aaSAndroid Build Coastguard Worker                                 const SkPath& p) {
2759*c8dee2aaSAndroid Build Coastguard Worker     SkBinaryWriteBuffer writer({});
2760*c8dee2aaSAndroid Build Coastguard Worker     writer.writePath(p);
2761*c8dee2aaSAndroid Build Coastguard Worker     size_t size = writer.bytesWritten();
2762*c8dee2aaSAndroid Build Coastguard Worker     SkAutoMalloc storage(size);
2763*c8dee2aaSAndroid Build Coastguard Worker     writer.writeToMemory(storage.get());
2764*c8dee2aaSAndroid Build Coastguard Worker     SkReadBuffer reader(storage.get(), size);
2765*c8dee2aaSAndroid Build Coastguard Worker 
2766*c8dee2aaSAndroid Build Coastguard Worker     SkPath readBack;
2767*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, readBack != p);
2768*c8dee2aaSAndroid Build Coastguard Worker     reader.readPath(&readBack);
2769*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, readBack == p);
2770*c8dee2aaSAndroid Build Coastguard Worker 
2771*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathPriv::GetConvexityOrUnknown(readBack) ==
2772*c8dee2aaSAndroid Build Coastguard Worker                               SkPathPriv::GetConvexityOrUnknown(p));
2773*c8dee2aaSAndroid Build Coastguard Worker 
2774*c8dee2aaSAndroid Build Coastguard Worker     SkRect oval0, oval1;
2775*c8dee2aaSAndroid Build Coastguard Worker     SkPathDirection dir0, dir1;
2776*c8dee2aaSAndroid Build Coastguard Worker     unsigned start0, start1;
2777*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, readBack.isOval(nullptr) == p.isOval(nullptr));
2778*c8dee2aaSAndroid Build Coastguard Worker     if (SkPathPriv::IsOval(p, &oval0, &dir0, &start0) &&
2779*c8dee2aaSAndroid Build Coastguard Worker         SkPathPriv::IsOval(readBack, &oval1, &dir1, &start1)) {
2780*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, oval0 == oval1);
2781*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, dir0 == dir1);
2782*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, start0 == start1);
2783*c8dee2aaSAndroid Build Coastguard Worker     }
2784*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, readBack.isRRect(nullptr) == p.isRRect(nullptr));
2785*c8dee2aaSAndroid Build Coastguard Worker     SkRRect rrect0, rrect1;
2786*c8dee2aaSAndroid Build Coastguard Worker     if (SkPathPriv::IsRRect(p, &rrect0, &dir0, &start0) &&
2787*c8dee2aaSAndroid Build Coastguard Worker         SkPathPriv::IsRRect(readBack, &rrect1, &dir1, &start1)) {
2788*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, rrect0 == rrect1);
2789*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, dir0 == dir1);
2790*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, start0 == start1);
2791*c8dee2aaSAndroid Build Coastguard Worker     }
2792*c8dee2aaSAndroid Build Coastguard Worker     const SkRect& origBounds = p.getBounds();
2793*c8dee2aaSAndroid Build Coastguard Worker     const SkRect& readBackBounds = readBack.getBounds();
2794*c8dee2aaSAndroid Build Coastguard Worker 
2795*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, origBounds == readBackBounds);
2796*c8dee2aaSAndroid Build Coastguard Worker }
2797*c8dee2aaSAndroid Build Coastguard Worker 
test_flattening(skiatest::Reporter * reporter)2798*c8dee2aaSAndroid Build Coastguard Worker static void test_flattening(skiatest::Reporter* reporter) {
2799*c8dee2aaSAndroid Build Coastguard Worker     SkPath p;
2800*c8dee2aaSAndroid Build Coastguard Worker 
2801*c8dee2aaSAndroid Build Coastguard Worker     static const SkPoint pts[] = {
2802*c8dee2aaSAndroid Build Coastguard Worker         { 0, 0 },
2803*c8dee2aaSAndroid Build Coastguard Worker         { SkIntToScalar(10), SkIntToScalar(10) },
2804*c8dee2aaSAndroid Build Coastguard Worker         { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
2805*c8dee2aaSAndroid Build Coastguard Worker         { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
2806*c8dee2aaSAndroid Build Coastguard Worker     };
2807*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(pts[0]);
2808*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(pts[1]);
2809*c8dee2aaSAndroid Build Coastguard Worker     p.quadTo(pts[2], pts[3]);
2810*c8dee2aaSAndroid Build Coastguard Worker     p.cubicTo(pts[4], pts[5], pts[6]);
2811*c8dee2aaSAndroid Build Coastguard Worker 
2812*c8dee2aaSAndroid Build Coastguard Worker     write_and_read_back(reporter, p);
2813*c8dee2aaSAndroid Build Coastguard Worker 
2814*c8dee2aaSAndroid Build Coastguard Worker     // create a buffer that should be much larger than the path so we don't
2815*c8dee2aaSAndroid Build Coastguard Worker     // kill our stack if writer goes too far.
2816*c8dee2aaSAndroid Build Coastguard Worker     char buffer[1024];
2817*c8dee2aaSAndroid Build Coastguard Worker     size_t size1 = p.writeToMemory(nullptr);
2818*c8dee2aaSAndroid Build Coastguard Worker     size_t size2 = p.writeToMemory(buffer);
2819*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, size1 == size2);
2820*c8dee2aaSAndroid Build Coastguard Worker 
2821*c8dee2aaSAndroid Build Coastguard Worker     SkPath p2;
2822*c8dee2aaSAndroid Build Coastguard Worker     size_t size3 = p2.readFromMemory(buffer, 1024);
2823*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, size1 == size3);
2824*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p == p2);
2825*c8dee2aaSAndroid Build Coastguard Worker 
2826*c8dee2aaSAndroid Build Coastguard Worker     size3 = p2.readFromMemory(buffer, 0);
2827*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !size3);
2828*c8dee2aaSAndroid Build Coastguard Worker 
2829*c8dee2aaSAndroid Build Coastguard Worker     SkPath tooShort;
2830*c8dee2aaSAndroid Build Coastguard Worker     size3 = tooShort.readFromMemory(buffer, size1 - 1);
2831*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, tooShort.isEmpty());
2832*c8dee2aaSAndroid Build Coastguard Worker 
2833*c8dee2aaSAndroid Build Coastguard Worker     char buffer2[1024];
2834*c8dee2aaSAndroid Build Coastguard Worker     size3 = p2.writeToMemory(buffer2);
2835*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, size1 == size3);
2836*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, memcmp(buffer, buffer2, size1) == 0);
2837*c8dee2aaSAndroid Build Coastguard Worker 
2838*c8dee2aaSAndroid Build Coastguard Worker     // test persistence of the oval flag & convexity
2839*c8dee2aaSAndroid Build Coastguard Worker     {
2840*c8dee2aaSAndroid Build Coastguard Worker         SkPath oval;
2841*c8dee2aaSAndroid Build Coastguard Worker         SkRect rect = SkRect::MakeWH(10, 10);
2842*c8dee2aaSAndroid Build Coastguard Worker         oval.addOval(rect);
2843*c8dee2aaSAndroid Build Coastguard Worker 
2844*c8dee2aaSAndroid Build Coastguard Worker         write_and_read_back(reporter, oval);
2845*c8dee2aaSAndroid Build Coastguard Worker     }
2846*c8dee2aaSAndroid Build Coastguard Worker }
2847*c8dee2aaSAndroid Build Coastguard Worker 
test_transform(skiatest::Reporter * reporter)2848*c8dee2aaSAndroid Build Coastguard Worker static void test_transform(skiatest::Reporter* reporter) {
2849*c8dee2aaSAndroid Build Coastguard Worker     SkPath p;
2850*c8dee2aaSAndroid Build Coastguard Worker 
2851*c8dee2aaSAndroid Build Coastguard Worker #define CONIC_PERSPECTIVE_BUG_FIXED 0
2852*c8dee2aaSAndroid Build Coastguard Worker     static const SkPoint pts[] = {
2853*c8dee2aaSAndroid Build Coastguard Worker         { 0, 0 },  // move
2854*c8dee2aaSAndroid Build Coastguard Worker         { SkIntToScalar(10), SkIntToScalar(10) },  // line
2855*c8dee2aaSAndroid Build Coastguard Worker         { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },  // quad
2856*c8dee2aaSAndroid Build Coastguard Worker         { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) },  // cubic
2857*c8dee2aaSAndroid Build Coastguard Worker #if CONIC_PERSPECTIVE_BUG_FIXED
2858*c8dee2aaSAndroid Build Coastguard Worker         { 0, 0 }, { SkIntToScalar(20), SkIntToScalar(10) },  // conic
2859*c8dee2aaSAndroid Build Coastguard Worker #endif
2860*c8dee2aaSAndroid Build Coastguard Worker     };
2861*c8dee2aaSAndroid Build Coastguard Worker     const int kPtCount = std::size(pts);
2862*c8dee2aaSAndroid Build Coastguard Worker 
2863*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(pts[0]);
2864*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(pts[1]);
2865*c8dee2aaSAndroid Build Coastguard Worker     p.quadTo(pts[2], pts[3]);
2866*c8dee2aaSAndroid Build Coastguard Worker     p.cubicTo(pts[4], pts[5], pts[6]);
2867*c8dee2aaSAndroid Build Coastguard Worker #if CONIC_PERSPECTIVE_BUG_FIXED
2868*c8dee2aaSAndroid Build Coastguard Worker     p.conicTo(pts[4], pts[5], 0.5f);
2869*c8dee2aaSAndroid Build Coastguard Worker #endif
2870*c8dee2aaSAndroid Build Coastguard Worker     p.close();
2871*c8dee2aaSAndroid Build Coastguard Worker 
2872*c8dee2aaSAndroid Build Coastguard Worker     {
2873*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix matrix;
2874*c8dee2aaSAndroid Build Coastguard Worker         matrix.reset();
2875*c8dee2aaSAndroid Build Coastguard Worker         SkPath p1;
2876*c8dee2aaSAndroid Build Coastguard Worker         p.transform(matrix, &p1);
2877*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, p == p1);
2878*c8dee2aaSAndroid Build Coastguard Worker     }
2879*c8dee2aaSAndroid Build Coastguard Worker 
2880*c8dee2aaSAndroid Build Coastguard Worker 
2881*c8dee2aaSAndroid Build Coastguard Worker     {
2882*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix matrix;
2883*c8dee2aaSAndroid Build Coastguard Worker         matrix.setScale(SK_Scalar1 * 2, SK_Scalar1 * 3);
2884*c8dee2aaSAndroid Build Coastguard Worker 
2885*c8dee2aaSAndroid Build Coastguard Worker         SkPath p1;      // Leave p1 non-unique (i.e., the empty path)
2886*c8dee2aaSAndroid Build Coastguard Worker 
2887*c8dee2aaSAndroid Build Coastguard Worker         p.transform(matrix, &p1);
2888*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pts1[kPtCount];
2889*c8dee2aaSAndroid Build Coastguard Worker         int count = p1.getPoints(pts1, kPtCount);
2890*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, kPtCount == count);
2891*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < count; ++i) {
2892*c8dee2aaSAndroid Build Coastguard Worker             SkPoint newPt = SkPoint::Make(pts[i].fX * 2, pts[i].fY * 3);
2893*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, newPt == pts1[i]);
2894*c8dee2aaSAndroid Build Coastguard Worker         }
2895*c8dee2aaSAndroid Build Coastguard Worker     }
2896*c8dee2aaSAndroid Build Coastguard Worker 
2897*c8dee2aaSAndroid Build Coastguard Worker     {
2898*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix matrix;
2899*c8dee2aaSAndroid Build Coastguard Worker         matrix.reset();
2900*c8dee2aaSAndroid Build Coastguard Worker         matrix.setPerspX(4);
2901*c8dee2aaSAndroid Build Coastguard Worker 
2902*c8dee2aaSAndroid Build Coastguard Worker         SkPath p1;
2903*c8dee2aaSAndroid Build Coastguard Worker         p1.moveTo(SkPoint::Make(0, 0));
2904*c8dee2aaSAndroid Build Coastguard Worker 
2905*c8dee2aaSAndroid Build Coastguard Worker         p.transform(matrix, &p1, SkApplyPerspectiveClip::kNo);
2906*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, matrix.invert(&matrix));
2907*c8dee2aaSAndroid Build Coastguard Worker         p1.transform(matrix, nullptr, SkApplyPerspectiveClip::kNo);
2908*c8dee2aaSAndroid Build Coastguard Worker         SkRect pBounds = p.getBounds();
2909*c8dee2aaSAndroid Build Coastguard Worker         SkRect p1Bounds = p1.getBounds();
2910*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(pBounds.fLeft, p1Bounds.fLeft));
2911*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(pBounds.fTop, p1Bounds.fTop));
2912*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(pBounds.fRight, p1Bounds.fRight));
2913*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(pBounds.fBottom, p1Bounds.fBottom));
2914*c8dee2aaSAndroid Build Coastguard Worker     }
2915*c8dee2aaSAndroid Build Coastguard Worker 
2916*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
2917*c8dee2aaSAndroid Build Coastguard Worker     p.addCircle(0, 0, 1, SkPathDirection::kCW);
2918*c8dee2aaSAndroid Build Coastguard Worker 
2919*c8dee2aaSAndroid Build Coastguard Worker     {
2920*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix matrix;
2921*c8dee2aaSAndroid Build Coastguard Worker         matrix.reset();
2922*c8dee2aaSAndroid Build Coastguard Worker         SkPath p1;
2923*c8dee2aaSAndroid Build Coastguard Worker         p1.moveTo(SkPoint::Make(0, 0));
2924*c8dee2aaSAndroid Build Coastguard Worker 
2925*c8dee2aaSAndroid Build Coastguard Worker         p.transform(matrix, &p1);
2926*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, SkPathPriv::ComputeFirstDirection(p1) == SkPathFirstDirection::kCW);
2927*c8dee2aaSAndroid Build Coastguard Worker     }
2928*c8dee2aaSAndroid Build Coastguard Worker 
2929*c8dee2aaSAndroid Build Coastguard Worker 
2930*c8dee2aaSAndroid Build Coastguard Worker     {
2931*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix matrix;
2932*c8dee2aaSAndroid Build Coastguard Worker         matrix.reset();
2933*c8dee2aaSAndroid Build Coastguard Worker         matrix.setScaleX(-1);
2934*c8dee2aaSAndroid Build Coastguard Worker         SkPath p1;
2935*c8dee2aaSAndroid Build Coastguard Worker         p1.moveTo(SkPoint::Make(0, 0)); // Make p1 unique (i.e., not empty path)
2936*c8dee2aaSAndroid Build Coastguard Worker 
2937*c8dee2aaSAndroid Build Coastguard Worker         p.transform(matrix, &p1);
2938*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, SkPathPriv::ComputeFirstDirection(p1) == SkPathFirstDirection::kCCW);
2939*c8dee2aaSAndroid Build Coastguard Worker     }
2940*c8dee2aaSAndroid Build Coastguard Worker 
2941*c8dee2aaSAndroid Build Coastguard Worker     {
2942*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix matrix;
2943*c8dee2aaSAndroid Build Coastguard Worker         matrix.setAll(1, 1, 0, 1, 1, 0, 0, 0, 1);
2944*c8dee2aaSAndroid Build Coastguard Worker         SkPath p1;
2945*c8dee2aaSAndroid Build Coastguard Worker         p1.moveTo(SkPoint::Make(0, 0)); // Make p1 unique (i.e., not empty path)
2946*c8dee2aaSAndroid Build Coastguard Worker 
2947*c8dee2aaSAndroid Build Coastguard Worker         p.transform(matrix, &p1);
2948*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, SkPathPriv::ComputeFirstDirection(p1) == SkPathFirstDirection::kUnknown);
2949*c8dee2aaSAndroid Build Coastguard Worker     }
2950*c8dee2aaSAndroid Build Coastguard Worker 
2951*c8dee2aaSAndroid Build Coastguard Worker     {
2952*c8dee2aaSAndroid Build Coastguard Worker         SkPath p1;
2953*c8dee2aaSAndroid Build Coastguard Worker         p1.addRect({ 10, 20, 30, 40 });
2954*c8dee2aaSAndroid Build Coastguard Worker         SkPath p2;
2955*c8dee2aaSAndroid Build Coastguard Worker         p2.addRect({ 10, 20, 30, 40 });
2956*c8dee2aaSAndroid Build Coastguard Worker         uint32_t id1 = p1.getGenerationID();
2957*c8dee2aaSAndroid Build Coastguard Worker         uint32_t id2 = p2.getGenerationID();
2958*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, id1 != id2);
2959*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix matrix;
2960*c8dee2aaSAndroid Build Coastguard Worker         matrix.setScale(2, 2);
2961*c8dee2aaSAndroid Build Coastguard Worker         p1.transform(matrix, &p2);
2962*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, id1 == p1.getGenerationID());
2963*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, id2 != p2.getGenerationID());
2964*c8dee2aaSAndroid Build Coastguard Worker         p1.transform(matrix);
2965*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, id1 != p1.getGenerationID());
2966*c8dee2aaSAndroid Build Coastguard Worker     }
2967*c8dee2aaSAndroid Build Coastguard Worker }
2968*c8dee2aaSAndroid Build Coastguard Worker 
test_zero_length_paths(skiatest::Reporter * reporter)2969*c8dee2aaSAndroid Build Coastguard Worker static void test_zero_length_paths(skiatest::Reporter* reporter) {
2970*c8dee2aaSAndroid Build Coastguard Worker     SkPath  p;
2971*c8dee2aaSAndroid Build Coastguard Worker     uint8_t verbs[32];
2972*c8dee2aaSAndroid Build Coastguard Worker 
2973*c8dee2aaSAndroid Build Coastguard Worker     struct SUPPRESS_VISIBILITY_WARNING zeroPathTestData {
2974*c8dee2aaSAndroid Build Coastguard Worker         const char* testPath;
2975*c8dee2aaSAndroid Build Coastguard Worker         const size_t numResultPts;
2976*c8dee2aaSAndroid Build Coastguard Worker         const SkRect resultBound;
2977*c8dee2aaSAndroid Build Coastguard Worker         const SkPath::Verb* resultVerbs;
2978*c8dee2aaSAndroid Build Coastguard Worker         const size_t numResultVerbs;
2979*c8dee2aaSAndroid Build Coastguard Worker     };
2980*c8dee2aaSAndroid Build Coastguard Worker 
2981*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs1[] = { SkPath::kMove_Verb };
2982*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs2[] = { SkPath::kMove_Verb, SkPath::kMove_Verb };
2983*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs3[] = { SkPath::kMove_Verb, SkPath::kClose_Verb };
2984*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs4[] = { SkPath::kMove_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kClose_Verb };
2985*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs5[] = { SkPath::kMove_Verb, SkPath::kLine_Verb };
2986*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs6[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kMove_Verb, SkPath::kLine_Verb };
2987*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs7[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb };
2988*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs8[] = {
2989*c8dee2aaSAndroid Build Coastguard Worker         SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb
2990*c8dee2aaSAndroid Build Coastguard Worker     };
2991*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs9[] = { SkPath::kMove_Verb, SkPath::kQuad_Verb };
2992*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs10[] = { SkPath::kMove_Verb, SkPath::kQuad_Verb, SkPath::kMove_Verb, SkPath::kQuad_Verb };
2993*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs11[] = { SkPath::kMove_Verb, SkPath::kQuad_Verb, SkPath::kClose_Verb };
2994*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs12[] = {
2995*c8dee2aaSAndroid Build Coastguard Worker         SkPath::kMove_Verb, SkPath::kQuad_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kQuad_Verb, SkPath::kClose_Verb
2996*c8dee2aaSAndroid Build Coastguard Worker     };
2997*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs13[] = { SkPath::kMove_Verb, SkPath::kCubic_Verb };
2998*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs14[] = { SkPath::kMove_Verb, SkPath::kCubic_Verb, SkPath::kMove_Verb, SkPath::kCubic_Verb };
2999*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs15[] = { SkPath::kMove_Verb, SkPath::kCubic_Verb, SkPath::kClose_Verb };
3000*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs16[] = {
3001*c8dee2aaSAndroid Build Coastguard Worker         SkPath::kMove_Verb, SkPath::kCubic_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kCubic_Verb, SkPath::kClose_Verb
3002*c8dee2aaSAndroid Build Coastguard Worker     };
3003*c8dee2aaSAndroid Build Coastguard Worker     static const struct zeroPathTestData gZeroLengthTests[] = {
3004*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 1", 1, {1, 1, 1, 1}, resultVerbs1, std::size(resultVerbs1) },
3005*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 1 M 2 1", 2, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs2, std::size(resultVerbs2) },
3006*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 1 z", 1, {1, 1, 1, 1}, resultVerbs3, std::size(resultVerbs3) },
3007*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 1 z M 2 1 z", 2, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs4, std::size(resultVerbs4) },
3008*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 1 L 1 1", 2, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs5, std::size(resultVerbs5) },
3009*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 1 L 1 1 M 2 1 L 2 1", 4, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs6, std::size(resultVerbs6) },
3010*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 1 L 1 1 z", 2, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs7, std::size(resultVerbs7) },
3011*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 1 L 1 1 z M 2 1 L 2 1 z", 4, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs8, std::size(resultVerbs8) },
3012*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 1 Q 1 1 1 1", 3, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs9, std::size(resultVerbs9) },
3013*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 1 Q 1 1 1 1 M 2 1 Q 2 1 2 1", 6, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs10, std::size(resultVerbs10) },
3014*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 1 Q 1 1 1 1 z", 3, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs11, std::size(resultVerbs11) },
3015*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 1 Q 1 1 1 1 z M 2 1 Q 2 1 2 1 z", 6, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs12, std::size(resultVerbs12) },
3016*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 1 C 1 1 1 1 1 1", 4, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs13, std::size(resultVerbs13) },
3017*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 1 C 1 1 1 1 1 1 M 2 1 C 2 1 2 1 2 1", 8, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs14,
3018*c8dee2aaSAndroid Build Coastguard Worker             std::size(resultVerbs14)
3019*c8dee2aaSAndroid Build Coastguard Worker         },
3020*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 1 C 1 1 1 1 1 1 z", 4, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs15, std::size(resultVerbs15) },
3021*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 1 C 1 1 1 1 1 1 z M 2 1 C 2 1 2 1 2 1 z", 8, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs16,
3022*c8dee2aaSAndroid Build Coastguard Worker             std::size(resultVerbs16)
3023*c8dee2aaSAndroid Build Coastguard Worker         }
3024*c8dee2aaSAndroid Build Coastguard Worker     };
3025*c8dee2aaSAndroid Build Coastguard Worker 
3026*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < std::size(gZeroLengthTests); ++i) {
3027*c8dee2aaSAndroid Build Coastguard Worker         p.reset();
3028*c8dee2aaSAndroid Build Coastguard Worker         bool valid = SkParsePath::FromSVGString(gZeroLengthTests[i].testPath, &p);
3029*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, valid);
3030*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !p.isEmpty());
3031*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, gZeroLengthTests[i].numResultPts == (size_t)p.countPoints());
3032*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, gZeroLengthTests[i].resultBound == p.getBounds());
3033*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, gZeroLengthTests[i].numResultVerbs == (size_t)p.getVerbs(verbs, std::size(verbs)));
3034*c8dee2aaSAndroid Build Coastguard Worker         for (size_t j = 0; j < gZeroLengthTests[i].numResultVerbs; ++j) {
3035*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, gZeroLengthTests[i].resultVerbs[j] == verbs[j]);
3036*c8dee2aaSAndroid Build Coastguard Worker         }
3037*c8dee2aaSAndroid Build Coastguard Worker     }
3038*c8dee2aaSAndroid Build Coastguard Worker }
3039*c8dee2aaSAndroid Build Coastguard Worker 
3040*c8dee2aaSAndroid Build Coastguard Worker struct SegmentInfo {
3041*c8dee2aaSAndroid Build Coastguard Worker     SkPath fPath;
3042*c8dee2aaSAndroid Build Coastguard Worker     int    fPointCount;
3043*c8dee2aaSAndroid Build Coastguard Worker };
3044*c8dee2aaSAndroid Build Coastguard Worker 
3045*c8dee2aaSAndroid Build Coastguard Worker #define kCurveSegmentMask   (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)
3046*c8dee2aaSAndroid Build Coastguard Worker 
test_segment_masks(skiatest::Reporter * reporter)3047*c8dee2aaSAndroid Build Coastguard Worker static void test_segment_masks(skiatest::Reporter* reporter) {
3048*c8dee2aaSAndroid Build Coastguard Worker     SkPath p, p2;
3049*c8dee2aaSAndroid Build Coastguard Worker 
3050*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(0, 0);
3051*c8dee2aaSAndroid Build Coastguard Worker     p.quadTo(100, 100, 200, 200);
3052*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == p.getSegmentMasks());
3053*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.isEmpty());
3054*c8dee2aaSAndroid Build Coastguard Worker     p2 = p;
3055*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p2.getSegmentMasks() == p.getSegmentMasks());
3056*c8dee2aaSAndroid Build Coastguard Worker     p.cubicTo(100, 100, 200, 200, 300, 300);
3057*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, kCurveSegmentMask == p.getSegmentMasks());
3058*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.isEmpty());
3059*c8dee2aaSAndroid Build Coastguard Worker     p2 = p;
3060*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p2.getSegmentMasks() == p.getSegmentMasks());
3061*c8dee2aaSAndroid Build Coastguard Worker 
3062*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
3063*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(0, 0);
3064*c8dee2aaSAndroid Build Coastguard Worker     p.cubicTo(100, 100, 200, 200, 300, 300);
3065*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == p.getSegmentMasks());
3066*c8dee2aaSAndroid Build Coastguard Worker     p2 = p;
3067*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p2.getSegmentMasks() == p.getSegmentMasks());
3068*c8dee2aaSAndroid Build Coastguard Worker 
3069*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.isEmpty());
3070*c8dee2aaSAndroid Build Coastguard Worker }
3071*c8dee2aaSAndroid Build Coastguard Worker 
test_iter(skiatest::Reporter * reporter)3072*c8dee2aaSAndroid Build Coastguard Worker static void test_iter(skiatest::Reporter* reporter) {
3073*c8dee2aaSAndroid Build Coastguard Worker     SkPath  p;
3074*c8dee2aaSAndroid Build Coastguard Worker     SkPoint pts[4];
3075*c8dee2aaSAndroid Build Coastguard Worker 
3076*c8dee2aaSAndroid Build Coastguard Worker     // Test an iterator with no path
3077*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Iter noPathIter;
3078*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
3079*c8dee2aaSAndroid Build Coastguard Worker 
3080*c8dee2aaSAndroid Build Coastguard Worker     // Test that setting an empty path works
3081*c8dee2aaSAndroid Build Coastguard Worker     noPathIter.setPath(p, false);
3082*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
3083*c8dee2aaSAndroid Build Coastguard Worker 
3084*c8dee2aaSAndroid Build Coastguard Worker     // Test that close path makes no difference for an empty path
3085*c8dee2aaSAndroid Build Coastguard Worker     noPathIter.setPath(p, true);
3086*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
3087*c8dee2aaSAndroid Build Coastguard Worker 
3088*c8dee2aaSAndroid Build Coastguard Worker     // Test an iterator with an initial empty path
3089*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Iter iter(p, false);
3090*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
3091*c8dee2aaSAndroid Build Coastguard Worker 
3092*c8dee2aaSAndroid Build Coastguard Worker     // Test that close path makes no difference
3093*c8dee2aaSAndroid Build Coastguard Worker     iter.setPath(p, true);
3094*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
3095*c8dee2aaSAndroid Build Coastguard Worker 
3096*c8dee2aaSAndroid Build Coastguard Worker 
3097*c8dee2aaSAndroid Build Coastguard Worker     struct iterTestData {
3098*c8dee2aaSAndroid Build Coastguard Worker         const char* testPath;
3099*c8dee2aaSAndroid Build Coastguard Worker         const bool forceClose;
3100*c8dee2aaSAndroid Build Coastguard Worker         const size_t* numResultPtsPerVerb;
3101*c8dee2aaSAndroid Build Coastguard Worker         const SkPoint* resultPts;
3102*c8dee2aaSAndroid Build Coastguard Worker         const SkPath::Verb* resultVerbs;
3103*c8dee2aaSAndroid Build Coastguard Worker         const size_t numResultVerbs;
3104*c8dee2aaSAndroid Build Coastguard Worker     };
3105*c8dee2aaSAndroid Build Coastguard Worker 
3106*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs1[] = { SkPath::kDone_Verb };
3107*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs2[] = {
3108*c8dee2aaSAndroid Build Coastguard Worker         SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kMove_Verb, SkPath::kClose_Verb, SkPath::kDone_Verb
3109*c8dee2aaSAndroid Build Coastguard Worker     };
3110*c8dee2aaSAndroid Build Coastguard Worker     static const SkPath::Verb resultVerbs3[] = {
3111*c8dee2aaSAndroid Build Coastguard Worker         SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kClose_Verb, SkPath::kDone_Verb
3112*c8dee2aaSAndroid Build Coastguard Worker     };
3113*c8dee2aaSAndroid Build Coastguard Worker     static const size_t resultPtsSizes1[] = { 0 };
3114*c8dee2aaSAndroid Build Coastguard Worker     static const size_t resultPtsSizes2[] = { 1, 2, 1, 1, 0 };
3115*c8dee2aaSAndroid Build Coastguard Worker     static const size_t resultPtsSizes3[] = { 1, 2, 1, 1, 1, 0 };
3116*c8dee2aaSAndroid Build Coastguard Worker     static const SkPoint* resultPts1 = nullptr;
3117*c8dee2aaSAndroid Build Coastguard Worker     static const SkPoint resultPts2[] = {
3118*c8dee2aaSAndroid Build Coastguard Worker         { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { 0, 0 }, { 0, 0 }
3119*c8dee2aaSAndroid Build Coastguard Worker     };
3120*c8dee2aaSAndroid Build Coastguard Worker     static const SkPoint resultPts3[] = {
3121*c8dee2aaSAndroid Build Coastguard Worker         { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { 0, 0 }, { 0, 0 }
3122*c8dee2aaSAndroid Build Coastguard Worker     };
3123*c8dee2aaSAndroid Build Coastguard Worker     static const struct iterTestData gIterTests[] = {
3124*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 0", false, resultPtsSizes1, resultPts1, resultVerbs1, std::size(resultVerbs1) },
3125*c8dee2aaSAndroid Build Coastguard Worker         { "z", false, resultPtsSizes1, resultPts1, resultVerbs1, std::size(resultVerbs1) },
3126*c8dee2aaSAndroid Build Coastguard Worker         { "z", true, resultPtsSizes1, resultPts1, resultVerbs1, std::size(resultVerbs1) },
3127*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 0 L 1 0 M 0 0 z", false, resultPtsSizes2, resultPts2, resultVerbs2, std::size(resultVerbs2) },
3128*c8dee2aaSAndroid Build Coastguard Worker         { "M 1 0 L 1 0 M 0 0 z", true, resultPtsSizes3, resultPts3, resultVerbs3, std::size(resultVerbs3) }
3129*c8dee2aaSAndroid Build Coastguard Worker     };
3130*c8dee2aaSAndroid Build Coastguard Worker 
3131*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < std::size(gIterTests); ++i) {
3132*c8dee2aaSAndroid Build Coastguard Worker         p.reset();
3133*c8dee2aaSAndroid Build Coastguard Worker         bool valid = SkParsePath::FromSVGString(gIterTests[i].testPath, &p);
3134*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, valid);
3135*c8dee2aaSAndroid Build Coastguard Worker         iter.setPath(p, gIterTests[i].forceClose);
3136*c8dee2aaSAndroid Build Coastguard Worker         int j = 0, l = 0;
3137*c8dee2aaSAndroid Build Coastguard Worker         do {
3138*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, iter.next(pts) == gIterTests[i].resultVerbs[j]);
3139*c8dee2aaSAndroid Build Coastguard Worker             for (int k = 0; k < (int)gIterTests[i].numResultPtsPerVerb[j]; ++k) {
3140*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, pts[k] == gIterTests[i].resultPts[l++]);
3141*c8dee2aaSAndroid Build Coastguard Worker             }
3142*c8dee2aaSAndroid Build Coastguard Worker         } while (gIterTests[i].resultVerbs[j++] != SkPath::kDone_Verb);
3143*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, j == (int)gIterTests[i].numResultVerbs);
3144*c8dee2aaSAndroid Build Coastguard Worker     }
3145*c8dee2aaSAndroid Build Coastguard Worker 
3146*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
3147*c8dee2aaSAndroid Build Coastguard Worker     iter.setPath(p, false);
3148*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !iter.isClosedContour());
3149*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(1, 1);
3150*c8dee2aaSAndroid Build Coastguard Worker     p.close();
3151*c8dee2aaSAndroid Build Coastguard Worker     iter.setPath(p, false);
3152*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, iter.isClosedContour());
3153*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
3154*c8dee2aaSAndroid Build Coastguard Worker     iter.setPath(p, true);
3155*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !iter.isClosedContour());
3156*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(1, 1);
3157*c8dee2aaSAndroid Build Coastguard Worker     iter.setPath(p, true);
3158*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, iter.isClosedContour());
3159*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(0, 0);
3160*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(2, 2);
3161*c8dee2aaSAndroid Build Coastguard Worker     iter.setPath(p, false);
3162*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !iter.isClosedContour());
3163*c8dee2aaSAndroid Build Coastguard Worker 
3164*c8dee2aaSAndroid Build Coastguard Worker     // this checks to see if the NaN logic is executed in SkPath::autoClose(), but does not
3165*c8dee2aaSAndroid Build Coastguard Worker     // check to see if the result is correct.
3166*c8dee2aaSAndroid Build Coastguard Worker     for (int setNaN = 0; setNaN < 4; ++setNaN) {
3167*c8dee2aaSAndroid Build Coastguard Worker         p.reset();
3168*c8dee2aaSAndroid Build Coastguard Worker         p.moveTo(setNaN == 0 ? SK_ScalarNaN : 0, setNaN == 1 ? SK_ScalarNaN : 0);
3169*c8dee2aaSAndroid Build Coastguard Worker         p.lineTo(setNaN == 2 ? SK_ScalarNaN : 1, setNaN == 3 ? SK_ScalarNaN : 1);
3170*c8dee2aaSAndroid Build Coastguard Worker         iter.setPath(p, true);
3171*c8dee2aaSAndroid Build Coastguard Worker         iter.next(pts);
3172*c8dee2aaSAndroid Build Coastguard Worker         iter.next(pts);
3173*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, SkPath::kClose_Verb == iter.next(pts));
3174*c8dee2aaSAndroid Build Coastguard Worker     }
3175*c8dee2aaSAndroid Build Coastguard Worker 
3176*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
3177*c8dee2aaSAndroid Build Coastguard Worker     p.quadTo(0, 0, 0, 0);
3178*c8dee2aaSAndroid Build Coastguard Worker     iter.setPath(p, false);
3179*c8dee2aaSAndroid Build Coastguard Worker     iter.next(pts);
3180*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPath::kQuad_Verb == iter.next(pts));
3181*c8dee2aaSAndroid Build Coastguard Worker 
3182*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
3183*c8dee2aaSAndroid Build Coastguard Worker     p.conicTo(0, 0, 0, 0, 0.5f);
3184*c8dee2aaSAndroid Build Coastguard Worker     iter.setPath(p, false);
3185*c8dee2aaSAndroid Build Coastguard Worker     iter.next(pts);
3186*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPath::kConic_Verb == iter.next(pts));
3187*c8dee2aaSAndroid Build Coastguard Worker 
3188*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
3189*c8dee2aaSAndroid Build Coastguard Worker     p.cubicTo(0, 0, 0, 0, 0, 0);
3190*c8dee2aaSAndroid Build Coastguard Worker     iter.setPath(p, false);
3191*c8dee2aaSAndroid Build Coastguard Worker     iter.next(pts);
3192*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPath::kCubic_Verb == iter.next(pts));
3193*c8dee2aaSAndroid Build Coastguard Worker 
3194*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(1, 1);  // add a trailing moveto
3195*c8dee2aaSAndroid Build Coastguard Worker     iter.setPath(p, false);
3196*c8dee2aaSAndroid Build Coastguard Worker     iter.next(pts);
3197*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPath::kCubic_Verb == iter.next(pts));
3198*c8dee2aaSAndroid Build Coastguard Worker 
3199*c8dee2aaSAndroid Build Coastguard Worker     // The GM degeneratesegments.cpp test is more extensive
3200*c8dee2aaSAndroid Build Coastguard Worker 
3201*c8dee2aaSAndroid Build Coastguard Worker     // Test out mixed degenerate and non-degenerate geometry with Conics
3202*c8dee2aaSAndroid Build Coastguard Worker     const SkVector radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 100, 100 } };
3203*c8dee2aaSAndroid Build Coastguard Worker     SkRect r = SkRect::MakeWH(100, 100);
3204*c8dee2aaSAndroid Build Coastguard Worker     SkRRect rr;
3205*c8dee2aaSAndroid Build Coastguard Worker     rr.setRectRadii(r, radii);
3206*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
3207*c8dee2aaSAndroid Build Coastguard Worker     p.addRRect(rr);
3208*c8dee2aaSAndroid Build Coastguard Worker     iter.setPath(p, false);
3209*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPath::kMove_Verb == iter.next(pts));
3210*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPath::kLine_Verb == iter.next(pts));
3211*c8dee2aaSAndroid Build Coastguard Worker     return;
3212*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPath::kLine_Verb == iter.next(pts));
3213*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPath::kConic_Verb == iter.next(pts));
3214*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SK_ScalarRoot2Over2 == iter.conicWeight());
3215*c8dee2aaSAndroid Build Coastguard Worker }
3216*c8dee2aaSAndroid Build Coastguard Worker 
test_range_iter(skiatest::Reporter * reporter)3217*c8dee2aaSAndroid Build Coastguard Worker static void test_range_iter(skiatest::Reporter* reporter) {
3218*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
3219*c8dee2aaSAndroid Build Coastguard Worker 
3220*c8dee2aaSAndroid Build Coastguard Worker     // Test an iterator with an initial empty path
3221*c8dee2aaSAndroid Build Coastguard Worker     SkPathPriv::Iterate iterate(path);
3222*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, iterate.begin() == iterate.end());
3223*c8dee2aaSAndroid Build Coastguard Worker 
3224*c8dee2aaSAndroid Build Coastguard Worker     // Test that a move-only path returns the move.
3225*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SK_Scalar1, 0);
3226*c8dee2aaSAndroid Build Coastguard Worker     iterate = SkPathPriv::Iterate(path);
3227*c8dee2aaSAndroid Build Coastguard Worker     SkPathPriv::RangeIter iter = iterate.begin();
3228*c8dee2aaSAndroid Build Coastguard Worker     {
3229*c8dee2aaSAndroid Build Coastguard Worker         auto [verb, pts, w] = *iter++;
3230*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, verb == SkPathVerb::kMove);
3231*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
3232*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pts[0].fY == 0);
3233*c8dee2aaSAndroid Build Coastguard Worker     }
3234*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, iter == iterate.end());
3235*c8dee2aaSAndroid Build Coastguard Worker 
3236*c8dee2aaSAndroid Build Coastguard Worker     // No matter how many moves we add, we should get them all back
3237*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SK_Scalar1*2, SK_Scalar1);
3238*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SK_Scalar1*3, SK_Scalar1*2);
3239*c8dee2aaSAndroid Build Coastguard Worker     iterate = SkPathPriv::Iterate(path);
3240*c8dee2aaSAndroid Build Coastguard Worker     iter = iterate.begin();
3241*c8dee2aaSAndroid Build Coastguard Worker     {
3242*c8dee2aaSAndroid Build Coastguard Worker         auto [verb, pts, w] = *iter++;
3243*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, verb == SkPathVerb::kMove);
3244*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
3245*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pts[0].fY == 0);
3246*c8dee2aaSAndroid Build Coastguard Worker     }
3247*c8dee2aaSAndroid Build Coastguard Worker     {
3248*c8dee2aaSAndroid Build Coastguard Worker         auto [verb, pts, w] = *iter++;
3249*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, verb == SkPathVerb::kMove);
3250*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
3251*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
3252*c8dee2aaSAndroid Build Coastguard Worker     }
3253*c8dee2aaSAndroid Build Coastguard Worker     {
3254*c8dee2aaSAndroid Build Coastguard Worker         auto [verb, pts, w] = *iter++;
3255*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, verb == SkPathVerb::kMove);
3256*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
3257*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
3258*c8dee2aaSAndroid Build Coastguard Worker     }
3259*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, iter == iterate.end());
3260*c8dee2aaSAndroid Build Coastguard Worker 
3261*c8dee2aaSAndroid Build Coastguard Worker     // Initial close is never ever stored
3262*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
3263*c8dee2aaSAndroid Build Coastguard Worker     path.close();
3264*c8dee2aaSAndroid Build Coastguard Worker     iterate = SkPathPriv::Iterate(path);
3265*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, iterate.begin() == iterate.end());
3266*c8dee2aaSAndroid Build Coastguard Worker 
3267*c8dee2aaSAndroid Build Coastguard Worker     // Move/close sequences
3268*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
3269*c8dee2aaSAndroid Build Coastguard Worker     path.close(); // Not stored, no purpose
3270*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SK_Scalar1, 0);
3271*c8dee2aaSAndroid Build Coastguard Worker     path.close();
3272*c8dee2aaSAndroid Build Coastguard Worker     path.close(); // Not stored, no purpose
3273*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SK_Scalar1*2, SK_Scalar1);
3274*c8dee2aaSAndroid Build Coastguard Worker     path.close();
3275*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SK_Scalar1*3, SK_Scalar1*2);
3276*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SK_Scalar1*4, SK_Scalar1*3);
3277*c8dee2aaSAndroid Build Coastguard Worker     path.close();
3278*c8dee2aaSAndroid Build Coastguard Worker     iterate = SkPathPriv::Iterate(path);
3279*c8dee2aaSAndroid Build Coastguard Worker     iter = iterate.begin();
3280*c8dee2aaSAndroid Build Coastguard Worker     {
3281*c8dee2aaSAndroid Build Coastguard Worker         auto [verb, pts, w] = *iter++;
3282*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, verb == SkPathVerb::kMove);
3283*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
3284*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pts[0].fY == 0);
3285*c8dee2aaSAndroid Build Coastguard Worker     }
3286*c8dee2aaSAndroid Build Coastguard Worker     {
3287*c8dee2aaSAndroid Build Coastguard Worker         auto [verb, pts, w] = *iter++;
3288*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, verb == SkPathVerb::kClose);
3289*c8dee2aaSAndroid Build Coastguard Worker     }
3290*c8dee2aaSAndroid Build Coastguard Worker     {
3291*c8dee2aaSAndroid Build Coastguard Worker         auto [verb, pts, w] = *iter++;
3292*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, verb == SkPathVerb::kMove);
3293*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
3294*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
3295*c8dee2aaSAndroid Build Coastguard Worker     }
3296*c8dee2aaSAndroid Build Coastguard Worker     {
3297*c8dee2aaSAndroid Build Coastguard Worker         auto [verb, pts, w] = *iter++;
3298*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, verb == SkPathVerb::kClose);
3299*c8dee2aaSAndroid Build Coastguard Worker     }
3300*c8dee2aaSAndroid Build Coastguard Worker     {
3301*c8dee2aaSAndroid Build Coastguard Worker         auto [verb, pts, w] = *iter++;
3302*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, verb == SkPathVerb::kMove);
3303*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
3304*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
3305*c8dee2aaSAndroid Build Coastguard Worker     }
3306*c8dee2aaSAndroid Build Coastguard Worker     {
3307*c8dee2aaSAndroid Build Coastguard Worker         auto [verb, pts, w] = *iter++;
3308*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, verb == SkPathVerb::kMove);
3309*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
3310*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
3311*c8dee2aaSAndroid Build Coastguard Worker     }
3312*c8dee2aaSAndroid Build Coastguard Worker     {
3313*c8dee2aaSAndroid Build Coastguard Worker         auto [verb, pts, w] = *iter++;
3314*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, verb == SkPathVerb::kClose);
3315*c8dee2aaSAndroid Build Coastguard Worker     }
3316*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, iter == iterate.end());
3317*c8dee2aaSAndroid Build Coastguard Worker 
3318*c8dee2aaSAndroid Build Coastguard Worker     // Generate random paths and verify
3319*c8dee2aaSAndroid Build Coastguard Worker     SkPoint randomPts[25];
3320*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 5; ++i) {
3321*c8dee2aaSAndroid Build Coastguard Worker         for (int j = 0; j < 5; ++j) {
3322*c8dee2aaSAndroid Build Coastguard Worker             randomPts[i*5+j].set(SK_Scalar1*i, SK_Scalar1*j);
3323*c8dee2aaSAndroid Build Coastguard Worker         }
3324*c8dee2aaSAndroid Build Coastguard Worker     }
3325*c8dee2aaSAndroid Build Coastguard Worker 
3326*c8dee2aaSAndroid Build Coastguard Worker     // Max of 10 segments, max 3 points per segment
3327*c8dee2aaSAndroid Build Coastguard Worker     SkRandom rand(9876543);
3328*c8dee2aaSAndroid Build Coastguard Worker     SkPoint expectedPts[31]; // May have leading moveTo
3329*c8dee2aaSAndroid Build Coastguard Worker     SkPathVerb expectedVerbs[22]; // May have leading moveTo
3330*c8dee2aaSAndroid Build Coastguard Worker     SkPathVerb nextVerb;
3331*c8dee2aaSAndroid Build Coastguard Worker 
3332*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 500; ++i) {
3333*c8dee2aaSAndroid Build Coastguard Worker         path.reset();
3334*c8dee2aaSAndroid Build Coastguard Worker         bool lastWasClose = true;
3335*c8dee2aaSAndroid Build Coastguard Worker         bool haveMoveTo = false;
3336*c8dee2aaSAndroid Build Coastguard Worker         SkPoint lastMoveToPt = { 0, 0 };
3337*c8dee2aaSAndroid Build Coastguard Worker         int numPoints = 0;
3338*c8dee2aaSAndroid Build Coastguard Worker         int numVerbs = (rand.nextU() >> 16) % 10;
3339*c8dee2aaSAndroid Build Coastguard Worker         int numIterVerbs = 0;
3340*c8dee2aaSAndroid Build Coastguard Worker         for (int j = 0; j < numVerbs; ++j) {
3341*c8dee2aaSAndroid Build Coastguard Worker             do {
3342*c8dee2aaSAndroid Build Coastguard Worker                 nextVerb = static_cast<SkPathVerb>((rand.nextU() >> 16) % SkPath::kDone_Verb);
3343*c8dee2aaSAndroid Build Coastguard Worker             } while (lastWasClose && nextVerb == SkPathVerb::kClose);
3344*c8dee2aaSAndroid Build Coastguard Worker             switch (nextVerb) {
3345*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kMove:
3346*c8dee2aaSAndroid Build Coastguard Worker                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
3347*c8dee2aaSAndroid Build Coastguard Worker                     path.moveTo(expectedPts[numPoints]);
3348*c8dee2aaSAndroid Build Coastguard Worker                     lastMoveToPt = expectedPts[numPoints];
3349*c8dee2aaSAndroid Build Coastguard Worker                     numPoints += 1;
3350*c8dee2aaSAndroid Build Coastguard Worker                     lastWasClose = false;
3351*c8dee2aaSAndroid Build Coastguard Worker                     haveMoveTo = true;
3352*c8dee2aaSAndroid Build Coastguard Worker                     break;
3353*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kLine:
3354*c8dee2aaSAndroid Build Coastguard Worker                     if (!haveMoveTo) {
3355*c8dee2aaSAndroid Build Coastguard Worker                         expectedPts[numPoints++] = lastMoveToPt;
3356*c8dee2aaSAndroid Build Coastguard Worker                         expectedVerbs[numIterVerbs++] = SkPathVerb::kMove;
3357*c8dee2aaSAndroid Build Coastguard Worker                         haveMoveTo = true;
3358*c8dee2aaSAndroid Build Coastguard Worker                     }
3359*c8dee2aaSAndroid Build Coastguard Worker                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
3360*c8dee2aaSAndroid Build Coastguard Worker                     path.lineTo(expectedPts[numPoints]);
3361*c8dee2aaSAndroid Build Coastguard Worker                     numPoints += 1;
3362*c8dee2aaSAndroid Build Coastguard Worker                     lastWasClose = false;
3363*c8dee2aaSAndroid Build Coastguard Worker                     break;
3364*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kQuad:
3365*c8dee2aaSAndroid Build Coastguard Worker                     if (!haveMoveTo) {
3366*c8dee2aaSAndroid Build Coastguard Worker                         expectedPts[numPoints++] = lastMoveToPt;
3367*c8dee2aaSAndroid Build Coastguard Worker                         expectedVerbs[numIterVerbs++] = SkPathVerb::kMove;
3368*c8dee2aaSAndroid Build Coastguard Worker                         haveMoveTo = true;
3369*c8dee2aaSAndroid Build Coastguard Worker                     }
3370*c8dee2aaSAndroid Build Coastguard Worker                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
3371*c8dee2aaSAndroid Build Coastguard Worker                     expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
3372*c8dee2aaSAndroid Build Coastguard Worker                     path.quadTo(expectedPts[numPoints], expectedPts[numPoints + 1]);
3373*c8dee2aaSAndroid Build Coastguard Worker                     numPoints += 2;
3374*c8dee2aaSAndroid Build Coastguard Worker                     lastWasClose = false;
3375*c8dee2aaSAndroid Build Coastguard Worker                     break;
3376*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kConic:
3377*c8dee2aaSAndroid Build Coastguard Worker                     if (!haveMoveTo) {
3378*c8dee2aaSAndroid Build Coastguard Worker                         expectedPts[numPoints++] = lastMoveToPt;
3379*c8dee2aaSAndroid Build Coastguard Worker                         expectedVerbs[numIterVerbs++] = SkPathVerb::kMove;
3380*c8dee2aaSAndroid Build Coastguard Worker                         haveMoveTo = true;
3381*c8dee2aaSAndroid Build Coastguard Worker                     }
3382*c8dee2aaSAndroid Build Coastguard Worker                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
3383*c8dee2aaSAndroid Build Coastguard Worker                     expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
3384*c8dee2aaSAndroid Build Coastguard Worker                     path.conicTo(expectedPts[numPoints], expectedPts[numPoints + 1],
3385*c8dee2aaSAndroid Build Coastguard Worker                                  rand.nextUScalar1() * 4);
3386*c8dee2aaSAndroid Build Coastguard Worker                     numPoints += 2;
3387*c8dee2aaSAndroid Build Coastguard Worker                     lastWasClose = false;
3388*c8dee2aaSAndroid Build Coastguard Worker                     break;
3389*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kCubic:
3390*c8dee2aaSAndroid Build Coastguard Worker                     if (!haveMoveTo) {
3391*c8dee2aaSAndroid Build Coastguard Worker                         expectedPts[numPoints++] = lastMoveToPt;
3392*c8dee2aaSAndroid Build Coastguard Worker                         expectedVerbs[numIterVerbs++] = SkPathVerb::kMove;
3393*c8dee2aaSAndroid Build Coastguard Worker                         haveMoveTo = true;
3394*c8dee2aaSAndroid Build Coastguard Worker                     }
3395*c8dee2aaSAndroid Build Coastguard Worker                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
3396*c8dee2aaSAndroid Build Coastguard Worker                     expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
3397*c8dee2aaSAndroid Build Coastguard Worker                     expectedPts[numPoints + 2] = randomPts[(rand.nextU() >> 16) % 25];
3398*c8dee2aaSAndroid Build Coastguard Worker                     path.cubicTo(expectedPts[numPoints], expectedPts[numPoints + 1],
3399*c8dee2aaSAndroid Build Coastguard Worker                                  expectedPts[numPoints + 2]);
3400*c8dee2aaSAndroid Build Coastguard Worker                     numPoints += 3;
3401*c8dee2aaSAndroid Build Coastguard Worker                     lastWasClose = false;
3402*c8dee2aaSAndroid Build Coastguard Worker                     break;
3403*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kClose:
3404*c8dee2aaSAndroid Build Coastguard Worker                     path.close();
3405*c8dee2aaSAndroid Build Coastguard Worker                     haveMoveTo = false;
3406*c8dee2aaSAndroid Build Coastguard Worker                     lastWasClose = true;
3407*c8dee2aaSAndroid Build Coastguard Worker                     break;
3408*c8dee2aaSAndroid Build Coastguard Worker                 default:
3409*c8dee2aaSAndroid Build Coastguard Worker                     SkDEBUGFAIL("unexpected verb");
3410*c8dee2aaSAndroid Build Coastguard Worker             }
3411*c8dee2aaSAndroid Build Coastguard Worker             expectedVerbs[numIterVerbs++] = nextVerb;
3412*c8dee2aaSAndroid Build Coastguard Worker         }
3413*c8dee2aaSAndroid Build Coastguard Worker 
3414*c8dee2aaSAndroid Build Coastguard Worker         numVerbs = numIterVerbs;
3415*c8dee2aaSAndroid Build Coastguard Worker         numIterVerbs = 0;
3416*c8dee2aaSAndroid Build Coastguard Worker         int numIterPts = 0;
3417*c8dee2aaSAndroid Build Coastguard Worker         SkPoint lastMoveTo;
3418*c8dee2aaSAndroid Build Coastguard Worker         SkPoint lastPt;
3419*c8dee2aaSAndroid Build Coastguard Worker         lastMoveTo.set(0, 0);
3420*c8dee2aaSAndroid Build Coastguard Worker         lastPt.set(0, 0);
3421*c8dee2aaSAndroid Build Coastguard Worker         for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
3422*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, verb == expectedVerbs[numIterVerbs]);
3423*c8dee2aaSAndroid Build Coastguard Worker             numIterVerbs++;
3424*c8dee2aaSAndroid Build Coastguard Worker             switch (verb) {
3425*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kMove:
3426*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, numIterPts < numPoints);
3427*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, pts[0] == expectedPts[numIterPts]);
3428*c8dee2aaSAndroid Build Coastguard Worker                     lastPt = lastMoveTo = pts[0];
3429*c8dee2aaSAndroid Build Coastguard Worker                     numIterPts += 1;
3430*c8dee2aaSAndroid Build Coastguard Worker                     break;
3431*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kLine:
3432*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, numIterPts < numPoints + 1);
3433*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, pts[0] == lastPt);
3434*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
3435*c8dee2aaSAndroid Build Coastguard Worker                     lastPt = pts[1];
3436*c8dee2aaSAndroid Build Coastguard Worker                     numIterPts += 1;
3437*c8dee2aaSAndroid Build Coastguard Worker                     break;
3438*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kQuad:
3439*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kConic:
3440*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, numIterPts < numPoints + 2);
3441*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, pts[0] == lastPt);
3442*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
3443*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
3444*c8dee2aaSAndroid Build Coastguard Worker                     lastPt = pts[2];
3445*c8dee2aaSAndroid Build Coastguard Worker                     numIterPts += 2;
3446*c8dee2aaSAndroid Build Coastguard Worker                     break;
3447*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kCubic:
3448*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, numIterPts < numPoints + 3);
3449*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, pts[0] == lastPt);
3450*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
3451*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
3452*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, pts[3] == expectedPts[numIterPts + 2]);
3453*c8dee2aaSAndroid Build Coastguard Worker                     lastPt = pts[3];
3454*c8dee2aaSAndroid Build Coastguard Worker                     numIterPts += 3;
3455*c8dee2aaSAndroid Build Coastguard Worker                     break;
3456*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathVerb::kClose:
3457*c8dee2aaSAndroid Build Coastguard Worker                     lastPt = lastMoveTo;
3458*c8dee2aaSAndroid Build Coastguard Worker                     break;
3459*c8dee2aaSAndroid Build Coastguard Worker                 default:
3460*c8dee2aaSAndroid Build Coastguard Worker                     SkDEBUGFAIL("unexpected verb");
3461*c8dee2aaSAndroid Build Coastguard Worker             }
3462*c8dee2aaSAndroid Build Coastguard Worker         }
3463*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, numIterPts == numPoints);
3464*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, numIterVerbs == numVerbs);
3465*c8dee2aaSAndroid Build Coastguard Worker     }
3466*c8dee2aaSAndroid Build Coastguard Worker }
3467*c8dee2aaSAndroid Build Coastguard Worker 
check_for_circle(skiatest::Reporter * reporter,const SkPath & path,bool expectedCircle,SkPathFirstDirection expectedDir)3468*c8dee2aaSAndroid Build Coastguard Worker static void check_for_circle(skiatest::Reporter* reporter,
3469*c8dee2aaSAndroid Build Coastguard Worker                              const SkPath& path,
3470*c8dee2aaSAndroid Build Coastguard Worker                              bool expectedCircle,
3471*c8dee2aaSAndroid Build Coastguard Worker                              SkPathFirstDirection expectedDir) {
3472*c8dee2aaSAndroid Build Coastguard Worker     SkRect rect = SkRect::MakeEmpty();
3473*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isOval(&rect) == expectedCircle);
3474*c8dee2aaSAndroid Build Coastguard Worker     SkPathDirection isOvalDir;
3475*c8dee2aaSAndroid Build Coastguard Worker     unsigned isOvalStart;
3476*c8dee2aaSAndroid Build Coastguard Worker     if (SkPathPriv::IsOval(path, &rect, &isOvalDir, &isOvalStart)) {
3477*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, rect.height() == rect.width());
3478*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, SkPathPriv::AsFirstDirection(isOvalDir) == expectedDir);
3479*c8dee2aaSAndroid Build Coastguard Worker         SkPath tmpPath;
3480*c8dee2aaSAndroid Build Coastguard Worker         tmpPath.addOval(rect, isOvalDir, isOvalStart);
3481*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, path == tmpPath);
3482*c8dee2aaSAndroid Build Coastguard Worker     }
3483*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathPriv::ComputeFirstDirection(path) == expectedDir);
3484*c8dee2aaSAndroid Build Coastguard Worker }
3485*c8dee2aaSAndroid Build Coastguard Worker 
test_circle_skew(skiatest::Reporter * reporter,const SkPath & path,SkPathFirstDirection dir)3486*c8dee2aaSAndroid Build Coastguard Worker static void test_circle_skew(skiatest::Reporter* reporter,
3487*c8dee2aaSAndroid Build Coastguard Worker                              const SkPath& path,
3488*c8dee2aaSAndroid Build Coastguard Worker                              SkPathFirstDirection dir) {
3489*c8dee2aaSAndroid Build Coastguard Worker     SkPath tmp;
3490*c8dee2aaSAndroid Build Coastguard Worker 
3491*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix m;
3492*c8dee2aaSAndroid Build Coastguard Worker     m.setSkew(SkIntToScalar(3), SkIntToScalar(5));
3493*c8dee2aaSAndroid Build Coastguard Worker     path.transform(m, &tmp);
3494*c8dee2aaSAndroid Build Coastguard Worker     // this matrix reverses the direction.
3495*c8dee2aaSAndroid Build Coastguard Worker     if (SkPathFirstDirection::kCCW == dir) {
3496*c8dee2aaSAndroid Build Coastguard Worker         dir = SkPathFirstDirection::kCW;
3497*c8dee2aaSAndroid Build Coastguard Worker     } else {
3498*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, SkPathFirstDirection::kCW == dir);
3499*c8dee2aaSAndroid Build Coastguard Worker         dir = SkPathFirstDirection::kCCW;
3500*c8dee2aaSAndroid Build Coastguard Worker     }
3501*c8dee2aaSAndroid Build Coastguard Worker     check_for_circle(reporter, tmp, false, dir);
3502*c8dee2aaSAndroid Build Coastguard Worker }
3503*c8dee2aaSAndroid Build Coastguard Worker 
test_circle_translate(skiatest::Reporter * reporter,const SkPath & path,SkPathFirstDirection dir)3504*c8dee2aaSAndroid Build Coastguard Worker static void test_circle_translate(skiatest::Reporter* reporter,
3505*c8dee2aaSAndroid Build Coastguard Worker                                   const SkPath& path,
3506*c8dee2aaSAndroid Build Coastguard Worker                                   SkPathFirstDirection dir) {
3507*c8dee2aaSAndroid Build Coastguard Worker     SkPath tmp;
3508*c8dee2aaSAndroid Build Coastguard Worker 
3509*c8dee2aaSAndroid Build Coastguard Worker     // translate at small offset
3510*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix m;
3511*c8dee2aaSAndroid Build Coastguard Worker     m.setTranslate(SkIntToScalar(15), SkIntToScalar(15));
3512*c8dee2aaSAndroid Build Coastguard Worker     path.transform(m, &tmp);
3513*c8dee2aaSAndroid Build Coastguard Worker     check_for_circle(reporter, tmp, true, dir);
3514*c8dee2aaSAndroid Build Coastguard Worker 
3515*c8dee2aaSAndroid Build Coastguard Worker     tmp.reset();
3516*c8dee2aaSAndroid Build Coastguard Worker     m.reset();
3517*c8dee2aaSAndroid Build Coastguard Worker 
3518*c8dee2aaSAndroid Build Coastguard Worker     // translate at a relatively big offset
3519*c8dee2aaSAndroid Build Coastguard Worker     m.setTranslate(SkIntToScalar(1000), SkIntToScalar(1000));
3520*c8dee2aaSAndroid Build Coastguard Worker     path.transform(m, &tmp);
3521*c8dee2aaSAndroid Build Coastguard Worker     check_for_circle(reporter, tmp, true, dir);
3522*c8dee2aaSAndroid Build Coastguard Worker }
3523*c8dee2aaSAndroid Build Coastguard Worker 
test_circle_rotate(skiatest::Reporter * reporter,const SkPath & path,SkPathFirstDirection dir)3524*c8dee2aaSAndroid Build Coastguard Worker static void test_circle_rotate(skiatest::Reporter* reporter,
3525*c8dee2aaSAndroid Build Coastguard Worker                                const SkPath& path,
3526*c8dee2aaSAndroid Build Coastguard Worker                                SkPathFirstDirection dir) {
3527*c8dee2aaSAndroid Build Coastguard Worker     for (int angle = 0; angle < 360; ++angle) {
3528*c8dee2aaSAndroid Build Coastguard Worker         SkPath tmp;
3529*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix m;
3530*c8dee2aaSAndroid Build Coastguard Worker         m.setRotate(SkIntToScalar(angle));
3531*c8dee2aaSAndroid Build Coastguard Worker         path.transform(m, &tmp);
3532*c8dee2aaSAndroid Build Coastguard Worker 
3533*c8dee2aaSAndroid Build Coastguard Worker         // TODO: a rotated circle whose rotated angle is not a multiple of 90
3534*c8dee2aaSAndroid Build Coastguard Worker         // degrees is not an oval anymore, this can be improved.  we made this
3535*c8dee2aaSAndroid Build Coastguard Worker         // for the simplicity of our implementation.
3536*c8dee2aaSAndroid Build Coastguard Worker         if (angle % 90 == 0) {
3537*c8dee2aaSAndroid Build Coastguard Worker             check_for_circle(reporter, tmp, true, dir);
3538*c8dee2aaSAndroid Build Coastguard Worker         } else {
3539*c8dee2aaSAndroid Build Coastguard Worker             check_for_circle(reporter, tmp, false, dir);
3540*c8dee2aaSAndroid Build Coastguard Worker         }
3541*c8dee2aaSAndroid Build Coastguard Worker     }
3542*c8dee2aaSAndroid Build Coastguard Worker }
3543*c8dee2aaSAndroid Build Coastguard Worker 
test_circle_mirror_x(skiatest::Reporter * reporter,const SkPath & path,SkPathFirstDirection dir)3544*c8dee2aaSAndroid Build Coastguard Worker static void test_circle_mirror_x(skiatest::Reporter* reporter,
3545*c8dee2aaSAndroid Build Coastguard Worker                                  const SkPath& path,
3546*c8dee2aaSAndroid Build Coastguard Worker                                  SkPathFirstDirection dir) {
3547*c8dee2aaSAndroid Build Coastguard Worker     SkPath tmp;
3548*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix m;
3549*c8dee2aaSAndroid Build Coastguard Worker     m.reset();
3550*c8dee2aaSAndroid Build Coastguard Worker     m.setScaleX(-SK_Scalar1);
3551*c8dee2aaSAndroid Build Coastguard Worker     path.transform(m, &tmp);
3552*c8dee2aaSAndroid Build Coastguard Worker     if (SkPathFirstDirection::kCW == dir) {
3553*c8dee2aaSAndroid Build Coastguard Worker         dir = SkPathFirstDirection::kCCW;
3554*c8dee2aaSAndroid Build Coastguard Worker     } else {
3555*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, SkPathFirstDirection::kCCW == dir);
3556*c8dee2aaSAndroid Build Coastguard Worker         dir = SkPathFirstDirection::kCW;
3557*c8dee2aaSAndroid Build Coastguard Worker     }
3558*c8dee2aaSAndroid Build Coastguard Worker     check_for_circle(reporter, tmp, true, dir);
3559*c8dee2aaSAndroid Build Coastguard Worker }
3560*c8dee2aaSAndroid Build Coastguard Worker 
test_circle_mirror_y(skiatest::Reporter * reporter,const SkPath & path,SkPathFirstDirection dir)3561*c8dee2aaSAndroid Build Coastguard Worker static void test_circle_mirror_y(skiatest::Reporter* reporter,
3562*c8dee2aaSAndroid Build Coastguard Worker                                  const SkPath& path,
3563*c8dee2aaSAndroid Build Coastguard Worker                                  SkPathFirstDirection dir) {
3564*c8dee2aaSAndroid Build Coastguard Worker     SkPath tmp;
3565*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix m;
3566*c8dee2aaSAndroid Build Coastguard Worker     m.reset();
3567*c8dee2aaSAndroid Build Coastguard Worker     m.setScaleY(-SK_Scalar1);
3568*c8dee2aaSAndroid Build Coastguard Worker     path.transform(m, &tmp);
3569*c8dee2aaSAndroid Build Coastguard Worker 
3570*c8dee2aaSAndroid Build Coastguard Worker     if (SkPathFirstDirection::kCW == dir) {
3571*c8dee2aaSAndroid Build Coastguard Worker         dir = SkPathFirstDirection::kCCW;
3572*c8dee2aaSAndroid Build Coastguard Worker     } else {
3573*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, SkPathFirstDirection::kCCW == dir);
3574*c8dee2aaSAndroid Build Coastguard Worker         dir = SkPathFirstDirection::kCW;
3575*c8dee2aaSAndroid Build Coastguard Worker     }
3576*c8dee2aaSAndroid Build Coastguard Worker 
3577*c8dee2aaSAndroid Build Coastguard Worker     check_for_circle(reporter, tmp, true, dir);
3578*c8dee2aaSAndroid Build Coastguard Worker }
3579*c8dee2aaSAndroid Build Coastguard Worker 
test_circle_mirror_xy(skiatest::Reporter * reporter,const SkPath & path,SkPathFirstDirection dir)3580*c8dee2aaSAndroid Build Coastguard Worker static void test_circle_mirror_xy(skiatest::Reporter* reporter,
3581*c8dee2aaSAndroid Build Coastguard Worker                                  const SkPath& path,
3582*c8dee2aaSAndroid Build Coastguard Worker                                  SkPathFirstDirection dir) {
3583*c8dee2aaSAndroid Build Coastguard Worker     SkPath tmp;
3584*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix m;
3585*c8dee2aaSAndroid Build Coastguard Worker     m.reset();
3586*c8dee2aaSAndroid Build Coastguard Worker     m.setScaleX(-SK_Scalar1);
3587*c8dee2aaSAndroid Build Coastguard Worker     m.setScaleY(-SK_Scalar1);
3588*c8dee2aaSAndroid Build Coastguard Worker     path.transform(m, &tmp);
3589*c8dee2aaSAndroid Build Coastguard Worker 
3590*c8dee2aaSAndroid Build Coastguard Worker     check_for_circle(reporter, tmp, true, dir);
3591*c8dee2aaSAndroid Build Coastguard Worker }
3592*c8dee2aaSAndroid Build Coastguard Worker 
test_circle_with_direction(skiatest::Reporter * reporter,SkPathDirection inDir)3593*c8dee2aaSAndroid Build Coastguard Worker static void test_circle_with_direction(skiatest::Reporter* reporter,
3594*c8dee2aaSAndroid Build Coastguard Worker                                        SkPathDirection inDir) {
3595*c8dee2aaSAndroid Build Coastguard Worker     const SkPathFirstDirection dir = SkPathPriv::AsFirstDirection(inDir);
3596*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
3597*c8dee2aaSAndroid Build Coastguard Worker 
3598*c8dee2aaSAndroid Build Coastguard Worker     // circle at origin
3599*c8dee2aaSAndroid Build Coastguard Worker     path.addCircle(0, 0, SkIntToScalar(20), inDir);
3600*c8dee2aaSAndroid Build Coastguard Worker 
3601*c8dee2aaSAndroid Build Coastguard Worker     check_for_circle(reporter, path, true, dir);
3602*c8dee2aaSAndroid Build Coastguard Worker     test_circle_rotate(reporter, path, dir);
3603*c8dee2aaSAndroid Build Coastguard Worker     test_circle_translate(reporter, path, dir);
3604*c8dee2aaSAndroid Build Coastguard Worker     test_circle_skew(reporter, path, dir);
3605*c8dee2aaSAndroid Build Coastguard Worker     test_circle_mirror_x(reporter, path, dir);
3606*c8dee2aaSAndroid Build Coastguard Worker     test_circle_mirror_y(reporter, path, dir);
3607*c8dee2aaSAndroid Build Coastguard Worker     test_circle_mirror_xy(reporter, path, dir);
3608*c8dee2aaSAndroid Build Coastguard Worker 
3609*c8dee2aaSAndroid Build Coastguard Worker     // circle at an offset at (10, 10)
3610*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
3611*c8dee2aaSAndroid Build Coastguard Worker     path.addCircle(SkIntToScalar(10), SkIntToScalar(10),
3612*c8dee2aaSAndroid Build Coastguard Worker                    SkIntToScalar(20), inDir);
3613*c8dee2aaSAndroid Build Coastguard Worker 
3614*c8dee2aaSAndroid Build Coastguard Worker     check_for_circle(reporter, path, true, dir);
3615*c8dee2aaSAndroid Build Coastguard Worker     test_circle_rotate(reporter, path, dir);
3616*c8dee2aaSAndroid Build Coastguard Worker     test_circle_translate(reporter, path, dir);
3617*c8dee2aaSAndroid Build Coastguard Worker     test_circle_skew(reporter, path, dir);
3618*c8dee2aaSAndroid Build Coastguard Worker     test_circle_mirror_x(reporter, path, dir);
3619*c8dee2aaSAndroid Build Coastguard Worker     test_circle_mirror_y(reporter, path, dir);
3620*c8dee2aaSAndroid Build Coastguard Worker     test_circle_mirror_xy(reporter, path, dir);
3621*c8dee2aaSAndroid Build Coastguard Worker 
3622*c8dee2aaSAndroid Build Coastguard Worker     // Try different starting points for the contour.
3623*c8dee2aaSAndroid Build Coastguard Worker     for (unsigned start = 0; start < 4; ++start) {
3624*c8dee2aaSAndroid Build Coastguard Worker         path.reset();
3625*c8dee2aaSAndroid Build Coastguard Worker         path.addOval(SkRect::MakeXYWH(20, 10, 5, 5), inDir, start);
3626*c8dee2aaSAndroid Build Coastguard Worker         test_circle_rotate(reporter, path, dir);
3627*c8dee2aaSAndroid Build Coastguard Worker         test_circle_translate(reporter, path, dir);
3628*c8dee2aaSAndroid Build Coastguard Worker         test_circle_skew(reporter, path, dir);
3629*c8dee2aaSAndroid Build Coastguard Worker         test_circle_mirror_x(reporter, path, dir);
3630*c8dee2aaSAndroid Build Coastguard Worker         test_circle_mirror_y(reporter, path, dir);
3631*c8dee2aaSAndroid Build Coastguard Worker         test_circle_mirror_xy(reporter, path, dir);
3632*c8dee2aaSAndroid Build Coastguard Worker     }
3633*c8dee2aaSAndroid Build Coastguard Worker }
3634*c8dee2aaSAndroid Build Coastguard Worker 
test_circle_with_add_paths(skiatest::Reporter * reporter)3635*c8dee2aaSAndroid Build Coastguard Worker static void test_circle_with_add_paths(skiatest::Reporter* reporter) {
3636*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
3637*c8dee2aaSAndroid Build Coastguard Worker     SkPath circle;
3638*c8dee2aaSAndroid Build Coastguard Worker     SkPath rect;
3639*c8dee2aaSAndroid Build Coastguard Worker     SkPath empty;
3640*c8dee2aaSAndroid Build Coastguard Worker 
3641*c8dee2aaSAndroid Build Coastguard Worker     const SkPathDirection kCircleDir = SkPathDirection::kCW;
3642*c8dee2aaSAndroid Build Coastguard Worker     const SkPathDirection kCircleDirOpposite = SkPathDirection::kCCW;
3643*c8dee2aaSAndroid Build Coastguard Worker 
3644*c8dee2aaSAndroid Build Coastguard Worker     circle.addCircle(0, 0, SkIntToScalar(10), kCircleDir);
3645*c8dee2aaSAndroid Build Coastguard Worker     rect.addRect(SkIntToScalar(5), SkIntToScalar(5),
3646*c8dee2aaSAndroid Build Coastguard Worker                  SkIntToScalar(20), SkIntToScalar(20), SkPathDirection::kCW);
3647*c8dee2aaSAndroid Build Coastguard Worker 
3648*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix translate;
3649*c8dee2aaSAndroid Build Coastguard Worker     translate.setTranslate(SkIntToScalar(12), SkIntToScalar(12));
3650*c8dee2aaSAndroid Build Coastguard Worker 
3651*c8dee2aaSAndroid Build Coastguard Worker     // Although all the path concatenation related operations leave
3652*c8dee2aaSAndroid Build Coastguard Worker     // the path a circle, most mark it as a non-circle for simplicity
3653*c8dee2aaSAndroid Build Coastguard Worker 
3654*c8dee2aaSAndroid Build Coastguard Worker     // empty + circle (translate)
3655*c8dee2aaSAndroid Build Coastguard Worker     path = empty;
3656*c8dee2aaSAndroid Build Coastguard Worker     path.addPath(circle, translate);
3657*c8dee2aaSAndroid Build Coastguard Worker     check_for_circle(reporter, path, false, SkPathPriv::AsFirstDirection(kCircleDir));
3658*c8dee2aaSAndroid Build Coastguard Worker 
3659*c8dee2aaSAndroid Build Coastguard Worker     // circle + empty (translate)
3660*c8dee2aaSAndroid Build Coastguard Worker     path = circle;
3661*c8dee2aaSAndroid Build Coastguard Worker     path.addPath(empty, translate);
3662*c8dee2aaSAndroid Build Coastguard Worker 
3663*c8dee2aaSAndroid Build Coastguard Worker     check_for_circle(reporter, path, true, SkPathPriv::AsFirstDirection(kCircleDir));
3664*c8dee2aaSAndroid Build Coastguard Worker 
3665*c8dee2aaSAndroid Build Coastguard Worker     // test reverseAddPath
3666*c8dee2aaSAndroid Build Coastguard Worker     path = circle;
3667*c8dee2aaSAndroid Build Coastguard Worker     path.reverseAddPath(rect);
3668*c8dee2aaSAndroid Build Coastguard Worker     check_for_circle(reporter, path, false, SkPathPriv::AsFirstDirection(kCircleDirOpposite));
3669*c8dee2aaSAndroid Build Coastguard Worker }
3670*c8dee2aaSAndroid Build Coastguard Worker 
test_circle(skiatest::Reporter * reporter)3671*c8dee2aaSAndroid Build Coastguard Worker static void test_circle(skiatest::Reporter* reporter) {
3672*c8dee2aaSAndroid Build Coastguard Worker     test_circle_with_direction(reporter, SkPathDirection::kCW);
3673*c8dee2aaSAndroid Build Coastguard Worker     test_circle_with_direction(reporter, SkPathDirection::kCCW);
3674*c8dee2aaSAndroid Build Coastguard Worker 
3675*c8dee2aaSAndroid Build Coastguard Worker     // multiple addCircle()
3676*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
3677*c8dee2aaSAndroid Build Coastguard Worker     path.addCircle(0, 0, SkIntToScalar(10), SkPathDirection::kCW);
3678*c8dee2aaSAndroid Build Coastguard Worker     path.addCircle(0, 0, SkIntToScalar(20), SkPathDirection::kCW);
3679*c8dee2aaSAndroid Build Coastguard Worker     check_for_circle(reporter, path, false, SkPathFirstDirection::kCW);
3680*c8dee2aaSAndroid Build Coastguard Worker 
3681*c8dee2aaSAndroid Build Coastguard Worker     // some extra lineTo() would make isOval() fail
3682*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
3683*c8dee2aaSAndroid Build Coastguard Worker     path.addCircle(0, 0, SkIntToScalar(10), SkPathDirection::kCW);
3684*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0, 0);
3685*c8dee2aaSAndroid Build Coastguard Worker     check_for_circle(reporter, path, false, SkPathFirstDirection::kCW);
3686*c8dee2aaSAndroid Build Coastguard Worker 
3687*c8dee2aaSAndroid Build Coastguard Worker     // not back to the original point
3688*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
3689*c8dee2aaSAndroid Build Coastguard Worker     path.addCircle(0, 0, SkIntToScalar(10), SkPathDirection::kCW);
3690*c8dee2aaSAndroid Build Coastguard Worker     path.setLastPt(SkIntToScalar(5), SkIntToScalar(5));
3691*c8dee2aaSAndroid Build Coastguard Worker     check_for_circle(reporter, path, false, SkPathFirstDirection::kCW);
3692*c8dee2aaSAndroid Build Coastguard Worker 
3693*c8dee2aaSAndroid Build Coastguard Worker     test_circle_with_add_paths(reporter);
3694*c8dee2aaSAndroid Build Coastguard Worker 
3695*c8dee2aaSAndroid Build Coastguard Worker     // test negative radius
3696*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
3697*c8dee2aaSAndroid Build Coastguard Worker     path.addCircle(0, 0, -1, SkPathDirection::kCW);
3698*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isEmpty());
3699*c8dee2aaSAndroid Build Coastguard Worker }
3700*c8dee2aaSAndroid Build Coastguard Worker 
test_oval(skiatest::Reporter * reporter)3701*c8dee2aaSAndroid Build Coastguard Worker static void test_oval(skiatest::Reporter* reporter) {
3702*c8dee2aaSAndroid Build Coastguard Worker     SkRect rect;
3703*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix m;
3704*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
3705*c8dee2aaSAndroid Build Coastguard Worker     unsigned start = 0;
3706*c8dee2aaSAndroid Build Coastguard Worker     SkPathDirection dir = SkPathDirection::kCCW;
3707*c8dee2aaSAndroid Build Coastguard Worker 
3708*c8dee2aaSAndroid Build Coastguard Worker     rect = SkRect::MakeWH(SkIntToScalar(30), SkIntToScalar(50));
3709*c8dee2aaSAndroid Build Coastguard Worker     path.addOval(rect);
3710*c8dee2aaSAndroid Build Coastguard Worker 
3711*c8dee2aaSAndroid Build Coastguard Worker     // Defaults to dir = CW and start = 1
3712*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isOval(nullptr));
3713*c8dee2aaSAndroid Build Coastguard Worker 
3714*c8dee2aaSAndroid Build Coastguard Worker     m.setRotate(SkIntToScalar(90));
3715*c8dee2aaSAndroid Build Coastguard Worker     SkPath tmp;
3716*c8dee2aaSAndroid Build Coastguard Worker     path.transform(m, &tmp);
3717*c8dee2aaSAndroid Build Coastguard Worker     // an oval rotated 90 degrees is still an oval. The start index changes from 1 to 2. Direction
3718*c8dee2aaSAndroid Build Coastguard Worker     // is unchanged.
3719*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathPriv::IsOval(tmp, nullptr, &dir, &start));
3720*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, 2 == start);
3721*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathDirection::kCW == dir);
3722*c8dee2aaSAndroid Build Coastguard Worker 
3723*c8dee2aaSAndroid Build Coastguard Worker     m.reset();
3724*c8dee2aaSAndroid Build Coastguard Worker     m.setRotate(SkIntToScalar(30));
3725*c8dee2aaSAndroid Build Coastguard Worker     tmp.reset();
3726*c8dee2aaSAndroid Build Coastguard Worker     path.transform(m, &tmp);
3727*c8dee2aaSAndroid Build Coastguard Worker     // an oval rotated 30 degrees is not an oval anymore.
3728*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !tmp.isOval(nullptr));
3729*c8dee2aaSAndroid Build Coastguard Worker 
3730*c8dee2aaSAndroid Build Coastguard Worker     // since empty path being transformed.
3731*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
3732*c8dee2aaSAndroid Build Coastguard Worker     tmp.reset();
3733*c8dee2aaSAndroid Build Coastguard Worker     m.reset();
3734*c8dee2aaSAndroid Build Coastguard Worker     path.transform(m, &tmp);
3735*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !tmp.isOval(nullptr));
3736*c8dee2aaSAndroid Build Coastguard Worker 
3737*c8dee2aaSAndroid Build Coastguard Worker     // empty path is not an oval
3738*c8dee2aaSAndroid Build Coastguard Worker     tmp.reset();
3739*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !tmp.isOval(nullptr));
3740*c8dee2aaSAndroid Build Coastguard Worker 
3741*c8dee2aaSAndroid Build Coastguard Worker     // only has moveTo()s
3742*c8dee2aaSAndroid Build Coastguard Worker     tmp.reset();
3743*c8dee2aaSAndroid Build Coastguard Worker     tmp.moveTo(0, 0);
3744*c8dee2aaSAndroid Build Coastguard Worker     tmp.moveTo(SkIntToScalar(10), SkIntToScalar(10));
3745*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !tmp.isOval(nullptr));
3746*c8dee2aaSAndroid Build Coastguard Worker 
3747*c8dee2aaSAndroid Build Coastguard Worker     // mimic WebKit's calling convention,
3748*c8dee2aaSAndroid Build Coastguard Worker     // call moveTo() first and then call addOval()
3749*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
3750*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0);
3751*c8dee2aaSAndroid Build Coastguard Worker     path.addOval(rect);
3752*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isOval(nullptr));
3753*c8dee2aaSAndroid Build Coastguard Worker 
3754*c8dee2aaSAndroid Build Coastguard Worker     // copy path
3755*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
3756*c8dee2aaSAndroid Build Coastguard Worker     tmp.reset();
3757*c8dee2aaSAndroid Build Coastguard Worker     tmp.addOval(rect);
3758*c8dee2aaSAndroid Build Coastguard Worker     path = tmp;
3759*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathPriv::IsOval(path, nullptr, &dir, &start));
3760*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathDirection::kCW == dir);
3761*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, 1 == start);
3762*c8dee2aaSAndroid Build Coastguard Worker }
3763*c8dee2aaSAndroid Build Coastguard Worker 
test_empty(skiatest::Reporter * reporter,const SkPath & p)3764*c8dee2aaSAndroid Build Coastguard Worker static void test_empty(skiatest::Reporter* reporter, const SkPath& p) {
3765*c8dee2aaSAndroid Build Coastguard Worker     SkPath  empty;
3766*c8dee2aaSAndroid Build Coastguard Worker 
3767*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.isEmpty());
3768*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, 0 == p.countPoints());
3769*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, 0 == p.countVerbs());
3770*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
3771*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.isConvex());
3772*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.getFillType() == SkPathFillType::kWinding);
3773*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.isInverseFillType());
3774*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p == empty);
3775*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !(p != empty));
3776*c8dee2aaSAndroid Build Coastguard Worker }
3777*c8dee2aaSAndroid Build Coastguard Worker 
test_rrect_is_convex(skiatest::Reporter * reporter,SkPath * path,SkPathDirection dir)3778*c8dee2aaSAndroid Build Coastguard Worker static void test_rrect_is_convex(skiatest::Reporter* reporter, SkPath* path,
3779*c8dee2aaSAndroid Build Coastguard Worker                                  SkPathDirection dir) {
3780*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path->isConvex());
3781*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter,
3782*c8dee2aaSAndroid Build Coastguard Worker                     SkPathPriv::ComputeFirstDirection(*path) == SkPathPriv::AsFirstDirection(dir));
3783*c8dee2aaSAndroid Build Coastguard Worker     SkPathPriv::ForceComputeConvexity(*path);
3784*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path->isConvex());
3785*c8dee2aaSAndroid Build Coastguard Worker     path->reset();
3786*c8dee2aaSAndroid Build Coastguard Worker }
3787*c8dee2aaSAndroid Build Coastguard Worker 
test_rrect_convexity_is_unknown(skiatest::Reporter * reporter,SkPath * path,SkPathDirection dir)3788*c8dee2aaSAndroid Build Coastguard Worker static void test_rrect_convexity_is_unknown(skiatest::Reporter* reporter, SkPath* path,
3789*c8dee2aaSAndroid Build Coastguard Worker                                  SkPathDirection dir) {
3790*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path->isConvex());
3791*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter,
3792*c8dee2aaSAndroid Build Coastguard Worker                     SkPathPriv::ComputeFirstDirection(*path) == SkPathPriv::AsFirstDirection(dir));
3793*c8dee2aaSAndroid Build Coastguard Worker     SkPathPriv::ForceComputeConvexity(*path);
3794*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path->isConvex());
3795*c8dee2aaSAndroid Build Coastguard Worker     path->reset();
3796*c8dee2aaSAndroid Build Coastguard Worker }
3797*c8dee2aaSAndroid Build Coastguard Worker 
test_rrect(skiatest::Reporter * reporter)3798*c8dee2aaSAndroid Build Coastguard Worker static void test_rrect(skiatest::Reporter* reporter) {
3799*c8dee2aaSAndroid Build Coastguard Worker     SkPath p;
3800*c8dee2aaSAndroid Build Coastguard Worker     SkRRect rr;
3801*c8dee2aaSAndroid Build Coastguard Worker     SkVector radii[] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
3802*c8dee2aaSAndroid Build Coastguard Worker     SkRect r = {10, 20, 30, 40};
3803*c8dee2aaSAndroid Build Coastguard Worker     rr.setRectRadii(r, radii);
3804*c8dee2aaSAndroid Build Coastguard Worker     p.addRRect(rr);
3805*c8dee2aaSAndroid Build Coastguard Worker     test_rrect_is_convex(reporter, &p, SkPathDirection::kCW);
3806*c8dee2aaSAndroid Build Coastguard Worker     p.addRRect(rr, SkPathDirection::kCCW);
3807*c8dee2aaSAndroid Build Coastguard Worker     test_rrect_is_convex(reporter, &p, SkPathDirection::kCCW);
3808*c8dee2aaSAndroid Build Coastguard Worker     p.addRoundRect(r, &radii[0].fX);
3809*c8dee2aaSAndroid Build Coastguard Worker     test_rrect_is_convex(reporter, &p, SkPathDirection::kCW);
3810*c8dee2aaSAndroid Build Coastguard Worker     p.addRoundRect(r, &radii[0].fX, SkPathDirection::kCCW);
3811*c8dee2aaSAndroid Build Coastguard Worker     test_rrect_is_convex(reporter, &p, SkPathDirection::kCCW);
3812*c8dee2aaSAndroid Build Coastguard Worker     p.addRoundRect(r, radii[1].fX, radii[1].fY);
3813*c8dee2aaSAndroid Build Coastguard Worker     test_rrect_is_convex(reporter, &p, SkPathDirection::kCW);
3814*c8dee2aaSAndroid Build Coastguard Worker     p.addRoundRect(r, radii[1].fX, radii[1].fY, SkPathDirection::kCCW);
3815*c8dee2aaSAndroid Build Coastguard Worker     test_rrect_is_convex(reporter, &p, SkPathDirection::kCCW);
3816*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < std::size(radii); ++i) {
3817*c8dee2aaSAndroid Build Coastguard Worker         SkVector save = radii[i];
3818*c8dee2aaSAndroid Build Coastguard Worker         radii[i].set(0, 0);
3819*c8dee2aaSAndroid Build Coastguard Worker         rr.setRectRadii(r, radii);
3820*c8dee2aaSAndroid Build Coastguard Worker         p.addRRect(rr);
3821*c8dee2aaSAndroid Build Coastguard Worker         test_rrect_is_convex(reporter, &p, SkPathDirection::kCW);
3822*c8dee2aaSAndroid Build Coastguard Worker         radii[i] = save;
3823*c8dee2aaSAndroid Build Coastguard Worker     }
3824*c8dee2aaSAndroid Build Coastguard Worker     p.addRoundRect(r, 0, 0);
3825*c8dee2aaSAndroid Build Coastguard Worker     SkRect returnedRect;
3826*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.isRect(&returnedRect));
3827*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, returnedRect == r);
3828*c8dee2aaSAndroid Build Coastguard Worker     test_rrect_is_convex(reporter, &p, SkPathDirection::kCW);
3829*c8dee2aaSAndroid Build Coastguard Worker     SkVector zeroRadii[] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}};
3830*c8dee2aaSAndroid Build Coastguard Worker     rr.setRectRadii(r, zeroRadii);
3831*c8dee2aaSAndroid Build Coastguard Worker     p.addRRect(rr);
3832*c8dee2aaSAndroid Build Coastguard Worker     bool closed;
3833*c8dee2aaSAndroid Build Coastguard Worker     SkPathDirection dir;
3834*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.isRect(nullptr, &closed, &dir));
3835*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, closed);
3836*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathDirection::kCW == dir);
3837*c8dee2aaSAndroid Build Coastguard Worker     test_rrect_is_convex(reporter, &p, SkPathDirection::kCW);
3838*c8dee2aaSAndroid Build Coastguard Worker     p.addRRect(rr, SkPathDirection::kCW);
3839*c8dee2aaSAndroid Build Coastguard Worker     p.addRRect(rr, SkPathDirection::kCW);
3840*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.isConvex());
3841*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
3842*c8dee2aaSAndroid Build Coastguard Worker     p.addRRect(rr, SkPathDirection::kCCW);
3843*c8dee2aaSAndroid Build Coastguard Worker     p.addRRect(rr, SkPathDirection::kCCW);
3844*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.isConvex());
3845*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
3846*c8dee2aaSAndroid Build Coastguard Worker     SkRect emptyR = {10, 20, 10, 30};
3847*c8dee2aaSAndroid Build Coastguard Worker     rr.setRectRadii(emptyR, radii);
3848*c8dee2aaSAndroid Build Coastguard Worker     p.addRRect(rr);
3849*c8dee2aaSAndroid Build Coastguard Worker     // The round rect is "empty" in that it has no fill area. However,
3850*c8dee2aaSAndroid Build Coastguard Worker     // the path isn't "empty" in that it should have verbs and points.
3851*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.isEmpty());
3852*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
3853*c8dee2aaSAndroid Build Coastguard Worker     SkRect largeR = {0, 0, SK_ScalarMax, SK_ScalarMax};
3854*c8dee2aaSAndroid Build Coastguard Worker     rr.setRectRadii(largeR, radii);
3855*c8dee2aaSAndroid Build Coastguard Worker     p.addRRect(rr);
3856*c8dee2aaSAndroid Build Coastguard Worker     test_rrect_convexity_is_unknown(reporter, &p, SkPathDirection::kCW);
3857*c8dee2aaSAndroid Build Coastguard Worker 
3858*c8dee2aaSAndroid Build Coastguard Worker     // we check for non-finites
3859*c8dee2aaSAndroid Build Coastguard Worker     SkRect infR = {0, 0, SK_ScalarMax, SK_ScalarInfinity};
3860*c8dee2aaSAndroid Build Coastguard Worker     rr.setRectRadii(infR, radii);
3861*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rr.isEmpty());
3862*c8dee2aaSAndroid Build Coastguard Worker }
3863*c8dee2aaSAndroid Build Coastguard Worker 
test_arc(skiatest::Reporter * reporter)3864*c8dee2aaSAndroid Build Coastguard Worker static void test_arc(skiatest::Reporter* reporter) {
3865*c8dee2aaSAndroid Build Coastguard Worker     SkPath p;
3866*c8dee2aaSAndroid Build Coastguard Worker     SkRect emptyOval = {10, 20, 30, 20};
3867*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, emptyOval.isEmpty());
3868*c8dee2aaSAndroid Build Coastguard Worker     p.addArc(emptyOval, 1, 2);
3869*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.isEmpty());
3870*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
3871*c8dee2aaSAndroid Build Coastguard Worker     SkRect oval = {10, 20, 30, 40};
3872*c8dee2aaSAndroid Build Coastguard Worker     p.addArc(oval, 1, 0);
3873*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.isEmpty());
3874*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
3875*c8dee2aaSAndroid Build Coastguard Worker     SkPath cwOval;
3876*c8dee2aaSAndroid Build Coastguard Worker     cwOval.addOval(oval);
3877*c8dee2aaSAndroid Build Coastguard Worker     p.addArc(oval, 0, 360);
3878*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p == cwOval);
3879*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
3880*c8dee2aaSAndroid Build Coastguard Worker     SkPath ccwOval;
3881*c8dee2aaSAndroid Build Coastguard Worker     ccwOval.addOval(oval, SkPathDirection::kCCW);
3882*c8dee2aaSAndroid Build Coastguard Worker     p.addArc(oval, 0, -360);
3883*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p == ccwOval);
3884*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
3885*c8dee2aaSAndroid Build Coastguard Worker     p.addArc(oval, 1, 180);
3886*c8dee2aaSAndroid Build Coastguard Worker     // diagonal colinear points make arc convex
3887*c8dee2aaSAndroid Build Coastguard Worker     // TODO: one way to keep it concave would be to introduce interpolated on curve points
3888*c8dee2aaSAndroid Build Coastguard Worker     // between control points and computing the on curve point at scan conversion time
3889*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.isConvex());
3890*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathPriv::ComputeFirstDirection(p) == SkPathFirstDirection::kCW);
3891*c8dee2aaSAndroid Build Coastguard Worker     SkPathPriv::ForceComputeConvexity(p);
3892*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.isConvex());
3893*c8dee2aaSAndroid Build Coastguard Worker }
3894*c8dee2aaSAndroid Build Coastguard Worker 
oval_start_index_to_angle(unsigned start)3895*c8dee2aaSAndroid Build Coastguard Worker static inline SkScalar oval_start_index_to_angle(unsigned start) {
3896*c8dee2aaSAndroid Build Coastguard Worker     switch (start) {
3897*c8dee2aaSAndroid Build Coastguard Worker         case 0:
3898*c8dee2aaSAndroid Build Coastguard Worker             return 270.f;
3899*c8dee2aaSAndroid Build Coastguard Worker         case 1:
3900*c8dee2aaSAndroid Build Coastguard Worker             return 0.f;
3901*c8dee2aaSAndroid Build Coastguard Worker         case 2:
3902*c8dee2aaSAndroid Build Coastguard Worker             return 90.f;
3903*c8dee2aaSAndroid Build Coastguard Worker         case 3:
3904*c8dee2aaSAndroid Build Coastguard Worker             return 180.f;
3905*c8dee2aaSAndroid Build Coastguard Worker         default:
3906*c8dee2aaSAndroid Build Coastguard Worker             return -1.f;
3907*c8dee2aaSAndroid Build Coastguard Worker     }
3908*c8dee2aaSAndroid Build Coastguard Worker }
3909*c8dee2aaSAndroid Build Coastguard Worker 
canonical_start_angle(float angle)3910*c8dee2aaSAndroid Build Coastguard Worker static inline SkScalar canonical_start_angle(float angle) {
3911*c8dee2aaSAndroid Build Coastguard Worker     while (angle < 0.f) {
3912*c8dee2aaSAndroid Build Coastguard Worker         angle += 360.f;
3913*c8dee2aaSAndroid Build Coastguard Worker     }
3914*c8dee2aaSAndroid Build Coastguard Worker     while (angle >= 360.f) {
3915*c8dee2aaSAndroid Build Coastguard Worker         angle -= 360.f;
3916*c8dee2aaSAndroid Build Coastguard Worker     }
3917*c8dee2aaSAndroid Build Coastguard Worker     return angle;
3918*c8dee2aaSAndroid Build Coastguard Worker }
3919*c8dee2aaSAndroid Build Coastguard Worker 
check_oval_arc(skiatest::Reporter * reporter,SkScalar start,SkScalar sweep,const SkPath & path)3920*c8dee2aaSAndroid Build Coastguard Worker static void check_oval_arc(skiatest::Reporter* reporter, SkScalar start, SkScalar sweep,
3921*c8dee2aaSAndroid Build Coastguard Worker                            const SkPath& path) {
3922*c8dee2aaSAndroid Build Coastguard Worker     SkRect r = SkRect::MakeEmpty();
3923*c8dee2aaSAndroid Build Coastguard Worker     SkPathDirection d = SkPathDirection::kCCW;
3924*c8dee2aaSAndroid Build Coastguard Worker     unsigned s = ~0U;
3925*c8dee2aaSAndroid Build Coastguard Worker     bool isOval = SkPathPriv::IsOval(path, &r, &d, &s);
3926*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, isOval);
3927*c8dee2aaSAndroid Build Coastguard Worker     SkPath recreatedPath;
3928*c8dee2aaSAndroid Build Coastguard Worker     recreatedPath.addOval(r, d, s);
3929*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path == recreatedPath);
3930*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, oval_start_index_to_angle(s) == canonical_start_angle(start));
3931*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, (SkPathDirection::kCW == d) == (sweep > 0.f));
3932*c8dee2aaSAndroid Build Coastguard Worker }
3933*c8dee2aaSAndroid Build Coastguard Worker 
test_arc_ovals(skiatest::Reporter * reporter)3934*c8dee2aaSAndroid Build Coastguard Worker static void test_arc_ovals(skiatest::Reporter* reporter) {
3935*c8dee2aaSAndroid Build Coastguard Worker     SkRect oval = SkRect::MakeWH(10, 20);
3936*c8dee2aaSAndroid Build Coastguard Worker     for (SkScalar sweep : {-720.f, -540.f, -360.f, 360.f, 432.f, 720.f}) {
3937*c8dee2aaSAndroid Build Coastguard Worker         for (SkScalar start = -360.f; start <= 360.f; start += 1.f) {
3938*c8dee2aaSAndroid Build Coastguard Worker             SkPath path;
3939*c8dee2aaSAndroid Build Coastguard Worker             path.addArc(oval, start, sweep);
3940*c8dee2aaSAndroid Build Coastguard Worker             // SkPath's interfaces for inserting and extracting ovals only allow contours
3941*c8dee2aaSAndroid Build Coastguard Worker             // to start at multiples of 90 degrees.
3942*c8dee2aaSAndroid Build Coastguard Worker             if (std::fmod(start, 90.f) == 0) {
3943*c8dee2aaSAndroid Build Coastguard Worker                 check_oval_arc(reporter, start, sweep, path);
3944*c8dee2aaSAndroid Build Coastguard Worker             } else {
3945*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, !path.isOval(nullptr));
3946*c8dee2aaSAndroid Build Coastguard Worker             }
3947*c8dee2aaSAndroid Build Coastguard Worker         }
3948*c8dee2aaSAndroid Build Coastguard Worker         // Test start angles that are nearly at valid oval start angles.
3949*c8dee2aaSAndroid Build Coastguard Worker         for (float start : {-180.f, -90.f, 90.f, 180.f}) {
3950*c8dee2aaSAndroid Build Coastguard Worker             for (float delta : {-SK_ScalarNearlyZero, SK_ScalarNearlyZero}) {
3951*c8dee2aaSAndroid Build Coastguard Worker                 SkPath path;
3952*c8dee2aaSAndroid Build Coastguard Worker                 path.addArc(oval, start + delta, sweep);
3953*c8dee2aaSAndroid Build Coastguard Worker                 check_oval_arc(reporter, start, sweep, path);
3954*c8dee2aaSAndroid Build Coastguard Worker             }
3955*c8dee2aaSAndroid Build Coastguard Worker         }
3956*c8dee2aaSAndroid Build Coastguard Worker     }
3957*c8dee2aaSAndroid Build Coastguard Worker }
3958*c8dee2aaSAndroid Build Coastguard Worker 
check_move(skiatest::Reporter * reporter,SkPathPriv::RangeIter * iter,SkScalar x0,SkScalar y0)3959*c8dee2aaSAndroid Build Coastguard Worker static void check_move(skiatest::Reporter* reporter, SkPathPriv::RangeIter* iter,
3960*c8dee2aaSAndroid Build Coastguard Worker                        SkScalar x0, SkScalar y0) {
3961*c8dee2aaSAndroid Build Coastguard Worker     auto [v, pts, w] = *(*iter)++;
3962*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, v == SkPathVerb::kMove);
3963*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pts[0].fX == x0);
3964*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pts[0].fY == y0);
3965*c8dee2aaSAndroid Build Coastguard Worker }
3966*c8dee2aaSAndroid Build Coastguard Worker 
check_line(skiatest::Reporter * reporter,SkPathPriv::RangeIter * iter,SkScalar x1,SkScalar y1)3967*c8dee2aaSAndroid Build Coastguard Worker static void check_line(skiatest::Reporter* reporter, SkPathPriv::RangeIter* iter,
3968*c8dee2aaSAndroid Build Coastguard Worker                        SkScalar x1, SkScalar y1) {
3969*c8dee2aaSAndroid Build Coastguard Worker     auto [v, pts, w] = *(*iter)++;
3970*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, v == SkPathVerb::kLine);
3971*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pts[1].fX == x1);
3972*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pts[1].fY == y1);
3973*c8dee2aaSAndroid Build Coastguard Worker }
3974*c8dee2aaSAndroid Build Coastguard Worker 
check_quad(skiatest::Reporter * reporter,SkPathPriv::RangeIter * iter,SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2)3975*c8dee2aaSAndroid Build Coastguard Worker static void check_quad(skiatest::Reporter* reporter, SkPathPriv::RangeIter* iter,
3976*c8dee2aaSAndroid Build Coastguard Worker                        SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
3977*c8dee2aaSAndroid Build Coastguard Worker     auto [v, pts, w] = *(*iter)++;
3978*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, v == SkPathVerb::kQuad);
3979*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pts[1].fX == x1);
3980*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pts[1].fY == y1);
3981*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pts[2].fX == x2);
3982*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pts[2].fY == y2);
3983*c8dee2aaSAndroid Build Coastguard Worker }
3984*c8dee2aaSAndroid Build Coastguard Worker 
check_close(skiatest::Reporter * reporter,SkPathPriv::RangeIter * iter)3985*c8dee2aaSAndroid Build Coastguard Worker static void check_close(skiatest::Reporter* reporter, SkPathPriv::RangeIter* iter) {
3986*c8dee2aaSAndroid Build Coastguard Worker     auto [v, pts, w] = *(*iter)++;
3987*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, v == SkPathVerb::kClose);
3988*c8dee2aaSAndroid Build Coastguard Worker }
3989*c8dee2aaSAndroid Build Coastguard Worker 
check_done(skiatest::Reporter * reporter,SkPath * p,SkPathPriv::RangeIter * iter)3990*c8dee2aaSAndroid Build Coastguard Worker static void check_done(skiatest::Reporter* reporter, SkPath* p, SkPathPriv::RangeIter* iter) {
3991*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, *iter == SkPathPriv::Iterate(*p).end());
3992*c8dee2aaSAndroid Build Coastguard Worker }
3993*c8dee2aaSAndroid Build Coastguard Worker 
check_done_and_reset(skiatest::Reporter * reporter,SkPath * p,SkPathPriv::RangeIter * iter)3994*c8dee2aaSAndroid Build Coastguard Worker static void check_done_and_reset(skiatest::Reporter* reporter, SkPath* p,
3995*c8dee2aaSAndroid Build Coastguard Worker                                  SkPathPriv::RangeIter* iter) {
3996*c8dee2aaSAndroid Build Coastguard Worker     check_done(reporter, p, iter);
3997*c8dee2aaSAndroid Build Coastguard Worker     p->reset();
3998*c8dee2aaSAndroid Build Coastguard Worker }
3999*c8dee2aaSAndroid Build Coastguard Worker 
check_path_is_move_and_reset(skiatest::Reporter * reporter,SkPath * p,SkScalar x0,SkScalar y0)4000*c8dee2aaSAndroid Build Coastguard Worker static void check_path_is_move_and_reset(skiatest::Reporter* reporter, SkPath* p,
4001*c8dee2aaSAndroid Build Coastguard Worker                                          SkScalar x0, SkScalar y0) {
4002*c8dee2aaSAndroid Build Coastguard Worker     SkPathPriv::RangeIter iter = SkPathPriv::Iterate(*p).begin();
4003*c8dee2aaSAndroid Build Coastguard Worker     check_move(reporter, &iter, x0, y0);
4004*c8dee2aaSAndroid Build Coastguard Worker     check_done_and_reset(reporter, p, &iter);
4005*c8dee2aaSAndroid Build Coastguard Worker }
4006*c8dee2aaSAndroid Build Coastguard Worker 
check_path_is_line_and_reset(skiatest::Reporter * reporter,SkPath * p,SkScalar x1,SkScalar y1)4007*c8dee2aaSAndroid Build Coastguard Worker static void check_path_is_line_and_reset(skiatest::Reporter* reporter, SkPath* p,
4008*c8dee2aaSAndroid Build Coastguard Worker                                          SkScalar x1, SkScalar y1) {
4009*c8dee2aaSAndroid Build Coastguard Worker     SkPathPriv::RangeIter iter = SkPathPriv::Iterate(*p).begin();
4010*c8dee2aaSAndroid Build Coastguard Worker     check_move(reporter, &iter, 0, 0);
4011*c8dee2aaSAndroid Build Coastguard Worker     check_line(reporter, &iter, x1, y1);
4012*c8dee2aaSAndroid Build Coastguard Worker     check_done_and_reset(reporter, p, &iter);
4013*c8dee2aaSAndroid Build Coastguard Worker }
4014*c8dee2aaSAndroid Build Coastguard Worker 
check_path_is_line(skiatest::Reporter * reporter,SkPath * p,SkScalar x1,SkScalar y1)4015*c8dee2aaSAndroid Build Coastguard Worker static void check_path_is_line(skiatest::Reporter* reporter, SkPath* p,
4016*c8dee2aaSAndroid Build Coastguard Worker                                          SkScalar x1, SkScalar y1) {
4017*c8dee2aaSAndroid Build Coastguard Worker     SkPathPriv::RangeIter iter = SkPathPriv::Iterate(*p).begin();
4018*c8dee2aaSAndroid Build Coastguard Worker     check_move(reporter, &iter, 0, 0);
4019*c8dee2aaSAndroid Build Coastguard Worker     check_line(reporter, &iter, x1, y1);
4020*c8dee2aaSAndroid Build Coastguard Worker     check_done(reporter, p, &iter);
4021*c8dee2aaSAndroid Build Coastguard Worker }
4022*c8dee2aaSAndroid Build Coastguard Worker 
check_path_is_line_pair_and_reset(skiatest::Reporter * reporter,SkPath * p,SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2)4023*c8dee2aaSAndroid Build Coastguard Worker static void check_path_is_line_pair_and_reset(skiatest::Reporter* reporter, SkPath* p,
4024*c8dee2aaSAndroid Build Coastguard Worker                                     SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
4025*c8dee2aaSAndroid Build Coastguard Worker     SkPathPriv::RangeIter iter = SkPathPriv::Iterate(*p).begin();
4026*c8dee2aaSAndroid Build Coastguard Worker     check_move(reporter, &iter, 0, 0);
4027*c8dee2aaSAndroid Build Coastguard Worker     check_line(reporter, &iter, x1, y1);
4028*c8dee2aaSAndroid Build Coastguard Worker     check_line(reporter, &iter, x2, y2);
4029*c8dee2aaSAndroid Build Coastguard Worker     check_done_and_reset(reporter, p, &iter);
4030*c8dee2aaSAndroid Build Coastguard Worker }
4031*c8dee2aaSAndroid Build Coastguard Worker 
check_path_is_quad_and_reset(skiatest::Reporter * reporter,SkPath * p,SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2)4032*c8dee2aaSAndroid Build Coastguard Worker static void check_path_is_quad_and_reset(skiatest::Reporter* reporter, SkPath* p,
4033*c8dee2aaSAndroid Build Coastguard Worker                                     SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
4034*c8dee2aaSAndroid Build Coastguard Worker     SkPathPriv::RangeIter iter = SkPathPriv::Iterate(*p).begin();
4035*c8dee2aaSAndroid Build Coastguard Worker     check_move(reporter, &iter, 0, 0);
4036*c8dee2aaSAndroid Build Coastguard Worker     check_quad(reporter, &iter, x1, y1, x2, y2);
4037*c8dee2aaSAndroid Build Coastguard Worker     check_done_and_reset(reporter, p, &iter);
4038*c8dee2aaSAndroid Build Coastguard Worker }
4039*c8dee2aaSAndroid Build Coastguard Worker 
nearly_equal(const SkRect & a,const SkRect & b)4040*c8dee2aaSAndroid Build Coastguard Worker static bool nearly_equal(const SkRect& a, const SkRect& b) {
4041*c8dee2aaSAndroid Build Coastguard Worker     return  SkScalarNearlyEqual(a.fLeft, b.fLeft) &&
4042*c8dee2aaSAndroid Build Coastguard Worker             SkScalarNearlyEqual(a.fTop, b.fTop) &&
4043*c8dee2aaSAndroid Build Coastguard Worker             SkScalarNearlyEqual(a.fRight, b.fRight) &&
4044*c8dee2aaSAndroid Build Coastguard Worker             SkScalarNearlyEqual(a.fBottom, b.fBottom);
4045*c8dee2aaSAndroid Build Coastguard Worker }
4046*c8dee2aaSAndroid Build Coastguard Worker 
test_rMoveTo(skiatest::Reporter * reporter)4047*c8dee2aaSAndroid Build Coastguard Worker static void test_rMoveTo(skiatest::Reporter* reporter) {
4048*c8dee2aaSAndroid Build Coastguard Worker     SkPath p;
4049*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(10, 11);
4050*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(20, 21);
4051*c8dee2aaSAndroid Build Coastguard Worker     p.close();
4052*c8dee2aaSAndroid Build Coastguard Worker     p.rMoveTo(30, 31);
4053*c8dee2aaSAndroid Build Coastguard Worker     SkPathPriv::RangeIter iter = SkPathPriv::Iterate(p).begin();
4054*c8dee2aaSAndroid Build Coastguard Worker     check_move(reporter, &iter, 10, 11);
4055*c8dee2aaSAndroid Build Coastguard Worker     check_line(reporter, &iter, 20, 21);
4056*c8dee2aaSAndroid Build Coastguard Worker     check_close(reporter, &iter);
4057*c8dee2aaSAndroid Build Coastguard Worker     check_move(reporter, &iter, 10 + 30, 11 + 31);
4058*c8dee2aaSAndroid Build Coastguard Worker     check_done_and_reset(reporter, &p, &iter);
4059*c8dee2aaSAndroid Build Coastguard Worker 
4060*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(10, 11);
4061*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(20, 21);
4062*c8dee2aaSAndroid Build Coastguard Worker     p.rMoveTo(30, 31);
4063*c8dee2aaSAndroid Build Coastguard Worker     iter = SkPathPriv::Iterate(p).begin();
4064*c8dee2aaSAndroid Build Coastguard Worker     check_move(reporter, &iter, 10, 11);
4065*c8dee2aaSAndroid Build Coastguard Worker     check_line(reporter, &iter, 20, 21);
4066*c8dee2aaSAndroid Build Coastguard Worker     check_move(reporter, &iter, 20 + 30, 21 + 31);
4067*c8dee2aaSAndroid Build Coastguard Worker     check_done_and_reset(reporter, &p, &iter);
4068*c8dee2aaSAndroid Build Coastguard Worker 
4069*c8dee2aaSAndroid Build Coastguard Worker     p.rMoveTo(30, 31);
4070*c8dee2aaSAndroid Build Coastguard Worker     iter = SkPathPriv::Iterate(p).begin();
4071*c8dee2aaSAndroid Build Coastguard Worker     check_move(reporter, &iter, 30, 31);
4072*c8dee2aaSAndroid Build Coastguard Worker     check_done_and_reset(reporter, &p, &iter);
4073*c8dee2aaSAndroid Build Coastguard Worker }
4074*c8dee2aaSAndroid Build Coastguard Worker 
test_arcTo(skiatest::Reporter * reporter)4075*c8dee2aaSAndroid Build Coastguard Worker static void test_arcTo(skiatest::Reporter* reporter) {
4076*c8dee2aaSAndroid Build Coastguard Worker     SkPath p;
4077*c8dee2aaSAndroid Build Coastguard Worker     p.arcTo(0, 0, 1, 2, 1);
4078*c8dee2aaSAndroid Build Coastguard Worker     check_path_is_line_and_reset(reporter, &p, 0, 0);
4079*c8dee2aaSAndroid Build Coastguard Worker     p.arcTo(1, 2, 1, 2, 1);
4080*c8dee2aaSAndroid Build Coastguard Worker     check_path_is_line_and_reset(reporter, &p, 1, 2);
4081*c8dee2aaSAndroid Build Coastguard Worker     p.arcTo(1, 2, 3, 4, 0);
4082*c8dee2aaSAndroid Build Coastguard Worker     check_path_is_line_and_reset(reporter, &p, 1, 2);
4083*c8dee2aaSAndroid Build Coastguard Worker     p.arcTo(1, 2, 0, 0, 1);
4084*c8dee2aaSAndroid Build Coastguard Worker     check_path_is_line_and_reset(reporter, &p, 1, 2);
4085*c8dee2aaSAndroid Build Coastguard Worker     p.arcTo(1, 0, 1, 1, 1);
4086*c8dee2aaSAndroid Build Coastguard Worker     SkPoint pt;
4087*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.getLastPt(&pt) && pt.fX == 1 && pt.fY == 1);
4088*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4089*c8dee2aaSAndroid Build Coastguard Worker     p.arcTo(1, 0, 1, -1, 1);
4090*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.getLastPt(&pt) && pt.fX == 1 && pt.fY == -1);
4091*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4092*c8dee2aaSAndroid Build Coastguard Worker     SkRect oval = {1, 2, 3, 4};
4093*c8dee2aaSAndroid Build Coastguard Worker     p.arcTo(oval, 0, 0, true);
4094*c8dee2aaSAndroid Build Coastguard Worker     check_path_is_move_and_reset(reporter, &p, oval.fRight, oval.centerY());
4095*c8dee2aaSAndroid Build Coastguard Worker     p.arcTo(oval, 0, 0, false);
4096*c8dee2aaSAndroid Build Coastguard Worker     check_path_is_move_and_reset(reporter, &p, oval.fRight, oval.centerY());
4097*c8dee2aaSAndroid Build Coastguard Worker     p.arcTo(oval, 360, 0, true);
4098*c8dee2aaSAndroid Build Coastguard Worker     check_path_is_move_and_reset(reporter, &p, oval.fRight, oval.centerY());
4099*c8dee2aaSAndroid Build Coastguard Worker     p.arcTo(oval, 360, 0, false);
4100*c8dee2aaSAndroid Build Coastguard Worker     check_path_is_move_and_reset(reporter, &p, oval.fRight, oval.centerY());
4101*c8dee2aaSAndroid Build Coastguard Worker 
4102*c8dee2aaSAndroid Build Coastguard Worker     for (float sweep = 359, delta = 0.5f; sweep != (float) (sweep + delta); ) {
4103*c8dee2aaSAndroid Build Coastguard Worker         p.arcTo(oval, 0, sweep, false);
4104*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, nearly_equal(p.getBounds(), oval));
4105*c8dee2aaSAndroid Build Coastguard Worker         sweep += delta;
4106*c8dee2aaSAndroid Build Coastguard Worker         delta /= 2;
4107*c8dee2aaSAndroid Build Coastguard Worker     }
4108*c8dee2aaSAndroid Build Coastguard Worker     for (float sweep = 361, delta = 0.5f; sweep != (float) (sweep - delta);) {
4109*c8dee2aaSAndroid Build Coastguard Worker         p.arcTo(oval, 0, sweep, false);
4110*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, nearly_equal(p.getBounds(), oval));
4111*c8dee2aaSAndroid Build Coastguard Worker         sweep -= delta;
4112*c8dee2aaSAndroid Build Coastguard Worker         delta /= 2;
4113*c8dee2aaSAndroid Build Coastguard Worker     }
4114*c8dee2aaSAndroid Build Coastguard Worker     SkRect noOvalWidth = {1, 2, 0, 3};
4115*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4116*c8dee2aaSAndroid Build Coastguard Worker     p.arcTo(noOvalWidth, 0, 360, false);
4117*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.isEmpty());
4118*c8dee2aaSAndroid Build Coastguard Worker 
4119*c8dee2aaSAndroid Build Coastguard Worker     SkRect noOvalHeight = {1, 2, 3, 1};
4120*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4121*c8dee2aaSAndroid Build Coastguard Worker     p.arcTo(noOvalHeight, 0, 360, false);
4122*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.isEmpty());
4123*c8dee2aaSAndroid Build Coastguard Worker 
4124*c8dee2aaSAndroid Build Coastguard Worker     // Inspired by http://code.google.com/p/chromium/issues/detail?id=1001768
4125*c8dee2aaSAndroid Build Coastguard Worker     {
4126*c8dee2aaSAndroid Build Coastguard Worker       p.reset();
4127*c8dee2aaSAndroid Build Coastguard Worker       p.moveTo(216, 216);
4128*c8dee2aaSAndroid Build Coastguard Worker       p.arcTo(216, 108, 0, SkPath::ArcSize::kLarge_ArcSize, SkPathDirection::kCW, 216, 0);
4129*c8dee2aaSAndroid Build Coastguard Worker       p.arcTo(270, 135, 0, SkPath::ArcSize::kLarge_ArcSize, SkPathDirection::kCCW, 216, 216);
4130*c8dee2aaSAndroid Build Coastguard Worker 
4131*c8dee2aaSAndroid Build Coastguard Worker       // The 'arcTo' call should end up exactly at the starting location.
4132*c8dee2aaSAndroid Build Coastguard Worker       int n = p.countPoints();
4133*c8dee2aaSAndroid Build Coastguard Worker       REPORTER_ASSERT(reporter, p.getPoint(0) == p.getPoint(n - 1));
4134*c8dee2aaSAndroid Build Coastguard Worker     }
4135*c8dee2aaSAndroid Build Coastguard Worker 
4136*c8dee2aaSAndroid Build Coastguard Worker     // This test, if improperly handled, can create an infinite loop in angles_to_unit_vectors
4137*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4138*c8dee2aaSAndroid Build Coastguard Worker     p.arcTo(SkRect::MakeXYWH(0, 0, 10, 10), -2.61488527e+33f, 359.992157f, false);
4139*c8dee2aaSAndroid Build Coastguard Worker }
4140*c8dee2aaSAndroid Build Coastguard Worker 
test_addPath(skiatest::Reporter * reporter)4141*c8dee2aaSAndroid Build Coastguard Worker static void test_addPath(skiatest::Reporter* reporter) {
4142*c8dee2aaSAndroid Build Coastguard Worker     SkPath p, q;
4143*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(1, 2);
4144*c8dee2aaSAndroid Build Coastguard Worker     q.moveTo(4, 4);
4145*c8dee2aaSAndroid Build Coastguard Worker     q.lineTo(7, 8);
4146*c8dee2aaSAndroid Build Coastguard Worker     q.conicTo(8, 7, 6, 5, 0.5f);
4147*c8dee2aaSAndroid Build Coastguard Worker     q.quadTo(6, 7, 8, 6);
4148*c8dee2aaSAndroid Build Coastguard Worker     q.cubicTo(5, 6, 7, 8, 7, 5);
4149*c8dee2aaSAndroid Build Coastguard Worker     q.close();
4150*c8dee2aaSAndroid Build Coastguard Worker     p.addPath(q, -4, -4);
4151*c8dee2aaSAndroid Build Coastguard Worker     SkRect expected = {0, 0, 4, 4};
4152*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.getBounds() == expected);
4153*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4154*c8dee2aaSAndroid Build Coastguard Worker     p.reverseAddPath(q);
4155*c8dee2aaSAndroid Build Coastguard Worker     SkRect reverseExpected = {4, 4, 8, 8};
4156*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.getBounds() == reverseExpected);
4157*c8dee2aaSAndroid Build Coastguard Worker }
4158*c8dee2aaSAndroid Build Coastguard Worker 
test_addPathMode(skiatest::Reporter * reporter,bool explicitMoveTo,bool extend)4159*c8dee2aaSAndroid Build Coastguard Worker static void test_addPathMode(skiatest::Reporter* reporter, bool explicitMoveTo, bool extend) {
4160*c8dee2aaSAndroid Build Coastguard Worker     SkPath p, q;
4161*c8dee2aaSAndroid Build Coastguard Worker     if (explicitMoveTo) {
4162*c8dee2aaSAndroid Build Coastguard Worker         p.moveTo(1, 1);
4163*c8dee2aaSAndroid Build Coastguard Worker     }
4164*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(1, 2);
4165*c8dee2aaSAndroid Build Coastguard Worker     if (explicitMoveTo) {
4166*c8dee2aaSAndroid Build Coastguard Worker         q.moveTo(2, 1);
4167*c8dee2aaSAndroid Build Coastguard Worker     }
4168*c8dee2aaSAndroid Build Coastguard Worker     q.lineTo(2, 2);
4169*c8dee2aaSAndroid Build Coastguard Worker     p.addPath(q, extend ? SkPath::kExtend_AddPathMode : SkPath::kAppend_AddPathMode);
4170*c8dee2aaSAndroid Build Coastguard Worker     uint8_t verbs[4];
4171*c8dee2aaSAndroid Build Coastguard Worker     int verbcount = p.getVerbs(verbs, 4);
4172*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, verbcount == 4);
4173*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, verbs[0] == SkPath::kMove_Verb);
4174*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, verbs[1] == SkPath::kLine_Verb);
4175*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, verbs[2] == (extend ? SkPath::kLine_Verb : SkPath::kMove_Verb));
4176*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, verbs[3] == SkPath::kLine_Verb);
4177*c8dee2aaSAndroid Build Coastguard Worker }
4178*c8dee2aaSAndroid Build Coastguard Worker 
test_extendClosedPath(skiatest::Reporter * reporter)4179*c8dee2aaSAndroid Build Coastguard Worker static void test_extendClosedPath(skiatest::Reporter* reporter) {
4180*c8dee2aaSAndroid Build Coastguard Worker     SkPath p, q;
4181*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(1, 1);
4182*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(1, 2);
4183*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(2, 2);
4184*c8dee2aaSAndroid Build Coastguard Worker     p.close();
4185*c8dee2aaSAndroid Build Coastguard Worker     q.moveTo(2, 1);
4186*c8dee2aaSAndroid Build Coastguard Worker     q.lineTo(2, 3);
4187*c8dee2aaSAndroid Build Coastguard Worker     p.addPath(q, SkPath::kExtend_AddPathMode);
4188*c8dee2aaSAndroid Build Coastguard Worker     uint8_t verbs[7];
4189*c8dee2aaSAndroid Build Coastguard Worker     int verbcount = p.getVerbs(verbs, 7);
4190*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, verbcount == 7);
4191*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, verbs[0] == SkPath::kMove_Verb);
4192*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, verbs[1] == SkPath::kLine_Verb);
4193*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, verbs[2] == SkPath::kLine_Verb);
4194*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, verbs[3] == SkPath::kClose_Verb);
4195*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, verbs[4] == SkPath::kMove_Verb);
4196*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, verbs[5] == SkPath::kLine_Verb);
4197*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, verbs[6] == SkPath::kLine_Verb);
4198*c8dee2aaSAndroid Build Coastguard Worker 
4199*c8dee2aaSAndroid Build Coastguard Worker     SkPoint pt;
4200*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.getLastPt(&pt));
4201*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pt == SkPoint::Make(2, 3));
4202*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.getPoint(3) == SkPoint::Make(1, 1));
4203*c8dee2aaSAndroid Build Coastguard Worker }
4204*c8dee2aaSAndroid Build Coastguard Worker 
test_addEmptyPath(skiatest::Reporter * reporter,SkPath::AddPathMode mode)4205*c8dee2aaSAndroid Build Coastguard Worker static void test_addEmptyPath(skiatest::Reporter* reporter, SkPath::AddPathMode mode) {
4206*c8dee2aaSAndroid Build Coastguard Worker     SkPath p, q, r;
4207*c8dee2aaSAndroid Build Coastguard Worker     // case 1: dst is empty
4208*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(2, 1);
4209*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(2, 3);
4210*c8dee2aaSAndroid Build Coastguard Worker     q.addPath(p, mode);
4211*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, q == p);
4212*c8dee2aaSAndroid Build Coastguard Worker     // case 2: src is empty
4213*c8dee2aaSAndroid Build Coastguard Worker     p.addPath(r, mode);
4214*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, q == p);
4215*c8dee2aaSAndroid Build Coastguard Worker     // case 3: src and dst are empty
4216*c8dee2aaSAndroid Build Coastguard Worker     q.reset();
4217*c8dee2aaSAndroid Build Coastguard Worker     q.addPath(r, mode);
4218*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, q.isEmpty());
4219*c8dee2aaSAndroid Build Coastguard Worker }
4220*c8dee2aaSAndroid Build Coastguard Worker 
test_conicTo_special_case(skiatest::Reporter * reporter)4221*c8dee2aaSAndroid Build Coastguard Worker static void test_conicTo_special_case(skiatest::Reporter* reporter) {
4222*c8dee2aaSAndroid Build Coastguard Worker     SkPath p;
4223*c8dee2aaSAndroid Build Coastguard Worker     p.conicTo(1, 2, 3, 4, -1);
4224*c8dee2aaSAndroid Build Coastguard Worker     check_path_is_line_and_reset(reporter, &p, 3, 4);
4225*c8dee2aaSAndroid Build Coastguard Worker     p.conicTo(1, 2, 3, 4, SK_ScalarInfinity);
4226*c8dee2aaSAndroid Build Coastguard Worker     check_path_is_line_pair_and_reset(reporter, &p, 1, 2, 3, 4);
4227*c8dee2aaSAndroid Build Coastguard Worker     p.conicTo(1, 2, 3, 4, 1);
4228*c8dee2aaSAndroid Build Coastguard Worker     check_path_is_quad_and_reset(reporter, &p, 1, 2, 3, 4);
4229*c8dee2aaSAndroid Build Coastguard Worker }
4230*c8dee2aaSAndroid Build Coastguard Worker 
test_get_point(skiatest::Reporter * reporter)4231*c8dee2aaSAndroid Build Coastguard Worker static void test_get_point(skiatest::Reporter* reporter) {
4232*c8dee2aaSAndroid Build Coastguard Worker     SkPath p;
4233*c8dee2aaSAndroid Build Coastguard Worker     SkPoint pt = p.getPoint(0);
4234*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pt == SkPoint::Make(0, 0));
4235*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.getLastPt(nullptr));
4236*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.getLastPt(&pt) && pt == SkPoint::Make(0, 0));
4237*c8dee2aaSAndroid Build Coastguard Worker     p.setLastPt(10, 10);
4238*c8dee2aaSAndroid Build Coastguard Worker     pt = p.getPoint(0);
4239*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pt == SkPoint::Make(10, 10));
4240*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.getLastPt(nullptr));
4241*c8dee2aaSAndroid Build Coastguard Worker     p.rMoveTo(10, 10);
4242*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.getLastPt(&pt) && pt == SkPoint::Make(20, 20));
4243*c8dee2aaSAndroid Build Coastguard Worker }
4244*c8dee2aaSAndroid Build Coastguard Worker 
test_contains(skiatest::Reporter * reporter)4245*c8dee2aaSAndroid Build Coastguard Worker static void test_contains(skiatest::Reporter* reporter) {
4246*c8dee2aaSAndroid Build Coastguard Worker     SkPath p;
4247*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(SkBits2Float(0xe085e7b1), SkBits2Float(0x5f512c00));  // -7.7191e+19f, 1.50724e+19f
4248*c8dee2aaSAndroid Build Coastguard Worker     p.conicTo(SkBits2Float(0xdfdaa221), SkBits2Float(0x5eaac338), SkBits2Float(0x60342f13), SkBits2Float(0xdf0cbb58), SkBits2Float(0x3f3504f3));  // -3.15084e+19f, 6.15237e+18f, 5.19345e+19f, -1.01408e+19f, 0.707107f
4249*c8dee2aaSAndroid Build Coastguard Worker     p.conicTo(SkBits2Float(0x60ead799), SkBits2Float(0xdfb76c24), SkBits2Float(0x609b9872), SkBits2Float(0xdf730de8), SkBits2Float(0x3f3504f4));  // 1.35377e+20f, -2.6434e+19f, 8.96947e+19f, -1.75139e+19f, 0.707107f
4250*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(SkBits2Float(0x609b9872), SkBits2Float(0xdf730de8));  // 8.96947e+19f, -1.75139e+19f
4251*c8dee2aaSAndroid Build Coastguard Worker     p.conicTo(SkBits2Float(0x6018b296), SkBits2Float(0xdeee870d), SkBits2Float(0xe008cd8e), SkBits2Float(0x5ed5b2db), SkBits2Float(0x3f3504f3));  // 4.40121e+19f, -8.59386e+18f, -3.94308e+19f, 7.69931e+18f, 0.707107f
4252*c8dee2aaSAndroid Build Coastguard Worker     p.conicTo(SkBits2Float(0xe0d526d9), SkBits2Float(0x5fa67b31), SkBits2Float(0xe085e7b2), SkBits2Float(0x5f512c01), SkBits2Float(0x3f3504f3));  // -1.22874e+20f, 2.39925e+19f, -7.7191e+19f, 1.50724e+19f, 0.707107f
4253*c8dee2aaSAndroid Build Coastguard Worker     // this may return true or false, depending on the platform's numerics, but it should not crash
4254*c8dee2aaSAndroid Build Coastguard Worker     (void) p.contains(-77.2027664f, 15.3066053f);
4255*c8dee2aaSAndroid Build Coastguard Worker 
4256*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4257*c8dee2aaSAndroid Build Coastguard Worker     p.setFillType(SkPathFillType::kInverseWinding);
4258*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(0, 0));
4259*c8dee2aaSAndroid Build Coastguard Worker     p.setFillType(SkPathFillType::kWinding);
4260*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.contains(0, 0));
4261*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(4, 4);
4262*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(6, 8);
4263*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(8, 4);
4264*c8dee2aaSAndroid Build Coastguard Worker     // test on edge
4265*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(6, 4));
4266*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(5, 6));
4267*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(7, 6));
4268*c8dee2aaSAndroid Build Coastguard Worker     // test quick reject
4269*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.contains(4, 0));
4270*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.contains(0, 4));
4271*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.contains(4, 10));
4272*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.contains(10, 4));
4273*c8dee2aaSAndroid Build Coastguard Worker     // test various crossings in x
4274*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.contains(5, 7));
4275*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(6, 7));
4276*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.contains(7, 7));
4277*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4278*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(4, 4);
4279*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(8, 6);
4280*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(4, 8);
4281*c8dee2aaSAndroid Build Coastguard Worker     // test on edge
4282*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(4, 6));
4283*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(6, 5));
4284*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(6, 7));
4285*c8dee2aaSAndroid Build Coastguard Worker     // test various crossings in y
4286*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.contains(7, 5));
4287*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(7, 6));
4288*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.contains(7, 7));
4289*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4290*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(4, 4);
4291*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(8, 4);
4292*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(8, 8);
4293*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(4, 8);
4294*c8dee2aaSAndroid Build Coastguard Worker     // test on vertices
4295*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(4, 4));
4296*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(8, 4));
4297*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(8, 8));
4298*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(4, 8));
4299*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4300*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(4, 4);
4301*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(6, 8);
4302*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(2, 8);
4303*c8dee2aaSAndroid Build Coastguard Worker     // test on edge
4304*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(5, 6));
4305*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(4, 8));
4306*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(3, 6));
4307*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4308*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(4, 4);
4309*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(0, 6);
4310*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(4, 8);
4311*c8dee2aaSAndroid Build Coastguard Worker     // test on edge
4312*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(2, 5));
4313*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(2, 7));
4314*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(4, 6));
4315*c8dee2aaSAndroid Build Coastguard Worker     // test canceling coincident edge (a smaller triangle is coincident with a larger one)
4316*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4317*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(4, 0);
4318*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(6, 4);
4319*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(2, 4);
4320*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(4, 0);
4321*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(0, 8);
4322*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(8, 8);
4323*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.contains(1, 2));
4324*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.contains(3, 2));
4325*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.contains(4, 0));
4326*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(4, 4));
4327*c8dee2aaSAndroid Build Coastguard Worker 
4328*c8dee2aaSAndroid Build Coastguard Worker     // test quads
4329*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4330*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(4, 4);
4331*c8dee2aaSAndroid Build Coastguard Worker     p.quadTo(6, 6, 8, 8);
4332*c8dee2aaSAndroid Build Coastguard Worker     p.quadTo(6, 8, 4, 8);
4333*c8dee2aaSAndroid Build Coastguard Worker     p.quadTo(4, 6, 4, 4);
4334*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(5, 6));
4335*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.contains(6, 5));
4336*c8dee2aaSAndroid Build Coastguard Worker     // test quad edge
4337*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(5, 5));
4338*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(5, 8));
4339*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(4, 5));
4340*c8dee2aaSAndroid Build Coastguard Worker     // test quad endpoints
4341*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(4, 4));
4342*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(8, 8));
4343*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(4, 8));
4344*c8dee2aaSAndroid Build Coastguard Worker 
4345*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4346*c8dee2aaSAndroid Build Coastguard Worker     const SkPoint qPts[] = {{6, 6}, {8, 8}, {6, 8}, {4, 8}, {4, 6}, {4, 4}, {6, 6}};
4347*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(qPts[0]);
4348*c8dee2aaSAndroid Build Coastguard Worker     for (int index = 1; index < (int) std::size(qPts); index += 2) {
4349*c8dee2aaSAndroid Build Coastguard Worker         p.quadTo(qPts[index], qPts[index + 1]);
4350*c8dee2aaSAndroid Build Coastguard Worker     }
4351*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(5, 6));
4352*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.contains(6, 5));
4353*c8dee2aaSAndroid Build Coastguard Worker     // test quad edge
4354*c8dee2aaSAndroid Build Coastguard Worker     SkPoint halfway;
4355*c8dee2aaSAndroid Build Coastguard Worker     for (int index = 0; index < (int) std::size(qPts) - 2; index += 2) {
4356*c8dee2aaSAndroid Build Coastguard Worker         SkEvalQuadAt(&qPts[index], 0.5f, &halfway, nullptr);
4357*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, p.contains(halfway.fX, halfway.fY));
4358*c8dee2aaSAndroid Build Coastguard Worker     }
4359*c8dee2aaSAndroid Build Coastguard Worker 
4360*c8dee2aaSAndroid Build Coastguard Worker     // test conics
4361*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4362*c8dee2aaSAndroid Build Coastguard Worker     const SkPoint kPts[] = {{4, 4}, {6, 6}, {8, 8}, {6, 8}, {4, 8}, {4, 6}, {4, 4}};
4363*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(kPts[0]);
4364*c8dee2aaSAndroid Build Coastguard Worker     for (int index = 1; index < (int) std::size(kPts); index += 2) {
4365*c8dee2aaSAndroid Build Coastguard Worker         p.conicTo(kPts[index], kPts[index + 1], 0.5f);
4366*c8dee2aaSAndroid Build Coastguard Worker     }
4367*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(5, 6));
4368*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.contains(6, 5));
4369*c8dee2aaSAndroid Build Coastguard Worker     // test conic edge
4370*c8dee2aaSAndroid Build Coastguard Worker     for (int index = 0; index < (int) std::size(kPts) - 2; index += 2) {
4371*c8dee2aaSAndroid Build Coastguard Worker         SkConic conic(&kPts[index], 0.5f);
4372*c8dee2aaSAndroid Build Coastguard Worker         halfway = conic.evalAt(0.5f);
4373*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, p.contains(halfway.fX, halfway.fY));
4374*c8dee2aaSAndroid Build Coastguard Worker     }
4375*c8dee2aaSAndroid Build Coastguard Worker     // test conic end points
4376*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(4, 4));
4377*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(8, 8));
4378*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.contains(4, 8));
4379*c8dee2aaSAndroid Build Coastguard Worker 
4380*c8dee2aaSAndroid Build Coastguard Worker     // test cubics
4381*c8dee2aaSAndroid Build Coastguard Worker     SkPoint pts[] = {{5, 4}, {6, 5}, {7, 6}, {6, 6}, {4, 6}, {5, 7}, {5, 5}, {5, 4}, {6, 5}, {7, 6}};
4382*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 3; ++i) {
4383*c8dee2aaSAndroid Build Coastguard Worker         p.reset();
4384*c8dee2aaSAndroid Build Coastguard Worker         p.setFillType(SkPathFillType::kEvenOdd);
4385*c8dee2aaSAndroid Build Coastguard Worker         p.moveTo(pts[i].fX, pts[i].fY);
4386*c8dee2aaSAndroid Build Coastguard Worker         p.cubicTo(pts[i + 1].fX, pts[i + 1].fY, pts[i + 2].fX, pts[i + 2].fY, pts[i + 3].fX, pts[i + 3].fY);
4387*c8dee2aaSAndroid Build Coastguard Worker         p.cubicTo(pts[i + 4].fX, pts[i + 4].fY, pts[i + 5].fX, pts[i + 5].fY, pts[i + 6].fX, pts[i + 6].fY);
4388*c8dee2aaSAndroid Build Coastguard Worker         p.close();
4389*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, p.contains(5.5f, 5.5f));
4390*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !p.contains(4.5f, 5.5f));
4391*c8dee2aaSAndroid Build Coastguard Worker         // test cubic edge
4392*c8dee2aaSAndroid Build Coastguard Worker         SkEvalCubicAt(&pts[i], 0.5f, &halfway, nullptr, nullptr);
4393*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, p.contains(halfway.fX, halfway.fY));
4394*c8dee2aaSAndroid Build Coastguard Worker         SkEvalCubicAt(&pts[i + 3], 0.5f, &halfway, nullptr, nullptr);
4395*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, p.contains(halfway.fX, halfway.fY));
4396*c8dee2aaSAndroid Build Coastguard Worker         // test cubic end points
4397*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, p.contains(pts[i].fX, pts[i].fY));
4398*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, p.contains(pts[i + 3].fX, pts[i + 3].fY));
4399*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, p.contains(pts[i + 6].fX, pts[i + 6].fY));
4400*c8dee2aaSAndroid Build Coastguard Worker     }
4401*c8dee2aaSAndroid Build Coastguard Worker }
4402*c8dee2aaSAndroid Build Coastguard Worker 
4403*c8dee2aaSAndroid Build Coastguard Worker class PathRefTest_Private {
4404*c8dee2aaSAndroid Build Coastguard Worker public:
GetFreeSpace(const SkPathRef & ref)4405*c8dee2aaSAndroid Build Coastguard Worker     static size_t GetFreeSpace(const SkPathRef& ref) {
4406*c8dee2aaSAndroid Build Coastguard Worker         return   (ref.fPoints.capacity() - ref.fPoints.size()) * sizeof(SkPoint)
4407*c8dee2aaSAndroid Build Coastguard Worker                + (ref.fVerbs.capacity()  - ref.fVerbs.size())  * sizeof(uint8_t);
4408*c8dee2aaSAndroid Build Coastguard Worker     }
4409*c8dee2aaSAndroid Build Coastguard Worker 
TestPathRef(skiatest::Reporter * reporter)4410*c8dee2aaSAndroid Build Coastguard Worker     static void TestPathRef(skiatest::Reporter* reporter) {
4411*c8dee2aaSAndroid Build Coastguard Worker         static const int kRepeatCnt = 10;
4412*c8dee2aaSAndroid Build Coastguard Worker 
4413*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkPathRef> pathRef(new SkPathRef);
4414*c8dee2aaSAndroid Build Coastguard Worker 
4415*c8dee2aaSAndroid Build Coastguard Worker         SkPathRef::Editor ed(&pathRef);
4416*c8dee2aaSAndroid Build Coastguard Worker 
4417*c8dee2aaSAndroid Build Coastguard Worker         {
4418*c8dee2aaSAndroid Build Coastguard Worker             ed.growForRepeatedVerb(SkPath::kMove_Verb, kRepeatCnt);
4419*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countVerbs());
4420*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countPoints());
4421*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, 0 == pathRef->getSegmentMasks());
4422*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < kRepeatCnt; ++i) {
4423*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, SkPath::kMove_Verb == pathRef->atVerb(i));
4424*c8dee2aaSAndroid Build Coastguard Worker             }
4425*c8dee2aaSAndroid Build Coastguard Worker             ed.resetToSize(0, 0, 0);
4426*c8dee2aaSAndroid Build Coastguard Worker         }
4427*c8dee2aaSAndroid Build Coastguard Worker 
4428*c8dee2aaSAndroid Build Coastguard Worker         {
4429*c8dee2aaSAndroid Build Coastguard Worker             ed.growForRepeatedVerb(SkPath::kLine_Verb, kRepeatCnt);
4430*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countVerbs());
4431*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countPoints());
4432*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == pathRef->getSegmentMasks());
4433*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < kRepeatCnt; ++i) {
4434*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, SkPath::kLine_Verb == pathRef->atVerb(i));
4435*c8dee2aaSAndroid Build Coastguard Worker             }
4436*c8dee2aaSAndroid Build Coastguard Worker             ed.resetToSize(0, 0, 0);
4437*c8dee2aaSAndroid Build Coastguard Worker         }
4438*c8dee2aaSAndroid Build Coastguard Worker 
4439*c8dee2aaSAndroid Build Coastguard Worker         {
4440*c8dee2aaSAndroid Build Coastguard Worker             ed.growForRepeatedVerb(SkPath::kQuad_Verb, kRepeatCnt);
4441*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countVerbs());
4442*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, 2*kRepeatCnt == pathRef->countPoints());
4443*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == pathRef->getSegmentMasks());
4444*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < kRepeatCnt; ++i) {
4445*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, SkPath::kQuad_Verb == pathRef->atVerb(i));
4446*c8dee2aaSAndroid Build Coastguard Worker             }
4447*c8dee2aaSAndroid Build Coastguard Worker             ed.resetToSize(0, 0, 0);
4448*c8dee2aaSAndroid Build Coastguard Worker         }
4449*c8dee2aaSAndroid Build Coastguard Worker 
4450*c8dee2aaSAndroid Build Coastguard Worker         {
4451*c8dee2aaSAndroid Build Coastguard Worker             SkScalar* weights = nullptr;
4452*c8dee2aaSAndroid Build Coastguard Worker             ed.growForRepeatedVerb(SkPath::kConic_Verb, kRepeatCnt, &weights);
4453*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countVerbs());
4454*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, 2*kRepeatCnt == pathRef->countPoints());
4455*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countWeights());
4456*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, SkPath::kConic_SegmentMask == pathRef->getSegmentMasks());
4457*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, weights);
4458*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < kRepeatCnt; ++i) {
4459*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, SkPath::kConic_Verb == pathRef->atVerb(i));
4460*c8dee2aaSAndroid Build Coastguard Worker             }
4461*c8dee2aaSAndroid Build Coastguard Worker             ed.resetToSize(0, 0, 0);
4462*c8dee2aaSAndroid Build Coastguard Worker         }
4463*c8dee2aaSAndroid Build Coastguard Worker 
4464*c8dee2aaSAndroid Build Coastguard Worker         {
4465*c8dee2aaSAndroid Build Coastguard Worker             ed.growForRepeatedVerb(SkPath::kCubic_Verb, kRepeatCnt);
4466*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countVerbs());
4467*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, 3*kRepeatCnt == pathRef->countPoints());
4468*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == pathRef->getSegmentMasks());
4469*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < kRepeatCnt; ++i) {
4470*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, SkPath::kCubic_Verb == pathRef->atVerb(i));
4471*c8dee2aaSAndroid Build Coastguard Worker             }
4472*c8dee2aaSAndroid Build Coastguard Worker             ed.resetToSize(0, 0, 0);
4473*c8dee2aaSAndroid Build Coastguard Worker         }
4474*c8dee2aaSAndroid Build Coastguard Worker     }
4475*c8dee2aaSAndroid Build Coastguard Worker };
4476*c8dee2aaSAndroid Build Coastguard Worker 
test_operatorEqual(skiatest::Reporter * reporter)4477*c8dee2aaSAndroid Build Coastguard Worker static void test_operatorEqual(skiatest::Reporter* reporter) {
4478*c8dee2aaSAndroid Build Coastguard Worker     SkPath a;
4479*c8dee2aaSAndroid Build Coastguard Worker     SkPath b;
4480*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, a == a);
4481*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, a == b);
4482*c8dee2aaSAndroid Build Coastguard Worker     a.setFillType(SkPathFillType::kInverseWinding);
4483*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, a != b);
4484*c8dee2aaSAndroid Build Coastguard Worker     a.reset();
4485*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, a == b);
4486*c8dee2aaSAndroid Build Coastguard Worker     a.lineTo(1, 1);
4487*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, a != b);
4488*c8dee2aaSAndroid Build Coastguard Worker     a.reset();
4489*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, a == b);
4490*c8dee2aaSAndroid Build Coastguard Worker     a.lineTo(1, 1);
4491*c8dee2aaSAndroid Build Coastguard Worker     b.lineTo(1, 2);
4492*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, a != b);
4493*c8dee2aaSAndroid Build Coastguard Worker     a.reset();
4494*c8dee2aaSAndroid Build Coastguard Worker     a.lineTo(1, 2);
4495*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, a == b);
4496*c8dee2aaSAndroid Build Coastguard Worker }
4497*c8dee2aaSAndroid Build Coastguard Worker 
compare_dump(skiatest::Reporter * reporter,const SkPath & path,bool dumpAsHex,const char * str)4498*c8dee2aaSAndroid Build Coastguard Worker static void compare_dump(skiatest::Reporter* reporter, const SkPath& path, bool dumpAsHex,
4499*c8dee2aaSAndroid Build Coastguard Worker                          const char* str) {
4500*c8dee2aaSAndroid Build Coastguard Worker     SkDynamicMemoryWStream wStream;
4501*c8dee2aaSAndroid Build Coastguard Worker     path.dump(&wStream, dumpAsHex);
4502*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkData> data = wStream.detachAsData();
4503*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, data->size() == strlen(str));
4504*c8dee2aaSAndroid Build Coastguard Worker     if (strlen(str) > 0) {
4505*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !memcmp(data->data(), str, strlen(str)));
4506*c8dee2aaSAndroid Build Coastguard Worker     } else {
4507*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, data->data() == nullptr || !memcmp(data->data(), str, strlen(str)));
4508*c8dee2aaSAndroid Build Coastguard Worker     }
4509*c8dee2aaSAndroid Build Coastguard Worker }
4510*c8dee2aaSAndroid Build Coastguard Worker 
test_dump(skiatest::Reporter * reporter)4511*c8dee2aaSAndroid Build Coastguard Worker static void test_dump(skiatest::Reporter* reporter) {
4512*c8dee2aaSAndroid Build Coastguard Worker     SkPath p;
4513*c8dee2aaSAndroid Build Coastguard Worker     compare_dump(reporter, p, false, "path.setFillType(SkPathFillType::kWinding);\n");
4514*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(1, 2);
4515*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(3, 4);
4516*c8dee2aaSAndroid Build Coastguard Worker     compare_dump(reporter, p, false, "path.setFillType(SkPathFillType::kWinding);\n"
4517*c8dee2aaSAndroid Build Coastguard Worker                                             "path.moveTo(1, 2);\n"
4518*c8dee2aaSAndroid Build Coastguard Worker                                             "path.lineTo(3, 4);\n");
4519*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4520*c8dee2aaSAndroid Build Coastguard Worker     p.setFillType(SkPathFillType::kEvenOdd);
4521*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(1, 2);
4522*c8dee2aaSAndroid Build Coastguard Worker     p.quadTo(3, 4, 5, 6);
4523*c8dee2aaSAndroid Build Coastguard Worker     compare_dump(reporter, p, false, "path.setFillType(SkPathFillType::kEvenOdd);\n"
4524*c8dee2aaSAndroid Build Coastguard Worker                                             "path.moveTo(1, 2);\n"
4525*c8dee2aaSAndroid Build Coastguard Worker                                             "path.quadTo(3, 4, 5, 6);\n");
4526*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4527*c8dee2aaSAndroid Build Coastguard Worker     p.setFillType(SkPathFillType::kInverseWinding);
4528*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(1, 2);
4529*c8dee2aaSAndroid Build Coastguard Worker     p.conicTo(3, 4, 5, 6, 0.5f);
4530*c8dee2aaSAndroid Build Coastguard Worker     compare_dump(reporter, p, false, "path.setFillType(SkPathFillType::kInverseWinding);\n"
4531*c8dee2aaSAndroid Build Coastguard Worker                                             "path.moveTo(1, 2);\n"
4532*c8dee2aaSAndroid Build Coastguard Worker                                             "path.conicTo(3, 4, 5, 6, 0.5f);\n");
4533*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4534*c8dee2aaSAndroid Build Coastguard Worker     p.setFillType(SkPathFillType::kInverseEvenOdd);
4535*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(1, 2);
4536*c8dee2aaSAndroid Build Coastguard Worker     p.cubicTo(3, 4, 5, 6, 7, 8);
4537*c8dee2aaSAndroid Build Coastguard Worker     compare_dump(reporter, p, false, "path.setFillType(SkPathFillType::kInverseEvenOdd);\n"
4538*c8dee2aaSAndroid Build Coastguard Worker                                             "path.moveTo(1, 2);\n"
4539*c8dee2aaSAndroid Build Coastguard Worker                                             "path.cubicTo(3, 4, 5, 6, 7, 8);\n");
4540*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4541*c8dee2aaSAndroid Build Coastguard Worker     p.setFillType(SkPathFillType::kWinding);
4542*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(1, 2);
4543*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(3, 4);
4544*c8dee2aaSAndroid Build Coastguard Worker     compare_dump(reporter, p, true,
4545*c8dee2aaSAndroid Build Coastguard Worker                  "path.setFillType(SkPathFillType::kWinding);\n"
4546*c8dee2aaSAndroid Build Coastguard Worker                  "path.moveTo(SkBits2Float(0x3f800000), SkBits2Float(0x40000000));  // 1, 2\n"
4547*c8dee2aaSAndroid Build Coastguard Worker                  "path.lineTo(SkBits2Float(0x40400000), SkBits2Float(0x40800000));  // 3, 4\n");
4548*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
4549*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(SkBits2Float(0x3f800000), SkBits2Float(0x40000000));
4550*c8dee2aaSAndroid Build Coastguard Worker     p.lineTo(SkBits2Float(0x40400000), SkBits2Float(0x40800000));
4551*c8dee2aaSAndroid Build Coastguard Worker     compare_dump(reporter, p, false, "path.setFillType(SkPathFillType::kWinding);\n"
4552*c8dee2aaSAndroid Build Coastguard Worker                                             "path.moveTo(1, 2);\n"
4553*c8dee2aaSAndroid Build Coastguard Worker                                             "path.lineTo(3, 4);\n");
4554*c8dee2aaSAndroid Build Coastguard Worker }
4555*c8dee2aaSAndroid Build Coastguard Worker 
4556*c8dee2aaSAndroid Build Coastguard Worker namespace {
4557*c8dee2aaSAndroid Build Coastguard Worker 
4558*c8dee2aaSAndroid Build Coastguard Worker class ChangeListener : public SkIDChangeListener {
4559*c8dee2aaSAndroid Build Coastguard Worker public:
ChangeListener(bool * changed)4560*c8dee2aaSAndroid Build Coastguard Worker     ChangeListener(bool *changed) : fChanged(changed) { *fChanged = false; }
~ChangeListener()4561*c8dee2aaSAndroid Build Coastguard Worker     ~ChangeListener() override {}
changed()4562*c8dee2aaSAndroid Build Coastguard Worker     void changed() override { *fChanged = true; }
4563*c8dee2aaSAndroid Build Coastguard Worker 
4564*c8dee2aaSAndroid Build Coastguard Worker private:
4565*c8dee2aaSAndroid Build Coastguard Worker     bool* fChanged;
4566*c8dee2aaSAndroid Build Coastguard Worker };
4567*c8dee2aaSAndroid Build Coastguard Worker 
4568*c8dee2aaSAndroid Build Coastguard Worker }  // namespace
4569*c8dee2aaSAndroid Build Coastguard Worker 
4570*c8dee2aaSAndroid Build Coastguard Worker class PathTest_Private {
4571*c8dee2aaSAndroid Build Coastguard Worker public:
GetFreeSpace(const SkPath & path)4572*c8dee2aaSAndroid Build Coastguard Worker     static size_t GetFreeSpace(const SkPath& path) {
4573*c8dee2aaSAndroid Build Coastguard Worker         return PathRefTest_Private::GetFreeSpace(*path.fPathRef);
4574*c8dee2aaSAndroid Build Coastguard Worker     }
4575*c8dee2aaSAndroid Build Coastguard Worker 
TestPathTo(skiatest::Reporter * reporter)4576*c8dee2aaSAndroid Build Coastguard Worker     static void TestPathTo(skiatest::Reporter* reporter) {
4577*c8dee2aaSAndroid Build Coastguard Worker         SkPath p, q;
4578*c8dee2aaSAndroid Build Coastguard Worker         p.lineTo(4, 4);
4579*c8dee2aaSAndroid Build Coastguard Worker         p.reversePathTo(q);
4580*c8dee2aaSAndroid Build Coastguard Worker         check_path_is_line(reporter, &p, 4, 4);
4581*c8dee2aaSAndroid Build Coastguard Worker         q.moveTo(-4, -4);
4582*c8dee2aaSAndroid Build Coastguard Worker         p.reversePathTo(q);
4583*c8dee2aaSAndroid Build Coastguard Worker         check_path_is_line(reporter, &p, 4, 4);
4584*c8dee2aaSAndroid Build Coastguard Worker         q.lineTo(7, 8);
4585*c8dee2aaSAndroid Build Coastguard Worker         q.conicTo(8, 7, 6, 5, 0.5f);
4586*c8dee2aaSAndroid Build Coastguard Worker         q.quadTo(6, 7, 8, 6);
4587*c8dee2aaSAndroid Build Coastguard Worker         q.cubicTo(5, 6, 7, 8, 7, 5);
4588*c8dee2aaSAndroid Build Coastguard Worker         q.close();
4589*c8dee2aaSAndroid Build Coastguard Worker         p.reversePathTo(q);
4590*c8dee2aaSAndroid Build Coastguard Worker         SkRect reverseExpected = {-4, -4, 8, 8};
4591*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, p.getBounds() == reverseExpected);
4592*c8dee2aaSAndroid Build Coastguard Worker     }
4593*c8dee2aaSAndroid Build Coastguard Worker 
TestPathrefListeners(skiatest::Reporter * reporter)4594*c8dee2aaSAndroid Build Coastguard Worker     static void TestPathrefListeners(skiatest::Reporter* reporter) {
4595*c8dee2aaSAndroid Build Coastguard Worker         SkPath p;
4596*c8dee2aaSAndroid Build Coastguard Worker 
4597*c8dee2aaSAndroid Build Coastguard Worker         bool changed = false;
4598*c8dee2aaSAndroid Build Coastguard Worker         p.moveTo(0, 0);
4599*c8dee2aaSAndroid Build Coastguard Worker 
4600*c8dee2aaSAndroid Build Coastguard Worker         // Check that listener is notified on moveTo().
4601*c8dee2aaSAndroid Build Coastguard Worker 
4602*c8dee2aaSAndroid Build Coastguard Worker         SkPathPriv::AddGenIDChangeListener(p, sk_make_sp<ChangeListener>(&changed));
4603*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !changed);
4604*c8dee2aaSAndroid Build Coastguard Worker         p.moveTo(10, 0);
4605*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, changed);
4606*c8dee2aaSAndroid Build Coastguard Worker 
4607*c8dee2aaSAndroid Build Coastguard Worker         // Check that listener is notified on lineTo().
4608*c8dee2aaSAndroid Build Coastguard Worker         SkPathPriv::AddGenIDChangeListener(p, sk_make_sp<ChangeListener>(&changed));
4609*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !changed);
4610*c8dee2aaSAndroid Build Coastguard Worker         p.lineTo(20, 0);
4611*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, changed);
4612*c8dee2aaSAndroid Build Coastguard Worker 
4613*c8dee2aaSAndroid Build Coastguard Worker         // Check that listener is notified on reset().
4614*c8dee2aaSAndroid Build Coastguard Worker         SkPathPriv::AddGenIDChangeListener(p, sk_make_sp<ChangeListener>(&changed));
4615*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !changed);
4616*c8dee2aaSAndroid Build Coastguard Worker         p.reset();
4617*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, changed);
4618*c8dee2aaSAndroid Build Coastguard Worker 
4619*c8dee2aaSAndroid Build Coastguard Worker         p.moveTo(0, 0);
4620*c8dee2aaSAndroid Build Coastguard Worker 
4621*c8dee2aaSAndroid Build Coastguard Worker         // Check that listener is notified on rewind().
4622*c8dee2aaSAndroid Build Coastguard Worker         SkPathPriv::AddGenIDChangeListener(p, sk_make_sp<ChangeListener>(&changed));
4623*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !changed);
4624*c8dee2aaSAndroid Build Coastguard Worker         p.rewind();
4625*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, changed);
4626*c8dee2aaSAndroid Build Coastguard Worker 
4627*c8dee2aaSAndroid Build Coastguard Worker         // Check that listener is notified on transform().
4628*c8dee2aaSAndroid Build Coastguard Worker         {
4629*c8dee2aaSAndroid Build Coastguard Worker             SkPath q;
4630*c8dee2aaSAndroid Build Coastguard Worker             q.moveTo(10, 10);
4631*c8dee2aaSAndroid Build Coastguard Worker             SkPathPriv::AddGenIDChangeListener(q, sk_make_sp<ChangeListener>(&changed));
4632*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !changed);
4633*c8dee2aaSAndroid Build Coastguard Worker             SkMatrix matrix;
4634*c8dee2aaSAndroid Build Coastguard Worker             matrix.setScale(2, 2);
4635*c8dee2aaSAndroid Build Coastguard Worker             p.transform(matrix, &q);
4636*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, changed);
4637*c8dee2aaSAndroid Build Coastguard Worker         }
4638*c8dee2aaSAndroid Build Coastguard Worker 
4639*c8dee2aaSAndroid Build Coastguard Worker         // Check that listener is notified when pathref is deleted.
4640*c8dee2aaSAndroid Build Coastguard Worker         {
4641*c8dee2aaSAndroid Build Coastguard Worker             SkPath q;
4642*c8dee2aaSAndroid Build Coastguard Worker             q.moveTo(10, 10);
4643*c8dee2aaSAndroid Build Coastguard Worker             SkPathPriv::AddGenIDChangeListener(q, sk_make_sp<ChangeListener>(&changed));
4644*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !changed);
4645*c8dee2aaSAndroid Build Coastguard Worker         }
4646*c8dee2aaSAndroid Build Coastguard Worker         // q went out of scope.
4647*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, changed);
4648*c8dee2aaSAndroid Build Coastguard Worker     }
4649*c8dee2aaSAndroid Build Coastguard Worker };
4650*c8dee2aaSAndroid Build Coastguard Worker 
test_crbug_629455(skiatest::Reporter * reporter)4651*c8dee2aaSAndroid Build Coastguard Worker static void test_crbug_629455(skiatest::Reporter* reporter) {
4652*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
4653*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0);
4654*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(SkBits2Float(0xcdcdcd00), SkBits2Float(0xcdcdcdcd),
4655*c8dee2aaSAndroid Build Coastguard Worker                  SkBits2Float(0xcdcdcdcd), SkBits2Float(0xcdcdcdcd),
4656*c8dee2aaSAndroid Build Coastguard Worker                  SkBits2Float(0x423fcdcd), SkBits2Float(0x40ed9341));
4657*c8dee2aaSAndroid Build Coastguard Worker //  AKA: cubicTo(-4.31596e+08f, -4.31602e+08f, -4.31602e+08f, -4.31602e+08f, 47.951f, 7.42423f);
4658*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0, 0);
4659*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(100, 100, path);
4660*c8dee2aaSAndroid Build Coastguard Worker }
4661*c8dee2aaSAndroid Build Coastguard Worker 
test_fuzz_crbug_662952(skiatest::Reporter * reporter)4662*c8dee2aaSAndroid Build Coastguard Worker static void test_fuzz_crbug_662952(skiatest::Reporter* reporter) {
4663*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
4664*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x4109999a), SkBits2Float(0x411c0000));  // 8.6f, 9.75f
4665*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x410a6666), SkBits2Float(0x411c0000));  // 8.65f, 9.75f
4666*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x410a6666), SkBits2Float(0x411e6666));  // 8.65f, 9.9f
4667*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x4109999a), SkBits2Float(0x411e6666));  // 8.6f, 9.9f
4668*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x4109999a), SkBits2Float(0x411c0000));  // 8.6f, 9.75f
4669*c8dee2aaSAndroid Build Coastguard Worker     path.close();
4670*c8dee2aaSAndroid Build Coastguard Worker 
4671*c8dee2aaSAndroid Build Coastguard Worker     auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100));
4672*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
4673*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(true);
4674*c8dee2aaSAndroid Build Coastguard Worker     surface->getCanvas()->clipPath(path, true);
4675*c8dee2aaSAndroid Build Coastguard Worker     surface->getCanvas()->drawRect(SkRect::MakeWH(100, 100), paint);
4676*c8dee2aaSAndroid Build Coastguard Worker }
4677*c8dee2aaSAndroid Build Coastguard Worker 
test_path_crbugskia6003()4678*c8dee2aaSAndroid Build Coastguard Worker static void test_path_crbugskia6003() {
4679*c8dee2aaSAndroid Build Coastguard Worker     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(500, 500)));
4680*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = surface->getCanvas();
4681*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
4682*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(true);
4683*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
4684*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x4325e666), SkBits2Float(0x42a1999a));  // 165.9f, 80.8f
4685*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x4325e666), SkBits2Float(0x42a2999a));  // 165.9f, 81.3f
4686*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x4325b333), SkBits2Float(0x42a2999a));  // 165.7f, 81.3f
4687*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x4325b333), SkBits2Float(0x42a16666));  // 165.7f, 80.7f
4688*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x4325b333), SkBits2Float(0x429f6666));  // 165.7f, 79.7f
4689*c8dee2aaSAndroid Build Coastguard Worker     // 165.7f, 79.7f, 165.8f, 79.7f, 165.8f, 79.7f
4690*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(SkBits2Float(0x4325b333), SkBits2Float(0x429f6666), SkBits2Float(0x4325cccc),
4691*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x429f6666), SkBits2Float(0x4325cccc), SkBits2Float(0x429f6666));
4692*c8dee2aaSAndroid Build Coastguard Worker     // 165.8f, 79.7f, 165.8f, 79.7f, 165.9f, 79.7f
4693*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(SkBits2Float(0x4325cccc), SkBits2Float(0x429f6666), SkBits2Float(0x4325cccc),
4694*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x429f6666), SkBits2Float(0x4325e666), SkBits2Float(0x429f6666));
4695*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x4325e666), SkBits2Float(0x42a1999a));  // 165.9f, 80.8f
4696*c8dee2aaSAndroid Build Coastguard Worker     path.close();
4697*c8dee2aaSAndroid Build Coastguard Worker     canvas->clipPath(path, true);
4698*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRect(SkRect::MakeWH(500, 500), paint);
4699*c8dee2aaSAndroid Build Coastguard Worker }
4700*c8dee2aaSAndroid Build Coastguard Worker 
test_fuzz_crbug_662730(skiatest::Reporter * reporter)4701*c8dee2aaSAndroid Build Coastguard Worker static void test_fuzz_crbug_662730(skiatest::Reporter* reporter) {
4702*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
4703*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000));  // 0, 0
4704*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xd5394437), SkBits2Float(0x37373737));  // -1.2731e+13f, 1.09205e-05f
4705*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x37373737), SkBits2Float(0x37373737));  // 1.09205e-05f, 1.09205e-05f
4706*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x37373745), SkBits2Float(0x0001b800));  // 1.09205e-05f, 1.57842e-40f
4707*c8dee2aaSAndroid Build Coastguard Worker     path.close();
4708*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(100, 100, path);
4709*c8dee2aaSAndroid Build Coastguard Worker }
4710*c8dee2aaSAndroid Build Coastguard Worker 
test_skbug_6947()4711*c8dee2aaSAndroid Build Coastguard Worker static void test_skbug_6947() {
4712*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
4713*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points[] =
4714*c8dee2aaSAndroid Build Coastguard Worker         {{125.126022f, -0.499872506f}, {125.288895f, -0.499338806f},
4715*c8dee2aaSAndroid Build Coastguard Worker          {125.299316f, -0.499290764f}, {126.294594f, 0.505449712f},
4716*c8dee2aaSAndroid Build Coastguard Worker          {125.999992f, 62.5047531f}, {124.0f, 62.4980202f},
4717*c8dee2aaSAndroid Build Coastguard Worker          {124.122749f, 0.498142242f}, {125.126022f, -0.499872506f},
4718*c8dee2aaSAndroid Build Coastguard Worker          {125.119476f, 1.50011659f}, {125.122749f, 0.50012207f},
4719*c8dee2aaSAndroid Build Coastguard Worker          {126.122749f, 0.502101898f}, {126.0f, 62.5019798f},
4720*c8dee2aaSAndroid Build Coastguard Worker          {125.0f, 62.5f}, {124.000008f, 62.4952469f},
4721*c8dee2aaSAndroid Build Coastguard Worker          {124.294609f, 0.495946467f}, {125.294601f, 0.50069809f},
4722*c8dee2aaSAndroid Build Coastguard Worker          {125.289886f, 1.50068688f}, {125.282349f, 1.50065041f},
4723*c8dee2aaSAndroid Build Coastguard Worker          {125.119476f, 1.50011659f}};
4724*c8dee2aaSAndroid Build Coastguard Worker     constexpr SkPath::Verb kMove = SkPath::kMove_Verb;
4725*c8dee2aaSAndroid Build Coastguard Worker     constexpr SkPath::Verb kLine = SkPath::kLine_Verb;
4726*c8dee2aaSAndroid Build Coastguard Worker     constexpr SkPath::Verb kClose = SkPath::kClose_Verb;
4727*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Verb verbs[] = {kMove, kLine, kLine, kLine, kLine, kLine, kLine, kLine, kClose,
4728*c8dee2aaSAndroid Build Coastguard Worker             kMove, kLine, kLine, kLine, kLine, kLine, kLine, kLine, kLine, kLine, kLine, kClose};
4729*c8dee2aaSAndroid Build Coastguard Worker     int pointIndex = 0;
4730*c8dee2aaSAndroid Build Coastguard Worker     for(auto verb : verbs) {
4731*c8dee2aaSAndroid Build Coastguard Worker         switch (verb) {
4732*c8dee2aaSAndroid Build Coastguard Worker             case kMove:
4733*c8dee2aaSAndroid Build Coastguard Worker                 path.moveTo(points[pointIndex++]);
4734*c8dee2aaSAndroid Build Coastguard Worker                 break;
4735*c8dee2aaSAndroid Build Coastguard Worker             case kLine:
4736*c8dee2aaSAndroid Build Coastguard Worker                 path.lineTo(points[pointIndex++]);
4737*c8dee2aaSAndroid Build Coastguard Worker                 break;
4738*c8dee2aaSAndroid Build Coastguard Worker             case kClose:
4739*c8dee2aaSAndroid Build Coastguard Worker             default:
4740*c8dee2aaSAndroid Build Coastguard Worker                 path.close();
4741*c8dee2aaSAndroid Build Coastguard Worker                 break;
4742*c8dee2aaSAndroid Build Coastguard Worker         }
4743*c8dee2aaSAndroid Build Coastguard Worker     }
4744*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(250, 125, path);
4745*c8dee2aaSAndroid Build Coastguard Worker }
4746*c8dee2aaSAndroid Build Coastguard Worker 
test_skbug_7015()4747*c8dee2aaSAndroid Build Coastguard Worker static void test_skbug_7015() {
4748*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
4749*c8dee2aaSAndroid Build Coastguard Worker     path.setFillType(SkPathFillType::kWinding);
4750*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x4388c000), SkBits2Float(0x43947c08));  // 273.5f, 296.969f
4751*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x4386c000), SkBits2Float(0x43947c08));  // 269.5f, 296.969f
4752*c8dee2aaSAndroid Build Coastguard Worker     // 269.297f, 292.172f, 273.695f, 292.172f, 273.5f, 296.969f
4753*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(SkBits2Float(0x4386a604), SkBits2Float(0x43921604),
4754*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x4388d8f6), SkBits2Float(0x43921604),
4755*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x4388c000), SkBits2Float(0x43947c08));
4756*c8dee2aaSAndroid Build Coastguard Worker     path.close();
4757*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(500, 500, path);
4758*c8dee2aaSAndroid Build Coastguard Worker }
4759*c8dee2aaSAndroid Build Coastguard Worker 
test_skbug_7051()4760*c8dee2aaSAndroid Build Coastguard Worker static void test_skbug_7051() {
4761*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
4762*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(10, 10);
4763*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(10, 20, 10, 30, 30, 30);
4764*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(50, 20);
4765*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(50, 10);
4766*c8dee2aaSAndroid Build Coastguard Worker     path.close();
4767*c8dee2aaSAndroid Build Coastguard Worker     test_draw_AA_path(100, 100, path);
4768*c8dee2aaSAndroid Build Coastguard Worker }
4769*c8dee2aaSAndroid Build Coastguard Worker 
test_skbug_7435()4770*c8dee2aaSAndroid Build Coastguard Worker static void test_skbug_7435() {
4771*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
4772*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
4773*c8dee2aaSAndroid Build Coastguard Worker     path.setFillType(SkPathFillType::kWinding);
4774*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x7f07a5af), SkBits2Float(0xff07ff1d));  // 1.80306e+38f, -1.8077e+38f
4775*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7edf4b2d), SkBits2Float(0xfedffe0a));  // 1.48404e+38f, -1.48868e+38f
4776*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7edf4585), SkBits2Float(0xfee003b2));  // 1.48389e+38f, -1.48883e+38f
4777*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7ef348e9), SkBits2Float(0xfef403c6));  // 1.6169e+38f, -1.62176e+38f
4778*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7ef74c4e), SkBits2Float(0xfef803cb));  // 1.64358e+38f, -1.64834e+38f
4779*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0x7ef74f23), SkBits2Float(0xfef8069e), SkBits2Float(0x7ef751f6), SkBits2Float(0xfef803c9), SkBits2Float(0x3f3504f3));  // 1.64365e+38f, -1.64841e+38f, 1.64372e+38f, -1.64834e+38f, 0.707107f
4780*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0x7ef754c8), SkBits2Float(0xfef800f5), SkBits2Float(0x7ef751f5), SkBits2Float(0xfef7fe22), SkBits2Float(0x3f353472));  // 1.6438e+38f, -1.64827e+38f, 1.64372e+38f, -1.64819e+38f, 0.707832f
4781*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7edb57a9), SkBits2Float(0xfedbfe06));  // 1.45778e+38f, -1.4621e+38f
4782*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7e875976), SkBits2Float(0xfe87fdb3));  // 8.99551e+37f, -9.03815e+37f
4783*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7ded5c2b), SkBits2Float(0xfdeff59e));  // 3.94382e+37f, -3.98701e+37f
4784*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7d7a78a7), SkBits2Float(0xfd7fda0f));  // 2.08083e+37f, -2.12553e+37f
4785*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7d7a6403), SkBits2Float(0xfd7fe461));  // 2.08016e+37f, -2.12587e+37f
4786*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0x7d7a4764), SkBits2Float(0xfd7ff2b0), SkBits2Float(0x7d7a55b4), SkBits2Float(0xfd8007a8), SkBits2Float(0x3f3504f3));  // 2.07924e+37f, -2.12633e+37f, 2.0797e+37f, -2.12726e+37f, 0.707107f
4787*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0x7d7a5803), SkBits2Float(0xfd8009f7), SkBits2Float(0x7d7a5ba9), SkBits2Float(0xfd800bcc), SkBits2Float(0x3f7cba66));  // 2.07977e+37f, -2.12741e+37f, 2.07989e+37f, -2.12753e+37f, 0.987219f
4788*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7d8d2067), SkBits2Float(0xfd900bdb));  // 2.34487e+37f, -2.39338e+37f
4789*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7ddd137a), SkBits2Float(0xfde00c2d));  // 3.67326e+37f, -3.72263e+37f
4790*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7ddd2a1b), SkBits2Float(0xfddff58e));  // 3.67473e+37f, -3.72116e+37f
4791*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7c694ae5), SkBits2Float(0xfc7fa67c));  // 4.8453e+36f, -5.30965e+36f
4792*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfc164a8b), SkBits2Float(0x7c005af5));  // -3.12143e+36f, 2.66584e+36f
4793*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfc8ae983), SkBits2Float(0x7c802da7));  // -5.77019e+36f, 5.32432e+36f
4794*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfc8b16d9), SkBits2Float(0x7c80007b));  // -5.77754e+36f, 5.31699e+36f
4795*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfc8b029c), SkBits2Float(0x7c7f8788));  // -5.77426e+36f, 5.30714e+36f
4796*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfc8b0290), SkBits2Float(0x7c7f8790));  // -5.77425e+36f, 5.30714e+36f
4797*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfc8b16cd), SkBits2Float(0x7c80007f));  // -5.77753e+36f, 5.31699e+36f
4798*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfc8b4409), SkBits2Float(0x7c7fa672));  // -5.78487e+36f, 5.30965e+36f
4799*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7d7aa2ba), SkBits2Float(0xfd800bd1));  // 2.0822e+37f, -2.12753e+37f
4800*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7e8757ee), SkBits2Float(0xfe88035b));  // 8.99512e+37f, -9.03962e+37f
4801*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7ef7552d), SkBits2Float(0xfef803ca));  // 1.64381e+38f, -1.64834e+38f
4802*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7f0fa653), SkBits2Float(0xff1001f9));  // 1.90943e+38f, -1.91419e+38f
4803*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7f0fa926), SkBits2Float(0xff0fff24));  // 1.90958e+38f, -1.91404e+38f
4804*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7f0da75c), SkBits2Float(0xff0dff22));  // 1.8829e+38f, -1.88746e+38f
4805*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7f07a5af), SkBits2Float(0xff07ff1d));  // 1.80306e+38f, -1.8077e+38f
4806*c8dee2aaSAndroid Build Coastguard Worker     path.close();
4807*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x7f07a2db), SkBits2Float(0xff0801f1));  // 1.80291e+38f, -1.80785e+38f
4808*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7f0da48a), SkBits2Float(0xff0e01f8));  // 1.88275e+38f, -1.88761e+38f
4809*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7f0fa654), SkBits2Float(0xff1001fa));  // 1.90943e+38f, -1.91419e+38f
4810*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7f0fa7bd), SkBits2Float(0xff10008f));  // 1.90951e+38f, -1.91412e+38f
4811*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7f0fa927), SkBits2Float(0xff0fff25));  // 1.90958e+38f, -1.91404e+38f
4812*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7ef75ad5), SkBits2Float(0xfef7fe22));  // 1.64395e+38f, -1.64819e+38f
4813*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7e875d96), SkBits2Float(0xfe87fdb3));  // 8.99659e+37f, -9.03815e+37f
4814*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7d7acff6), SkBits2Float(0xfd7fea5b));  // 2.08367e+37f, -2.12606e+37f
4815*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfc8b0588), SkBits2Float(0x7c8049b7));  // -5.77473e+36f, 5.32887e+36f
4816*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfc8b2b16), SkBits2Float(0x7c803d32));  // -5.78083e+36f, 5.32684e+36f
4817*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0xfc8b395c), SkBits2Float(0x7c803870), SkBits2Float(0xfc8b4405), SkBits2Float(0x7c802dd1), SkBits2Float(0x3f79349d));  // -5.78314e+36f, 5.32607e+36f, -5.78487e+36f, 5.32435e+36f, 0.973459f
4818*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0xfc8b715b), SkBits2Float(0x7c8000a5), SkBits2Float(0xfc8b442f), SkBits2Float(0x7c7fa69e), SkBits2Float(0x3f3504f3));  // -5.79223e+36f, 5.31702e+36f, -5.7849e+36f, 5.30966e+36f, 0.707107f
4819*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfc16ffaa), SkBits2Float(0x7bff4c12));  // -3.13612e+36f, 2.65116e+36f
4820*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7c6895e0), SkBits2Float(0xfc802dc0));  // 4.83061e+36f, -5.32434e+36f
4821*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7ddd137b), SkBits2Float(0xfde00c2e));  // 3.67326e+37f, -3.72263e+37f
4822*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7ddd1ecb), SkBits2Float(0xfde000de));  // 3.67399e+37f, -3.72189e+37f
4823*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7ddd2a1c), SkBits2Float(0xfddff58f));  // 3.67473e+37f, -3.72116e+37f
4824*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7d8d3711), SkBits2Float(0xfd8ff543));  // 2.34634e+37f, -2.39191e+37f
4825*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7d7a88fe), SkBits2Float(0xfd7fea69));  // 2.08136e+37f, -2.12606e+37f
4826*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7d7a7254), SkBits2Float(0xfd800080));  // 2.08063e+37f, -2.1268e+37f
4827*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7d7a80a4), SkBits2Float(0xfd800ed0));  // 2.08109e+37f, -2.12773e+37f
4828*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7d7a80a8), SkBits2Float(0xfd800ecf));  // 2.08109e+37f, -2.12773e+37f
4829*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7d7a7258), SkBits2Float(0xfd80007f));  // 2.08063e+37f, -2.1268e+37f
4830*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7d7a5bb9), SkBits2Float(0xfd800bd0));  // 2.0799e+37f, -2.12753e+37f
4831*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7ded458b), SkBits2Float(0xfdf00c3e));  // 3.94235e+37f, -3.98848e+37f
4832*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7e8753ce), SkBits2Float(0xfe88035b));  // 8.99405e+37f, -9.03962e+37f
4833*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7edb5201), SkBits2Float(0xfedc03ae));  // 1.45763e+38f, -1.46225e+38f
4834*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7ef74c4d), SkBits2Float(0xfef803ca));  // 1.64358e+38f, -1.64834e+38f
4835*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7ef74f21), SkBits2Float(0xfef800f6));  // 1.64365e+38f, -1.64827e+38f
4836*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7ef751f4), SkBits2Float(0xfef7fe21));  // 1.64372e+38f, -1.64819e+38f
4837*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7ef34e91), SkBits2Float(0xfef3fe1e));  // 1.61705e+38f, -1.62161e+38f
4838*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7edf4b2d), SkBits2Float(0xfedffe0a));  // 1.48404e+38f, -1.48868e+38f
4839*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7edf4859), SkBits2Float(0xfee000de));  // 1.48397e+38f, -1.48876e+38f
4840*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7edf4585), SkBits2Float(0xfee003b2));  // 1.48389e+38f, -1.48883e+38f
4841*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7f07a2db), SkBits2Float(0xff0801f1));  // 1.80291e+38f, -1.80785e+38f
4842*c8dee2aaSAndroid Build Coastguard Worker     path.close();
4843*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0xfab120db), SkBits2Float(0x77b50b4f));  // -4.59851e+35f, 7.34402e+33f
4844*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfd6597e5), SkBits2Float(0x7d60177f));  // -1.90739e+37f, 1.86168e+37f
4845*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfde2cea1), SkBits2Float(0x7de00c2e));  // -3.76848e+37f, 3.72263e+37f
4846*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe316511), SkBits2Float(0x7e300657));  // -5.89495e+37f, 5.84943e+37f
4847*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe415da1), SkBits2Float(0x7e400666));  // -6.42568e+37f, 6.38112e+37f
4848*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe41634a), SkBits2Float(0x7e4000be));  // -6.42641e+37f, 6.38039e+37f
4849*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe41634a), SkBits2Float(0x7e3ff8be));  // -6.42641e+37f, 6.37935e+37f
4850*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe416349), SkBits2Float(0x7e3ff8be));  // -6.42641e+37f, 6.37935e+37f
4851*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe415f69), SkBits2Float(0x7e3ff8be));  // -6.42591e+37f, 6.37935e+37f
4852*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe415bc9), SkBits2Float(0x7e3ff8be));  // -6.42544e+37f, 6.37935e+37f
4853*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe415bc9), SkBits2Float(0x7e4000be));  // -6.42544e+37f, 6.38039e+37f
4854*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe416171), SkBits2Float(0x7e3ffb16));  // -6.42617e+37f, 6.37966e+37f
4855*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe016131), SkBits2Float(0x7dfff5ae));  // -4.29938e+37f, 4.25286e+37f
4856*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe0155e2), SkBits2Float(0x7e000628));  // -4.29791e+37f, 4.25433e+37f
4857*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe0958ea), SkBits2Float(0x7e080630));  // -4.56415e+37f, 4.52018e+37f
4858*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe115c92), SkBits2Float(0x7e100638));  // -4.83047e+37f, 4.78603e+37f
4859*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0xfe11623c), SkBits2Float(0x7e100bdf), SkBits2Float(0xfe1167e2), SkBits2Float(0x7e100636), SkBits2Float(0x3f3504f3));  // -4.8312e+37f, 4.78676e+37f, -4.83194e+37f, 4.78603e+37f, 0.707107f
4860*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0xfe116d87), SkBits2Float(0x7e10008e), SkBits2Float(0xfe1167e2), SkBits2Float(0x7e0ffae8), SkBits2Float(0x3f35240a));  // -4.83267e+37f, 4.78529e+37f, -4.83194e+37f, 4.78456e+37f, 0.707581f
4861*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe016b92), SkBits2Float(0x7dfff5af));  // -4.30072e+37f, 4.25286e+37f
4862*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfdc2d963), SkBits2Float(0x7dbff56e));  // -3.23749e+37f, 3.18946e+37f
4863*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfd65ae25), SkBits2Float(0x7d5fea3d));  // -1.90811e+37f, 1.86021e+37f
4864*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfab448de), SkBits2Float(0xf7b50a19));  // -4.68046e+35f, -7.34383e+33f
4865*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfab174d9), SkBits2Float(0x43480000));  // -4.60703e+35f, 200
4866*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfab174d9), SkBits2Float(0x7800007f));  // -4.60703e+35f, 1.03848e+34f
4867*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfab3f4db), SkBits2Float(0x7800007f));  // -4.67194e+35f, 1.03848e+34f
4868*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfab3f4db), SkBits2Float(0x43480000));  // -4.67194e+35f, 200
4869*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfab120db), SkBits2Float(0x77b50b4f));  // -4.59851e+35f, 7.34402e+33f
4870*c8dee2aaSAndroid Build Coastguard Worker     path.close();
4871*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0xfab59cf2), SkBits2Float(0xf800007e));  // -4.71494e+35f, -1.03847e+34f
4872*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfaa7cc52), SkBits2Float(0xf800007f));  // -4.35629e+35f, -1.03848e+34f
4873*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfd6580e5), SkBits2Float(0x7d60177f));  // -1.90664e+37f, 1.86168e+37f
4874*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfdc2c2c1), SkBits2Float(0x7dc00c0f));  // -3.23602e+37f, 3.19093e+37f
4875*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe016040), SkBits2Float(0x7e000626));  // -4.29925e+37f, 4.25433e+37f
4876*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe115c90), SkBits2Float(0x7e100636));  // -4.83047e+37f, 4.78603e+37f
4877*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe116239), SkBits2Float(0x7e10008f));  // -4.8312e+37f, 4.78529e+37f
4878*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe1167e0), SkBits2Float(0x7e0ffae6));  // -4.83194e+37f, 4.78456e+37f
4879*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe096438), SkBits2Float(0x7e07fade));  // -4.56562e+37f, 4.51871e+37f
4880*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe016130), SkBits2Float(0x7dfff5ac));  // -4.29938e+37f, 4.25286e+37f
4881*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe015b89), SkBits2Float(0x7e00007f));  // -4.29864e+37f, 4.25359e+37f
4882*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe0155e1), SkBits2Float(0x7e000627));  // -4.29791e+37f, 4.25433e+37f
4883*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe415879), SkBits2Float(0x7e4008bf));  // -6.42501e+37f, 6.38143e+37f
4884*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe415f69), SkBits2Float(0x7e4008bf));  // -6.42591e+37f, 6.38143e+37f
4885*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe416349), SkBits2Float(0x7e4008bf));  // -6.42641e+37f, 6.38143e+37f
4886*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe41634a), SkBits2Float(0x7e4008bf));  // -6.42641e+37f, 6.38143e+37f
4887*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0xfe416699), SkBits2Float(0x7e4008bf), SkBits2Float(0xfe4168f1), SkBits2Float(0x7e400668), SkBits2Float(0x3f6c8ed9));  // -6.42684e+37f, 6.38143e+37f, -6.42715e+37f, 6.38113e+37f, 0.924055f
4888*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(SkBits2Float(0xfe416e9a), SkBits2Float(0x7e4000c2), SkBits2Float(0xfe4168f3), SkBits2Float(0x7e3ffb17), SkBits2Float(0x3f3504f3));  // -6.42788e+37f, 6.38039e+37f, -6.42715e+37f, 6.37966e+37f, 0.707107f
4889*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe317061), SkBits2Float(0x7e2ffb07));  // -5.89642e+37f, 5.84796e+37f
4890*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfde2e542), SkBits2Float(0x7ddff58e));  // -3.76995e+37f, 3.72116e+37f
4891*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfd65c525), SkBits2Float(0x7d5fea3d));  // -1.90886e+37f, 1.86021e+37f
4892*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfab6c8db), SkBits2Float(0xf7b50b4f));  // -4.74536e+35f, -7.34402e+33f
4893*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfab59cf2), SkBits2Float(0xf800007e));  // -4.71494e+35f, -1.03847e+34f
4894*c8dee2aaSAndroid Build Coastguard Worker     path.close();
4895*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0xfab3f4db), SkBits2Float(0x43480000));  // -4.67194e+35f, 200
4896*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfab174d9), SkBits2Float(0x43480000));  // -4.60703e+35f, 200
4897*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0xfd0593a5), SkBits2Float(0x7d00007f), SkBits2Float(0xfd659785), SkBits2Float(0x7d6000de));  // -1.10971e+37f, 1.0634e+37f, -1.90737e+37f, 1.86095e+37f
4898*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0xfda2cdf2), SkBits2Float(0x7da0009f), SkBits2Float(0xfdc2ce12), SkBits2Float(0x7dc000be));  // -2.70505e+37f, 2.6585e+37f, -3.23675e+37f, 3.1902e+37f
4899*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0xfde2ce31), SkBits2Float(0x7de000de), SkBits2Float(0xfe0165e9), SkBits2Float(0x7e00007f));  // -3.76845e+37f, 3.72189e+37f, -4.29999e+37f, 4.25359e+37f
4900*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0xfe1164b9), SkBits2Float(0x7e10008f), SkBits2Float(0xfe116239), SkBits2Float(0x7e10008f));  // -4.83153e+37f, 4.78529e+37f, -4.8312e+37f, 4.78529e+37f
4901*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0xfe116039), SkBits2Float(0x7e10008f), SkBits2Float(0xfe095e91), SkBits2Float(0x7e080087));  // -4.83094e+37f, 4.78529e+37f, -4.56488e+37f, 4.51944e+37f
4902*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0xfe015d09), SkBits2Float(0x7e00007f), SkBits2Float(0xfe015b89), SkBits2Float(0x7e00007f));  // -4.29884e+37f, 4.25359e+37f, -4.29864e+37f, 4.25359e+37f
4903*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xfe415bc9), SkBits2Float(0x7e4000be));  // -6.42544e+37f, 6.38039e+37f
4904*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0xfe415da9), SkBits2Float(0x7e4000be), SkBits2Float(0xfe415f69), SkBits2Float(0x7e4000be));  // -6.42568e+37f, 6.38039e+37f, -6.42591e+37f, 6.38039e+37f
4905*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0xfe416149), SkBits2Float(0x7e4000be), SkBits2Float(0xfe416349), SkBits2Float(0x7e4000be));  // -6.42615e+37f, 6.38039e+37f, -6.42641e+37f, 6.38039e+37f
4906*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0xfe416849), SkBits2Float(0x7e4000be), SkBits2Float(0xfe316ab9), SkBits2Float(0x7e3000af));  // -6.42706e+37f, 6.38039e+37f, -5.89569e+37f, 5.84869e+37f
4907*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0xfe216d29), SkBits2Float(0x7e20009f), SkBits2Float(0xfde2d9f2), SkBits2Float(0x7de000de));  // -5.36431e+37f, 5.31699e+37f, -3.76921e+37f, 3.72189e+37f
4908*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0xfda2d9b2), SkBits2Float(0x7da0009f), SkBits2Float(0xfd65ae85), SkBits2Float(0x7d6000de));  // -2.70582e+37f, 2.6585e+37f, -1.90812e+37f, 1.86095e+37f
4909*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0xfd05a9a6), SkBits2Float(0x7d00007f), SkBits2Float(0xfab3f4db), SkBits2Float(0x43480000));  // -1.11043e+37f, 1.0634e+37f, -4.67194e+35f, 200
4910*c8dee2aaSAndroid Build Coastguard Worker     path.close();
4911*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x7f07a445), SkBits2Float(0xff080087));  // 1.80299e+38f, -1.80778e+38f
4912*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0x7f0ba519), SkBits2Float(0xff0c008b), SkBits2Float(0x7f0da5f3), SkBits2Float(0xff0e008d));  // 1.8562e+38f, -1.86095e+38f, 1.88283e+38f, -1.88753e+38f
4913*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0x7f0fa6d5), SkBits2Float(0xff10008f), SkBits2Float(0x7f0fa7bd), SkBits2Float(0xff10008f));  // 1.90946e+38f, -1.91412e+38f, 1.90951e+38f, -1.91412e+38f
4914*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0x7f0faa7d), SkBits2Float(0xff10008f), SkBits2Float(0x7ef75801), SkBits2Float(0xfef800f6));  // 1.90965e+38f, -1.91412e+38f, 1.64388e+38f, -1.64827e+38f
4915*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0x7ecf5b09), SkBits2Float(0xfed000ce), SkBits2Float(0x7e875ac2), SkBits2Float(0xfe880087));  // 1.37811e+38f, -1.38242e+38f, 8.99585e+37f, -9.03889e+37f
4916*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0x7e0eb505), SkBits2Float(0xfe10008f), SkBits2Float(0x7d7ab958), SkBits2Float(0xfd80007f));  // 4.74226e+37f, -4.78529e+37f, 2.08293e+37f, -2.1268e+37f
4917*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0xfc8ac1cd), SkBits2Float(0x7c80007f), SkBits2Float(0xfc8b16cd), SkBits2Float(0x7c80007f));  // -5.76374e+36f, 5.31699e+36f, -5.77753e+36f, 5.31699e+36f
4918*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0xfc8b36cd), SkBits2Float(0x7c80007f), SkBits2Float(0xfc16a51a), SkBits2Float(0x7c00007f));  // -5.78273e+36f, 5.31699e+36f, -3.12877e+36f, 2.6585e+36f
4919*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0xfab6e4de), SkBits2Float(0x43480000), SkBits2Float(0x7c68f062), SkBits2Float(0xfc80007f));  // -4.7482e+35f, 200, 4.83795e+36f, -5.31699e+36f
4920*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7ddd1ecb), SkBits2Float(0xfde000de));  // 3.67399e+37f, -3.72189e+37f
4921*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0x7d9d254b), SkBits2Float(0xfda0009f), SkBits2Float(0x7d8d2bbc), SkBits2Float(0xfd90008f));  // 2.61103e+37f, -2.6585e+37f, 2.3456e+37f, -2.39265e+37f
4922*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0x7d7a64d8), SkBits2Float(0xfd80007f), SkBits2Float(0x7d7a7258), SkBits2Float(0xfd80007f));  // 2.08019e+37f, -2.1268e+37f, 2.08063e+37f, -2.1268e+37f
4923*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0x7d7a9058), SkBits2Float(0xfd80007f), SkBits2Float(0x7ded50db), SkBits2Float(0xfdf000ee));  // 2.0816e+37f, -2.1268e+37f, 3.94309e+37f, -3.98774e+37f
4924*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0x7e2eace5), SkBits2Float(0xfe3000af), SkBits2Float(0x7e8756a2), SkBits2Float(0xfe880087));  // 5.80458e+37f, -5.84869e+37f, 8.99478e+37f, -9.03889e+37f
4925*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0x7ebf56d9), SkBits2Float(0xfec000be), SkBits2Float(0x7edb54d5), SkBits2Float(0xfedc00da));  // 1.27167e+38f, -1.27608e+38f, 1.45771e+38f, -1.46217e+38f
4926*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0x7ef752e1), SkBits2Float(0xfef800f6), SkBits2Float(0x7ef74f21), SkBits2Float(0xfef800f6));  // 1.64375e+38f, -1.64827e+38f, 1.64365e+38f, -1.64827e+38f
4927*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0x7ef74d71), SkBits2Float(0xfef800f6), SkBits2Float(0x7ef34bbd), SkBits2Float(0xfef400f2));  // 1.64361e+38f, -1.64827e+38f, 1.61698e+38f, -1.62168e+38f
4928*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(SkBits2Float(0x7eef4a19), SkBits2Float(0xfef000ee), SkBits2Float(0x7edf4859), SkBits2Float(0xfee000de));  // 1.59035e+38f, -1.5951e+38f, 1.48397e+38f, -1.48876e+38f
4929*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x7f07a445), SkBits2Float(0xff080087));  // 1.80299e+38f, -1.80778e+38f
4930*c8dee2aaSAndroid Build Coastguard Worker     path.close();
4931*c8dee2aaSAndroid Build Coastguard Worker     SkSurfaces::Raster(SkImageInfo::MakeN32Premul(250, 250), nullptr)
4932*c8dee2aaSAndroid Build Coastguard Worker             ->getCanvas()
4933*c8dee2aaSAndroid Build Coastguard Worker             ->drawPath(path, paint);
4934*c8dee2aaSAndroid Build Coastguard Worker }
4935*c8dee2aaSAndroid Build Coastguard Worker 
test_interp(skiatest::Reporter * reporter)4936*c8dee2aaSAndroid Build Coastguard Worker static void test_interp(skiatest::Reporter* reporter) {
4937*c8dee2aaSAndroid Build Coastguard Worker     SkPath p1, p2, out;
4938*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p1.isInterpolatable(p2));
4939*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p1.interpolate(p2, 0, &out));
4940*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p1 == out);
4941*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p1.interpolate(p2, 1, &out));
4942*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p1 == out);
4943*c8dee2aaSAndroid Build Coastguard Worker     p1.moveTo(0, 2);
4944*c8dee2aaSAndroid Build Coastguard Worker     p1.lineTo(0, 4);
4945*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p1.isInterpolatable(p2));
4946*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p1.interpolate(p2, 1, &out));
4947*c8dee2aaSAndroid Build Coastguard Worker     p2.moveTo(6, 0);
4948*c8dee2aaSAndroid Build Coastguard Worker     p2.lineTo(8, 0);
4949*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p1.isInterpolatable(p2));
4950*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p1.interpolate(p2, 0, &out));
4951*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p2 == out);
4952*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p1.interpolate(p2, 1, &out));
4953*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p1 == out);
4954*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p1.interpolate(p2, 0.5f, &out));
4955*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, out.getBounds() == SkRect::MakeLTRB(3, 1, 4, 2));
4956*c8dee2aaSAndroid Build Coastguard Worker     p1.reset();
4957*c8dee2aaSAndroid Build Coastguard Worker     p1.moveTo(4, 4);
4958*c8dee2aaSAndroid Build Coastguard Worker     p1.conicTo(5, 4, 5, 5, 1 / SkScalarSqrt(2));
4959*c8dee2aaSAndroid Build Coastguard Worker     p2.reset();
4960*c8dee2aaSAndroid Build Coastguard Worker     p2.moveTo(4, 2);
4961*c8dee2aaSAndroid Build Coastguard Worker     p2.conicTo(7, 2, 7, 5, 1 / SkScalarSqrt(2));
4962*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p1.isInterpolatable(p2));
4963*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p1.interpolate(p2, 0.5f, &out));
4964*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, out.getBounds() == SkRect::MakeLTRB(4, 3, 6, 5));
4965*c8dee2aaSAndroid Build Coastguard Worker     p2.reset();
4966*c8dee2aaSAndroid Build Coastguard Worker     p2.moveTo(4, 2);
4967*c8dee2aaSAndroid Build Coastguard Worker     p2.conicTo(6, 3, 6, 5, 1);
4968*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p1.isInterpolatable(p2));
4969*c8dee2aaSAndroid Build Coastguard Worker     p2.reset();
4970*c8dee2aaSAndroid Build Coastguard Worker     p2.moveTo(4, 4);
4971*c8dee2aaSAndroid Build Coastguard Worker     p2.conicTo(5, 4, 5, 5, 0.5f);
4972*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p1.isInterpolatable(p2));
4973*c8dee2aaSAndroid Build Coastguard Worker }
4974*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(PathInterp,reporter)4975*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(PathInterp, reporter) {
4976*c8dee2aaSAndroid Build Coastguard Worker     test_interp(reporter);
4977*c8dee2aaSAndroid Build Coastguard Worker }
4978*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(PathBigCubic,reporter)4979*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(PathBigCubic, reporter) {
4980*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
4981*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000));  // 0, 0
4982*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x44000000), SkBits2Float(0x373938b8));  // 512, 1.10401e-05f
4983*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(SkBits2Float(0x00000001), SkBits2Float(0xdf000052), SkBits2Float(0x00000100), SkBits2Float(0x00000000), SkBits2Float(0x00000100), SkBits2Float(0x00000000));  // 1.4013e-45f, -9.22346e+18f, 3.58732e-43f, 0, 3.58732e-43f, 0
4984*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 512);
4985*c8dee2aaSAndroid Build Coastguard Worker 
4986*c8dee2aaSAndroid Build Coastguard Worker     // this call should not assert
4987*c8dee2aaSAndroid Build Coastguard Worker     SkSurfaces::Raster(SkImageInfo::MakeN32Premul(255, 255), nullptr)
4988*c8dee2aaSAndroid Build Coastguard Worker             ->getCanvas()
4989*c8dee2aaSAndroid Build Coastguard Worker             ->drawPath(path, SkPaint());
4990*c8dee2aaSAndroid Build Coastguard Worker }
4991*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(PathContains,reporter)4992*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(PathContains, reporter) {
4993*c8dee2aaSAndroid Build Coastguard Worker     test_contains(reporter);
4994*c8dee2aaSAndroid Build Coastguard Worker }
4995*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(Paths,reporter)4996*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(Paths, reporter) {
4997*c8dee2aaSAndroid Build Coastguard Worker     test_fuzz_crbug_647922();
4998*c8dee2aaSAndroid Build Coastguard Worker     test_fuzz_crbug_643933();
4999*c8dee2aaSAndroid Build Coastguard Worker     test_sect_with_horizontal_needs_pinning();
5000*c8dee2aaSAndroid Build Coastguard Worker     test_iterative_intersect_line();
5001*c8dee2aaSAndroid Build Coastguard Worker     test_crbug_629455(reporter);
5002*c8dee2aaSAndroid Build Coastguard Worker     test_fuzz_crbug_627414(reporter);
5003*c8dee2aaSAndroid Build Coastguard Worker     test_path_crbug364224();
5004*c8dee2aaSAndroid Build Coastguard Worker     test_fuzz_crbug_662952(reporter);
5005*c8dee2aaSAndroid Build Coastguard Worker     test_fuzz_crbug_662730(reporter);
5006*c8dee2aaSAndroid Build Coastguard Worker     test_fuzz_crbug_662780();
5007*c8dee2aaSAndroid Build Coastguard Worker     test_mask_overflow();
5008*c8dee2aaSAndroid Build Coastguard Worker     test_path_crbugskia6003();
5009*c8dee2aaSAndroid Build Coastguard Worker     test_fuzz_crbug_668907();
5010*c8dee2aaSAndroid Build Coastguard Worker     test_skbug_6947();
5011*c8dee2aaSAndroid Build Coastguard Worker     test_skbug_7015();
5012*c8dee2aaSAndroid Build Coastguard Worker     test_skbug_7051();
5013*c8dee2aaSAndroid Build Coastguard Worker     test_skbug_7435();
5014*c8dee2aaSAndroid Build Coastguard Worker 
5015*c8dee2aaSAndroid Build Coastguard Worker     SkSize::Make(3, 4);
5016*c8dee2aaSAndroid Build Coastguard Worker 
5017*c8dee2aaSAndroid Build Coastguard Worker     SkPath  p, empty;
5018*c8dee2aaSAndroid Build Coastguard Worker     SkRect  bounds, bounds2;
5019*c8dee2aaSAndroid Build Coastguard Worker     test_empty(reporter, p);
5020*c8dee2aaSAndroid Build Coastguard Worker 
5021*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.getBounds().isEmpty());
5022*c8dee2aaSAndroid Build Coastguard Worker 
5023*c8dee2aaSAndroid Build Coastguard Worker     // this triggers a code path in SkPath::operator= which is otherwise unexercised
5024*c8dee2aaSAndroid Build Coastguard Worker     SkPath& self = p;
5025*c8dee2aaSAndroid Build Coastguard Worker     p = self;
5026*c8dee2aaSAndroid Build Coastguard Worker 
5027*c8dee2aaSAndroid Build Coastguard Worker     // this triggers a code path in SkPath::swap which is otherwise unexercised
5028*c8dee2aaSAndroid Build Coastguard Worker     p.swap(self);
5029*c8dee2aaSAndroid Build Coastguard Worker 
5030*c8dee2aaSAndroid Build Coastguard Worker     bounds.setLTRB(0, 0, SK_Scalar1, SK_Scalar1);
5031*c8dee2aaSAndroid Build Coastguard Worker 
5032*c8dee2aaSAndroid Build Coastguard Worker     p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1);
5033*c8dee2aaSAndroid Build Coastguard Worker     check_convex_bounds(reporter, p, bounds);
5034*c8dee2aaSAndroid Build Coastguard Worker     // we have quads or cubics
5035*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter,
5036*c8dee2aaSAndroid Build Coastguard Worker                     p.getSegmentMasks() & (kCurveSegmentMask | SkPath::kConic_SegmentMask));
5037*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.isEmpty());
5038*c8dee2aaSAndroid Build Coastguard Worker 
5039*c8dee2aaSAndroid Build Coastguard Worker     p.reset();
5040*c8dee2aaSAndroid Build Coastguard Worker     test_empty(reporter, p);
5041*c8dee2aaSAndroid Build Coastguard Worker 
5042*c8dee2aaSAndroid Build Coastguard Worker     p.addOval(bounds);
5043*c8dee2aaSAndroid Build Coastguard Worker     check_convex_bounds(reporter, p, bounds);
5044*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.isEmpty());
5045*c8dee2aaSAndroid Build Coastguard Worker 
5046*c8dee2aaSAndroid Build Coastguard Worker     p.rewind();
5047*c8dee2aaSAndroid Build Coastguard Worker     test_empty(reporter, p);
5048*c8dee2aaSAndroid Build Coastguard Worker 
5049*c8dee2aaSAndroid Build Coastguard Worker     p.addRect(bounds);
5050*c8dee2aaSAndroid Build Coastguard Worker     check_convex_bounds(reporter, p, bounds);
5051*c8dee2aaSAndroid Build Coastguard Worker     // we have only lines
5052*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == p.getSegmentMasks());
5053*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.isEmpty());
5054*c8dee2aaSAndroid Build Coastguard Worker 
5055*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p != empty);
5056*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !(p == empty));
5057*c8dee2aaSAndroid Build Coastguard Worker 
5058*c8dee2aaSAndroid Build Coastguard Worker     // do getPoints and getVerbs return the right result
5059*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.getPoints(nullptr, 0) == 4);
5060*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.getVerbs(nullptr, 0) == 5);
5061*c8dee2aaSAndroid Build Coastguard Worker     SkPoint pts[4];
5062*c8dee2aaSAndroid Build Coastguard Worker     int count = p.getPoints(pts, 4);
5063*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, count == 4);
5064*c8dee2aaSAndroid Build Coastguard Worker     uint8_t verbs[6];
5065*c8dee2aaSAndroid Build Coastguard Worker     verbs[5] = 0xff;
5066*c8dee2aaSAndroid Build Coastguard Worker     p.getVerbs(verbs, 5);
5067*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
5068*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[1]);
5069*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[2]);
5070*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[3]);
5071*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPath::kClose_Verb == verbs[4]);
5072*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, 0xff == verbs[5]);
5073*c8dee2aaSAndroid Build Coastguard Worker     bounds2.setBounds(pts, 4);
5074*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, bounds == bounds2);
5075*c8dee2aaSAndroid Build Coastguard Worker 
5076*c8dee2aaSAndroid Build Coastguard Worker     bounds.offset(SK_Scalar1*3, SK_Scalar1*4);
5077*c8dee2aaSAndroid Build Coastguard Worker     p.offset(SK_Scalar1*3, SK_Scalar1*4);
5078*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, bounds == p.getBounds());
5079*c8dee2aaSAndroid Build Coastguard Worker 
5080*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.isRect(nullptr));
5081*c8dee2aaSAndroid Build Coastguard Worker     bounds2.setEmpty();
5082*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, p.isRect(&bounds2));
5083*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, bounds == bounds2);
5084*c8dee2aaSAndroid Build Coastguard Worker 
5085*c8dee2aaSAndroid Build Coastguard Worker     // now force p to not be a rect
5086*c8dee2aaSAndroid Build Coastguard Worker     bounds.setWH(SK_Scalar1/2, SK_Scalar1/2);
5087*c8dee2aaSAndroid Build Coastguard Worker     p.addRect(bounds);
5088*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !p.isRect(nullptr));
5089*c8dee2aaSAndroid Build Coastguard Worker 
5090*c8dee2aaSAndroid Build Coastguard Worker     // Test an edge case w.r.t. the bound returned by isRect (i.e., the
5091*c8dee2aaSAndroid Build Coastguard Worker     // path has a trailing moveTo. Please see crbug.com\445368)
5092*c8dee2aaSAndroid Build Coastguard Worker     {
5093*c8dee2aaSAndroid Build Coastguard Worker         SkRect r;
5094*c8dee2aaSAndroid Build Coastguard Worker         p.reset();
5095*c8dee2aaSAndroid Build Coastguard Worker         p.addRect(bounds);
5096*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, p.isRect(&r));
5097*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, r == bounds);
5098*c8dee2aaSAndroid Build Coastguard Worker         // add a moveTo outside of our bounds
5099*c8dee2aaSAndroid Build Coastguard Worker         p.moveTo(bounds.fLeft + 10, bounds.fBottom + 10);
5100*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, p.isRect(&r));
5101*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, r == bounds);
5102*c8dee2aaSAndroid Build Coastguard Worker     }
5103*c8dee2aaSAndroid Build Coastguard Worker 
5104*c8dee2aaSAndroid Build Coastguard Worker     test_operatorEqual(reporter);
5105*c8dee2aaSAndroid Build Coastguard Worker     test_isLine(reporter);
5106*c8dee2aaSAndroid Build Coastguard Worker     test_isRect(reporter);
5107*c8dee2aaSAndroid Build Coastguard Worker     test_is_closed_rect(reporter);
5108*c8dee2aaSAndroid Build Coastguard Worker     test_isNestedFillRects(reporter);
5109*c8dee2aaSAndroid Build Coastguard Worker     test_isArc(reporter);
5110*c8dee2aaSAndroid Build Coastguard Worker     test_zero_length_paths(reporter);
5111*c8dee2aaSAndroid Build Coastguard Worker     test_direction(reporter);
5112*c8dee2aaSAndroid Build Coastguard Worker     test_convexity(reporter);
5113*c8dee2aaSAndroid Build Coastguard Worker     test_convexity2(reporter);
5114*c8dee2aaSAndroid Build Coastguard Worker     test_convexity_doubleback(reporter);
5115*c8dee2aaSAndroid Build Coastguard Worker     test_conservativelyContains(reporter);
5116*c8dee2aaSAndroid Build Coastguard Worker     test_close(reporter);
5117*c8dee2aaSAndroid Build Coastguard Worker     test_segment_masks(reporter);
5118*c8dee2aaSAndroid Build Coastguard Worker     test_flattening(reporter);
5119*c8dee2aaSAndroid Build Coastguard Worker     test_transform(reporter);
5120*c8dee2aaSAndroid Build Coastguard Worker     test_bounds(reporter);
5121*c8dee2aaSAndroid Build Coastguard Worker     test_iter(reporter);
5122*c8dee2aaSAndroid Build Coastguard Worker     test_range_iter(reporter);
5123*c8dee2aaSAndroid Build Coastguard Worker     test_circle(reporter);
5124*c8dee2aaSAndroid Build Coastguard Worker     test_oval(reporter);
5125*c8dee2aaSAndroid Build Coastguard Worker     test_strokerec(reporter);
5126*c8dee2aaSAndroid Build Coastguard Worker     test_addPoly(reporter);
5127*c8dee2aaSAndroid Build Coastguard Worker     test_isfinite(reporter);
5128*c8dee2aaSAndroid Build Coastguard Worker     test_isfinite_after_transform(reporter);
5129*c8dee2aaSAndroid Build Coastguard Worker     test_islastcontourclosed(reporter);
5130*c8dee2aaSAndroid Build Coastguard Worker     test_arb_round_rect_is_convex(reporter);
5131*c8dee2aaSAndroid Build Coastguard Worker     test_arb_zero_rad_round_rect_is_rect(reporter);
5132*c8dee2aaSAndroid Build Coastguard Worker     test_addrect(reporter);
5133*c8dee2aaSAndroid Build Coastguard Worker     test_addrect_isfinite(reporter);
5134*c8dee2aaSAndroid Build Coastguard Worker     test_tricky_cubic();
5135*c8dee2aaSAndroid Build Coastguard Worker     test_clipped_cubic();
5136*c8dee2aaSAndroid Build Coastguard Worker     test_crbug_170666();
5137*c8dee2aaSAndroid Build Coastguard Worker     test_crbug_493450(reporter);
5138*c8dee2aaSAndroid Build Coastguard Worker     test_crbug_495894(reporter);
5139*c8dee2aaSAndroid Build Coastguard Worker     test_crbug_613918();
5140*c8dee2aaSAndroid Build Coastguard Worker     test_bad_cubic_crbug229478();
5141*c8dee2aaSAndroid Build Coastguard Worker     test_bad_cubic_crbug234190();
5142*c8dee2aaSAndroid Build Coastguard Worker     test_gen_id(reporter);
5143*c8dee2aaSAndroid Build Coastguard Worker     test_path_close_issue1474(reporter);
5144*c8dee2aaSAndroid Build Coastguard Worker     test_path_to_region(reporter);
5145*c8dee2aaSAndroid Build Coastguard Worker     test_rrect(reporter);
5146*c8dee2aaSAndroid Build Coastguard Worker     test_rMoveTo(reporter);
5147*c8dee2aaSAndroid Build Coastguard Worker     test_arc(reporter);
5148*c8dee2aaSAndroid Build Coastguard Worker     test_arc_ovals(reporter);
5149*c8dee2aaSAndroid Build Coastguard Worker     test_arcTo(reporter);
5150*c8dee2aaSAndroid Build Coastguard Worker     test_addPath(reporter);
5151*c8dee2aaSAndroid Build Coastguard Worker     test_addPathMode(reporter, false, false);
5152*c8dee2aaSAndroid Build Coastguard Worker     test_addPathMode(reporter, true, false);
5153*c8dee2aaSAndroid Build Coastguard Worker     test_addPathMode(reporter, false, true);
5154*c8dee2aaSAndroid Build Coastguard Worker     test_addPathMode(reporter, true, true);
5155*c8dee2aaSAndroid Build Coastguard Worker     test_extendClosedPath(reporter);
5156*c8dee2aaSAndroid Build Coastguard Worker     test_addEmptyPath(reporter, SkPath::kExtend_AddPathMode);
5157*c8dee2aaSAndroid Build Coastguard Worker     test_addEmptyPath(reporter, SkPath::kAppend_AddPathMode);
5158*c8dee2aaSAndroid Build Coastguard Worker     test_conicTo_special_case(reporter);
5159*c8dee2aaSAndroid Build Coastguard Worker     test_get_point(reporter);
5160*c8dee2aaSAndroid Build Coastguard Worker     test_contains(reporter);
5161*c8dee2aaSAndroid Build Coastguard Worker     PathTest_Private::TestPathTo(reporter);
5162*c8dee2aaSAndroid Build Coastguard Worker     PathRefTest_Private::TestPathRef(reporter);
5163*c8dee2aaSAndroid Build Coastguard Worker     PathTest_Private::TestPathrefListeners(reporter);
5164*c8dee2aaSAndroid Build Coastguard Worker     test_dump(reporter);
5165*c8dee2aaSAndroid Build Coastguard Worker     test_path_crbug389050(reporter);
5166*c8dee2aaSAndroid Build Coastguard Worker     test_path_crbugskia2820(reporter);
5167*c8dee2aaSAndroid Build Coastguard Worker     test_path_crbugskia5995();
5168*c8dee2aaSAndroid Build Coastguard Worker     test_skbug_3469(reporter);
5169*c8dee2aaSAndroid Build Coastguard Worker     test_skbug_3239(reporter);
5170*c8dee2aaSAndroid Build Coastguard Worker     test_bounds_crbug_513799(reporter);
5171*c8dee2aaSAndroid Build Coastguard Worker     test_fuzz_crbug_638223();
5172*c8dee2aaSAndroid Build Coastguard Worker }
5173*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(conservatively_contains_rect,reporter)5174*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(conservatively_contains_rect, reporter) {
5175*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
5176*c8dee2aaSAndroid Build Coastguard Worker 
5177*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x44000000), SkBits2Float(0x373938b8));  // 512, 1.10401e-05f
5178*c8dee2aaSAndroid Build Coastguard Worker     // 1.4013e-45f, -9.22346e+18f, 3.58732e-43f, 0, 3.58732e-43f, 0
5179*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(SkBits2Float(0x00000001), SkBits2Float(0xdf000052),
5180*c8dee2aaSAndroid Build Coastguard Worker                  SkBits2Float(0x00000100), SkBits2Float(0x00000000),
5181*c8dee2aaSAndroid Build Coastguard Worker                  SkBits2Float(0x00000100), SkBits2Float(0x00000000));
5182*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0);
5183*c8dee2aaSAndroid Build Coastguard Worker 
5184*c8dee2aaSAndroid Build Coastguard Worker     // this should not assert
5185*c8dee2aaSAndroid Build Coastguard Worker     path.conservativelyContainsRect({ -211747, 12.1115f, -197893, 25.0321f });
5186*c8dee2aaSAndroid Build Coastguard Worker }
5187*c8dee2aaSAndroid Build Coastguard Worker 
5188*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
5189*c8dee2aaSAndroid Build Coastguard Worker 
rand_path(SkPath * path,SkRandom & rand,SkPath::Verb verb,int n)5190*c8dee2aaSAndroid Build Coastguard Worker static void rand_path(SkPath* path, SkRandom& rand, SkPath::Verb verb, int n) {
5191*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < n; ++i) {
5192*c8dee2aaSAndroid Build Coastguard Worker         switch (verb) {
5193*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kLine_Verb:
5194*c8dee2aaSAndroid Build Coastguard Worker                 path->lineTo(rand.nextF()*100, rand.nextF()*100);
5195*c8dee2aaSAndroid Build Coastguard Worker                 break;
5196*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kQuad_Verb:
5197*c8dee2aaSAndroid Build Coastguard Worker                 path->quadTo(rand.nextF()*100, rand.nextF()*100,
5198*c8dee2aaSAndroid Build Coastguard Worker                              rand.nextF()*100, rand.nextF()*100);
5199*c8dee2aaSAndroid Build Coastguard Worker                 break;
5200*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kConic_Verb:
5201*c8dee2aaSAndroid Build Coastguard Worker                 path->conicTo(rand.nextF()*100, rand.nextF()*100,
5202*c8dee2aaSAndroid Build Coastguard Worker                               rand.nextF()*100, rand.nextF()*100, rand.nextF()*10);
5203*c8dee2aaSAndroid Build Coastguard Worker                 break;
5204*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kCubic_Verb:
5205*c8dee2aaSAndroid Build Coastguard Worker                 path->cubicTo(rand.nextF()*100, rand.nextF()*100,
5206*c8dee2aaSAndroid Build Coastguard Worker                               rand.nextF()*100, rand.nextF()*100,
5207*c8dee2aaSAndroid Build Coastguard Worker                               rand.nextF()*100, rand.nextF()*100);
5208*c8dee2aaSAndroid Build Coastguard Worker                 break;
5209*c8dee2aaSAndroid Build Coastguard Worker             default:
5210*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(false);
5211*c8dee2aaSAndroid Build Coastguard Worker         }
5212*c8dee2aaSAndroid Build Coastguard Worker     }
5213*c8dee2aaSAndroid Build Coastguard Worker }
5214*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(path_tight_bounds,reporter)5215*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(path_tight_bounds, reporter) {
5216*c8dee2aaSAndroid Build Coastguard Worker     SkRandom rand;
5217*c8dee2aaSAndroid Build Coastguard Worker 
5218*c8dee2aaSAndroid Build Coastguard Worker     const SkPath::Verb verbs[] = {
5219*c8dee2aaSAndroid Build Coastguard Worker         SkPath::kLine_Verb, SkPath::kQuad_Verb, SkPath::kConic_Verb, SkPath::kCubic_Verb,
5220*c8dee2aaSAndroid Build Coastguard Worker     };
5221*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 1000; ++i) {
5222*c8dee2aaSAndroid Build Coastguard Worker         for (int n = 1; n <= 10; n += 9) {
5223*c8dee2aaSAndroid Build Coastguard Worker             for (SkPath::Verb verb : verbs) {
5224*c8dee2aaSAndroid Build Coastguard Worker                 SkPath path;
5225*c8dee2aaSAndroid Build Coastguard Worker                 rand_path(&path, rand, verb, n);
5226*c8dee2aaSAndroid Build Coastguard Worker                 SkRect bounds = path.getBounds();
5227*c8dee2aaSAndroid Build Coastguard Worker                 SkRect tight = path.computeTightBounds();
5228*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, bounds.contains(tight));
5229*c8dee2aaSAndroid Build Coastguard Worker 
5230*c8dee2aaSAndroid Build Coastguard Worker                 SkRect tight2;
5231*c8dee2aaSAndroid Build Coastguard Worker                 TightBounds(path, &tight2);
5232*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, nearly_equal(tight, tight2));
5233*c8dee2aaSAndroid Build Coastguard Worker             }
5234*c8dee2aaSAndroid Build Coastguard Worker         }
5235*c8dee2aaSAndroid Build Coastguard Worker     }
5236*c8dee2aaSAndroid Build Coastguard Worker }
5237*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(skbug_6450,r)5238*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(skbug_6450, r) {
5239*c8dee2aaSAndroid Build Coastguard Worker     SkRect ri = { 0.18554693f, 195.26283f, 0.185784385f, 752.644409f };
5240*c8dee2aaSAndroid Build Coastguard Worker     SkVector rdi[4] = {
5241*c8dee2aaSAndroid Build Coastguard Worker         { 1.81159976e-09f, 7.58768801e-05f },
5242*c8dee2aaSAndroid Build Coastguard Worker         { 0.000118725002f, 0.000118725002f },
5243*c8dee2aaSAndroid Build Coastguard Worker         { 0.000118725002f, 0.000118725002f },
5244*c8dee2aaSAndroid Build Coastguard Worker         { 0.000118725002f, 0.486297607f }
5245*c8dee2aaSAndroid Build Coastguard Worker     };
5246*c8dee2aaSAndroid Build Coastguard Worker     SkRRect irr;
5247*c8dee2aaSAndroid Build Coastguard Worker     irr.setRectRadii(ri, rdi);
5248*c8dee2aaSAndroid Build Coastguard Worker     SkRect ro = { 9.18354821e-39f, 2.1710848e+9f, 2.16945843e+9f, 3.47808128e+9f };
5249*c8dee2aaSAndroid Build Coastguard Worker     SkVector rdo[4] = {
5250*c8dee2aaSAndroid Build Coastguard Worker         { 0, 0 },
5251*c8dee2aaSAndroid Build Coastguard Worker         { 0.0103298295f, 0.185887396f },
5252*c8dee2aaSAndroid Build Coastguard Worker         { 2.52999727e-29f, 169.001938f },
5253*c8dee2aaSAndroid Build Coastguard Worker         { 195.262741f, 195.161255f }
5254*c8dee2aaSAndroid Build Coastguard Worker     };
5255*c8dee2aaSAndroid Build Coastguard Worker     SkRRect orr;
5256*c8dee2aaSAndroid Build Coastguard Worker     orr.setRectRadii(ro, rdo);
5257*c8dee2aaSAndroid Build Coastguard Worker     SkMakeNullCanvas()->drawDRRect(orr, irr, SkPaint());
5258*c8dee2aaSAndroid Build Coastguard Worker }
5259*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(PathRefSerialization,reporter)5260*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(PathRefSerialization, reporter) {
5261*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
5262*c8dee2aaSAndroid Build Coastguard Worker     const size_t numMoves = 5;
5263*c8dee2aaSAndroid Build Coastguard Worker     const size_t numConics = 7;
5264*c8dee2aaSAndroid Build Coastguard Worker     const size_t numPoints = numMoves + 2 * numConics;
5265*c8dee2aaSAndroid Build Coastguard Worker     const size_t numVerbs = numMoves + numConics;
5266*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < numMoves; ++i) path.moveTo(1, 2);
5267*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < numConics; ++i) path.conicTo(1, 2, 3, 4, 5);
5268*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.countPoints() == numPoints);
5269*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.countVerbs() == numVerbs);
5270*c8dee2aaSAndroid Build Coastguard Worker 
5271*c8dee2aaSAndroid Build Coastguard Worker     // Verify that path serializes/deserializes properly.
5272*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkData> data = path.serialize();
5273*c8dee2aaSAndroid Build Coastguard Worker     size_t bytesWritten = data->size();
5274*c8dee2aaSAndroid Build Coastguard Worker 
5275*c8dee2aaSAndroid Build Coastguard Worker     {
5276*c8dee2aaSAndroid Build Coastguard Worker         SkPath readBack;
5277*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, readBack != path);
5278*c8dee2aaSAndroid Build Coastguard Worker         size_t bytesRead = readBack.readFromMemory(data->data(), bytesWritten);
5279*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, bytesRead == bytesWritten);
5280*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, readBack == path);
5281*c8dee2aaSAndroid Build Coastguard Worker     }
5282*c8dee2aaSAndroid Build Coastguard Worker 
5283*c8dee2aaSAndroid Build Coastguard Worker     // One less byte (rounded down to alignment) than was written will also
5284*c8dee2aaSAndroid Build Coastguard Worker     // fail to be deserialized.
5285*c8dee2aaSAndroid Build Coastguard Worker     {
5286*c8dee2aaSAndroid Build Coastguard Worker         SkPath readBack;
5287*c8dee2aaSAndroid Build Coastguard Worker         size_t bytesRead = readBack.readFromMemory(data->data(), bytesWritten - 4);
5288*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !bytesRead);
5289*c8dee2aaSAndroid Build Coastguard Worker     }
5290*c8dee2aaSAndroid Build Coastguard Worker }
5291*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(NonFinitePathIteration,reporter)5292*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(NonFinitePathIteration, reporter) {
5293*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
5294*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SK_ScalarInfinity, SK_ScalarInfinity);
5295*c8dee2aaSAndroid Build Coastguard Worker     SkPathPriv::Iterate iterate(path);
5296*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, iterate.begin() == iterate.end());
5297*c8dee2aaSAndroid Build Coastguard Worker }
5298*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(AndroidArc,reporter)5299*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(AndroidArc, reporter) {
5300*c8dee2aaSAndroid Build Coastguard Worker     const char* tests[] = {
5301*c8dee2aaSAndroid Build Coastguard Worker          "M50,0A50,50,0,0 1 100,50 L100,85 A15,15,0,0 1 85,100 L50,100 A50,50,0,0 1 50,0z",
5302*c8dee2aaSAndroid Build Coastguard Worker         ("M50,0L92,0 A8,8,0,0 1 100,8 L100,92 A8,8,0,0 1 92,100 L8,100"
5303*c8dee2aaSAndroid Build Coastguard Worker             " A8,8,0,0 1 0,92 L 0,8 A8,8,0,0 1 8,0z"),
5304*c8dee2aaSAndroid Build Coastguard Worker          "M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0"
5305*c8dee2aaSAndroid Build Coastguard Worker     };
5306*c8dee2aaSAndroid Build Coastguard Worker     for (auto test : tests) {
5307*c8dee2aaSAndroid Build Coastguard Worker         SkPath aPath;
5308*c8dee2aaSAndroid Build Coastguard Worker         SkAssertResult(SkParsePath::FromSVGString(test, &aPath));
5309*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(aPath.isConvex());
5310*c8dee2aaSAndroid Build Coastguard Worker         for (SkScalar scale = 1; scale < 1000; scale *= 1.1f) {
5311*c8dee2aaSAndroid Build Coastguard Worker             SkPath scalePath = aPath;
5312*c8dee2aaSAndroid Build Coastguard Worker             SkMatrix matrix;
5313*c8dee2aaSAndroid Build Coastguard Worker             matrix.setScale(scale, scale);
5314*c8dee2aaSAndroid Build Coastguard Worker             scalePath.transform(matrix);
5315*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(scalePath.isConvex());
5316*c8dee2aaSAndroid Build Coastguard Worker         }
5317*c8dee2aaSAndroid Build Coastguard Worker         for (SkScalar scale = 1; scale < .001; scale /= 1.1f) {
5318*c8dee2aaSAndroid Build Coastguard Worker             SkPath scalePath = aPath;
5319*c8dee2aaSAndroid Build Coastguard Worker             SkMatrix matrix;
5320*c8dee2aaSAndroid Build Coastguard Worker             matrix.setScale(scale, scale);
5321*c8dee2aaSAndroid Build Coastguard Worker             scalePath.transform(matrix);
5322*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(scalePath.isConvex());
5323*c8dee2aaSAndroid Build Coastguard Worker         }
5324*c8dee2aaSAndroid Build Coastguard Worker     }
5325*c8dee2aaSAndroid Build Coastguard Worker }
5326*c8dee2aaSAndroid Build Coastguard Worker 
5327*c8dee2aaSAndroid Build Coastguard Worker /*
5328*c8dee2aaSAndroid Build Coastguard Worker  *  Try a range of crazy values, just to ensure that we don't assert/crash.
5329*c8dee2aaSAndroid Build Coastguard Worker  */
DEF_TEST(HugeGeometry,reporter)5330*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(HugeGeometry, reporter) {
5331*c8dee2aaSAndroid Build Coastguard Worker     auto surf = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100));
5332*c8dee2aaSAndroid Build Coastguard Worker     auto canvas = surf->getCanvas();
5333*c8dee2aaSAndroid Build Coastguard Worker 
5334*c8dee2aaSAndroid Build Coastguard Worker     const bool aas[] = { false, true };
5335*c8dee2aaSAndroid Build Coastguard Worker     const SkPaint::Style styles[] = {
5336*c8dee2aaSAndroid Build Coastguard Worker         SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style
5337*c8dee2aaSAndroid Build Coastguard Worker     };
5338*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar values[] = {
5339*c8dee2aaSAndroid Build Coastguard Worker         0, 1, 1000, 1000 * 1000, 1000.f * 1000 * 10000, SK_ScalarMax / 2, SK_ScalarMax,
5340*c8dee2aaSAndroid Build Coastguard Worker         SK_ScalarInfinity
5341*c8dee2aaSAndroid Build Coastguard Worker     };
5342*c8dee2aaSAndroid Build Coastguard Worker 
5343*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
5344*c8dee2aaSAndroid Build Coastguard Worker     for (auto x : values) {
5345*c8dee2aaSAndroid Build Coastguard Worker         SkRect r = { -x, -x, x, x };
5346*c8dee2aaSAndroid Build Coastguard Worker         for (auto width : values) {
5347*c8dee2aaSAndroid Build Coastguard Worker             paint.setStrokeWidth(width);
5348*c8dee2aaSAndroid Build Coastguard Worker             for (auto aa : aas) {
5349*c8dee2aaSAndroid Build Coastguard Worker                 paint.setAntiAlias(aa);
5350*c8dee2aaSAndroid Build Coastguard Worker                 for (auto style : styles) {
5351*c8dee2aaSAndroid Build Coastguard Worker                     paint.setStyle(style);
5352*c8dee2aaSAndroid Build Coastguard Worker                     canvas->drawRect(r, paint);
5353*c8dee2aaSAndroid Build Coastguard Worker                     canvas->drawOval(r, paint);
5354*c8dee2aaSAndroid Build Coastguard Worker                 }
5355*c8dee2aaSAndroid Build Coastguard Worker             }
5356*c8dee2aaSAndroid Build Coastguard Worker         }
5357*c8dee2aaSAndroid Build Coastguard Worker     }
5358*c8dee2aaSAndroid Build Coastguard Worker 
5359*c8dee2aaSAndroid Build Coastguard Worker }
5360*c8dee2aaSAndroid Build Coastguard Worker 
5361*c8dee2aaSAndroid Build Coastguard Worker // Treat nonfinite paths as "empty" or "full", depending on inverse-filltype
DEF_TEST(ClipPath_nonfinite,reporter)5362*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(ClipPath_nonfinite, reporter) {
5363*c8dee2aaSAndroid Build Coastguard Worker     auto surf = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(10, 10));
5364*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = surf->getCanvas();
5365*c8dee2aaSAndroid Build Coastguard Worker 
5366*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !canvas->isClipEmpty());
5367*c8dee2aaSAndroid Build Coastguard Worker     for (bool aa : {false, true}) {
5368*c8dee2aaSAndroid Build Coastguard Worker         for (auto ft : {SkPathFillType::kWinding, SkPathFillType::kInverseWinding}) {
5369*c8dee2aaSAndroid Build Coastguard Worker             for (SkScalar bad : {SK_ScalarInfinity, SK_ScalarNaN}) {
5370*c8dee2aaSAndroid Build Coastguard Worker                 for (int bits = 1; bits <= 15; ++bits) {
5371*c8dee2aaSAndroid Build Coastguard Worker                     SkPoint p0 = { 0, 0 };
5372*c8dee2aaSAndroid Build Coastguard Worker                     SkPoint p1 = { 0, 0 };
5373*c8dee2aaSAndroid Build Coastguard Worker                     if (bits & 1) p0.fX = -bad;
5374*c8dee2aaSAndroid Build Coastguard Worker                     if (bits & 2) p0.fY = -bad;
5375*c8dee2aaSAndroid Build Coastguard Worker                     if (bits & 4) p1.fX = bad;
5376*c8dee2aaSAndroid Build Coastguard Worker                     if (bits & 8) p1.fY = bad;
5377*c8dee2aaSAndroid Build Coastguard Worker 
5378*c8dee2aaSAndroid Build Coastguard Worker                     SkPath path;
5379*c8dee2aaSAndroid Build Coastguard Worker                     path.moveTo(p0);
5380*c8dee2aaSAndroid Build Coastguard Worker                     path.lineTo(p1);
5381*c8dee2aaSAndroid Build Coastguard Worker                     path.setFillType(ft);
5382*c8dee2aaSAndroid Build Coastguard Worker                     canvas->save();
5383*c8dee2aaSAndroid Build Coastguard Worker                     canvas->clipPath(path, aa);
5384*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(reporter, canvas->isClipEmpty() == !path.isInverseFillType());
5385*c8dee2aaSAndroid Build Coastguard Worker                     canvas->restore();
5386*c8dee2aaSAndroid Build Coastguard Worker                 }
5387*c8dee2aaSAndroid Build Coastguard Worker             }
5388*c8dee2aaSAndroid Build Coastguard Worker         }
5389*c8dee2aaSAndroid Build Coastguard Worker     }
5390*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !canvas->isClipEmpty());
5391*c8dee2aaSAndroid Build Coastguard Worker }
5392*c8dee2aaSAndroid Build Coastguard Worker 
5393*c8dee2aaSAndroid Build Coastguard Worker // skbug.com/7792
DEF_TEST(Path_isRect,reporter)5394*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(Path_isRect, reporter) {
5395*c8dee2aaSAndroid Build Coastguard Worker     auto makePath = [](const SkPoint* points, size_t count, bool close) -> SkPath {
5396*c8dee2aaSAndroid Build Coastguard Worker         SkPath path;
5397*c8dee2aaSAndroid Build Coastguard Worker         for (size_t index = 0; index < count; ++index) {
5398*c8dee2aaSAndroid Build Coastguard Worker             index < 2 ? path.moveTo(points[index]) : path.lineTo(points[index]);
5399*c8dee2aaSAndroid Build Coastguard Worker         }
5400*c8dee2aaSAndroid Build Coastguard Worker         if (close) {
5401*c8dee2aaSAndroid Build Coastguard Worker             path.close();
5402*c8dee2aaSAndroid Build Coastguard Worker         }
5403*c8dee2aaSAndroid Build Coastguard Worker         return path;
5404*c8dee2aaSAndroid Build Coastguard Worker     };
5405*c8dee2aaSAndroid Build Coastguard Worker     auto makePath2 = [](const SkPoint* points, const SkPath::Verb* verbs, size_t count) -> SkPath {
5406*c8dee2aaSAndroid Build Coastguard Worker         SkPath path;
5407*c8dee2aaSAndroid Build Coastguard Worker         for (size_t index = 0; index < count; ++index) {
5408*c8dee2aaSAndroid Build Coastguard Worker             switch (verbs[index]) {
5409*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kMove_Verb:
5410*c8dee2aaSAndroid Build Coastguard Worker                     path.moveTo(*points++);
5411*c8dee2aaSAndroid Build Coastguard Worker                     break;
5412*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kLine_Verb:
5413*c8dee2aaSAndroid Build Coastguard Worker                     path.lineTo(*points++);
5414*c8dee2aaSAndroid Build Coastguard Worker                     break;
5415*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kClose_Verb:
5416*c8dee2aaSAndroid Build Coastguard Worker                     path.close();
5417*c8dee2aaSAndroid Build Coastguard Worker                     break;
5418*c8dee2aaSAndroid Build Coastguard Worker                 default:
5419*c8dee2aaSAndroid Build Coastguard Worker                     SkASSERT(0);
5420*c8dee2aaSAndroid Build Coastguard Worker             }
5421*c8dee2aaSAndroid Build Coastguard Worker         }
5422*c8dee2aaSAndroid Build Coastguard Worker         return path;
5423*c8dee2aaSAndroid Build Coastguard Worker     };
5424*c8dee2aaSAndroid Build Coastguard Worker     // isolated from skbug.com/7792 (bug description)
5425*c8dee2aaSAndroid Build Coastguard Worker     SkRect rect;
5426*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points[] = { {10, 10}, {75, 75}, {150, 75}, {150, 150}, {75, 150} };
5427*c8dee2aaSAndroid Build Coastguard Worker     SkPath path = makePath(points, std::size(points), false);
5428*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isRect(&rect));
5429*c8dee2aaSAndroid Build Coastguard Worker     SkRect compare;
5430*c8dee2aaSAndroid Build Coastguard Worker     compare.setBounds(&points[1], std::size(points) - 1);
5431*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rect == compare);
5432*c8dee2aaSAndroid Build Coastguard Worker     // isolated from skbug.com/7792#c3
5433*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points3[] = { {75, 50}, {100, 75}, {150, 75}, {150, 150}, {75, 150}, {75, 50} };
5434*c8dee2aaSAndroid Build Coastguard Worker     path = makePath(points3, std::size(points3), true);
5435*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isRect(&rect));
5436*c8dee2aaSAndroid Build Coastguard Worker     // isolated from skbug.com/7792#c9
5437*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points9[] = { {10, 10}, {75, 75}, {150, 75}, {150, 150}, {75, 150} };
5438*c8dee2aaSAndroid Build Coastguard Worker     path = makePath(points9, std::size(points9), true);
5439*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isRect(&rect));
5440*c8dee2aaSAndroid Build Coastguard Worker     compare.setBounds(&points9[1], std::size(points9) - 1);
5441*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rect == compare);
5442*c8dee2aaSAndroid Build Coastguard Worker     // isolated from skbug.com/7792#c11
5443*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Verb verbs11[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb,
5444*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kMove_Verb };
5445*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points11[] = { {75, 150}, {75, 75}, {150, 75}, {150, 150}, {75, 150}, {75, 150} };
5446*c8dee2aaSAndroid Build Coastguard Worker     path = makePath2(points11, verbs11, std::size(verbs11));
5447*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isRect(&rect));
5448*c8dee2aaSAndroid Build Coastguard Worker     compare.setBounds(&points11[0], std::size(points11));
5449*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rect == compare);
5450*c8dee2aaSAndroid Build Coastguard Worker     // isolated from skbug.com/7792#c14
5451*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Verb verbs14[] = { SkPath::kMove_Verb, SkPath::kMove_Verb, SkPath::kMove_Verb,
5452*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb,
5453*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb,
5454*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb, SkPath::kClose_Verb };
5455*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points14[] = { {250, 75}, {250, 75}, {250, 75}, {100, 75},
5456*c8dee2aaSAndroid Build Coastguard Worker                            {150, 75}, {150, 150}, {75, 150}, {75, 75}, {0, 0} };
5457*c8dee2aaSAndroid Build Coastguard Worker     path = makePath2(points14, verbs14, std::size(verbs14));
5458*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isRect(&rect));
5459*c8dee2aaSAndroid Build Coastguard Worker     // isolated from skbug.com/7792#c15
5460*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Verb verbs15[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb,
5461*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb, SkPath::kMove_Verb };
5462*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points15[] = { {75, 75}, {150, 75}, {150, 150}, {75, 150}, {250, 75} };
5463*c8dee2aaSAndroid Build Coastguard Worker     path = makePath2(points15, verbs15, std::size(verbs15));
5464*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isRect(&rect));
5465*c8dee2aaSAndroid Build Coastguard Worker     compare.setBounds(&points15[0], std::size(points15) - 1);
5466*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rect == compare);
5467*c8dee2aaSAndroid Build Coastguard Worker     // isolated from skbug.com/7792#c17
5468*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points17[] = { {75, 10}, {75, 75}, {150, 75}, {150, 150}, {75, 150}, {75, 10} };
5469*c8dee2aaSAndroid Build Coastguard Worker     path = makePath(points17, std::size(points17), true);
5470*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isRect(&rect));
5471*c8dee2aaSAndroid Build Coastguard Worker     // isolated from skbug.com/7792#c19
5472*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Verb verbs19[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb,
5473*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb,
5474*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb,
5475*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb, SkPath::kLine_Verb };
5476*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points19[] = { {75, 75}, {75, 75}, {75, 75}, {75, 75}, {150, 75}, {150, 150},
5477*c8dee2aaSAndroid Build Coastguard Worker                            {75, 150}, {10, 10}, {30, 10}, {10, 30} };
5478*c8dee2aaSAndroid Build Coastguard Worker     path = makePath2(points19, verbs19, std::size(verbs19));
5479*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isRect(&rect));
5480*c8dee2aaSAndroid Build Coastguard Worker     // isolated from skbug.com/7792#c23
5481*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Verb verbs23[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kMove_Verb,
5482*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb,
5483*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb, SkPath::kClose_Verb };
5484*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points23[] = { {75, 75}, {75, 75}, {75, 75}, {75, 75}, {150, 75}, {150, 150},
5485*c8dee2aaSAndroid Build Coastguard Worker                            {75, 150} };
5486*c8dee2aaSAndroid Build Coastguard Worker     path = makePath2(points23, verbs23, std::size(verbs23));
5487*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isRect(&rect));
5488*c8dee2aaSAndroid Build Coastguard Worker     compare.setBounds(&points23[0], std::size(points23));
5489*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rect == compare);
5490*c8dee2aaSAndroid Build Coastguard Worker     // isolated from skbug.com/7792#c29
5491*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Verb verbs29[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb,
5492*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kMove_Verb,
5493*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kClose_Verb };
5494*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points29[] = { {75, 75}, {150, 75}, {150, 150}, {75, 150}, {75, 250}, {75, 75} };
5495*c8dee2aaSAndroid Build Coastguard Worker     path = makePath2(points29, verbs29, std::size(verbs29));
5496*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isRect(&rect));
5497*c8dee2aaSAndroid Build Coastguard Worker     // isolated from skbug.com/7792#c31
5498*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Verb verbs31[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb,
5499*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kMove_Verb,
5500*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kClose_Verb };
5501*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points31[] = { {75, 75}, {150, 75}, {150, 150}, {75, 150}, {75, 10}, {75, 75} };
5502*c8dee2aaSAndroid Build Coastguard Worker     path = makePath2(points31, verbs31, std::size(verbs31));
5503*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isRect(&rect));
5504*c8dee2aaSAndroid Build Coastguard Worker     compare.setBounds(&points31[0], 4);
5505*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rect == compare);
5506*c8dee2aaSAndroid Build Coastguard Worker     // isolated from skbug.com/7792#c36
5507*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Verb verbs36[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb,
5508*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb, SkPath::kMove_Verb, SkPath::kLine_Verb  };
5509*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points36[] = { {75, 75}, {150, 75}, {150, 150}, {10, 150}, {75, 75}, {75, 75} };
5510*c8dee2aaSAndroid Build Coastguard Worker     path = makePath2(points36, verbs36, std::size(verbs36));
5511*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isRect(&rect));
5512*c8dee2aaSAndroid Build Coastguard Worker     // isolated from skbug.com/7792#c39
5513*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Verb verbs39[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb,
5514*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb };
5515*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points39[] = { {150, 75}, {150, 150}, {75, 150}, {75, 100} };
5516*c8dee2aaSAndroid Build Coastguard Worker     path = makePath2(points39, verbs39, std::size(verbs39));
5517*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !path.isRect(&rect));
5518*c8dee2aaSAndroid Build Coastguard Worker     // isolated from zero_length_paths_aa
5519*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Verb verbsAA[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb,
5520*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb,
5521*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb, SkPath::kClose_Verb };
5522*c8dee2aaSAndroid Build Coastguard Worker     SkPoint pointsAA[] = { {32, 9.5f}, {32, 9.5f}, {32, 17}, {17, 17}, {17, 9.5f}, {17, 2},
5523*c8dee2aaSAndroid Build Coastguard Worker                            {32, 2} };
5524*c8dee2aaSAndroid Build Coastguard Worker     path = makePath2(pointsAA, verbsAA, std::size(verbsAA));
5525*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isRect(&rect));
5526*c8dee2aaSAndroid Build Coastguard Worker     compare.setBounds(&pointsAA[0], std::size(pointsAA));
5527*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rect == compare);
5528*c8dee2aaSAndroid Build Coastguard Worker     // isolated from skbug.com/7792#c41
5529*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Verb verbs41[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb,
5530*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kMove_Verb,
5531*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kClose_Verb };
5532*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points41[] = { {75, 75}, {150, 75}, {150, 150}, {140, 150}, {140, 75}, {75, 75} };
5533*c8dee2aaSAndroid Build Coastguard Worker     path = makePath2(points41, verbs41, std::size(verbs41));
5534*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isRect(&rect));
5535*c8dee2aaSAndroid Build Coastguard Worker     compare.setBounds(&points41[1], 4);
5536*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rect == compare);
5537*c8dee2aaSAndroid Build Coastguard Worker     // isolated from skbug.com/7792#c53
5538*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Verb verbs53[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb,
5539*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kMove_Verb,
5540*c8dee2aaSAndroid Build Coastguard Worker                                SkPath::kClose_Verb };
5541*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points53[] = { {75, 75}, {150, 75}, {150, 150}, {140, 150}, {140, 75}, {75, 75} };
5542*c8dee2aaSAndroid Build Coastguard Worker     path = makePath2(points53, verbs53, std::size(verbs53));
5543*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path.isRect(&rect));
5544*c8dee2aaSAndroid Build Coastguard Worker     compare.setBounds(&points53[1], 4);
5545*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rect == compare);
5546*c8dee2aaSAndroid Build Coastguard Worker }
5547*c8dee2aaSAndroid Build Coastguard Worker 
5548*c8dee2aaSAndroid Build Coastguard Worker // Be sure we can safely add ourselves
DEF_TEST(Path_self_add,reporter)5549*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(Path_self_add, reporter) {
5550*c8dee2aaSAndroid Build Coastguard Worker     // The possible problem is that during path.add() we may have to grow the dst buffers as
5551*c8dee2aaSAndroid Build Coastguard Worker     // we append the src pts/verbs, but all the while we are iterating over the src. If src == dst
5552*c8dee2aaSAndroid Build Coastguard Worker     // we could realloc the buffer's (on behalf of dst) leaving the src iterator pointing at
5553*c8dee2aaSAndroid Build Coastguard Worker     // garbage.
5554*c8dee2aaSAndroid Build Coastguard Worker     //
5555*c8dee2aaSAndroid Build Coastguard Worker     // The test runs though verious sized src paths, since its not defined publicly what the
5556*c8dee2aaSAndroid Build Coastguard Worker     // reserve allocation strategy is for SkPath, therefore we can't know when an append operation
5557*c8dee2aaSAndroid Build Coastguard Worker     // will trigger a realloc. At the time of this writing, these loops were sufficient to trigger
5558*c8dee2aaSAndroid Build Coastguard Worker     // an ASAN error w/o the fix to SkPath::addPath().
5559*c8dee2aaSAndroid Build Coastguard Worker     //
5560*c8dee2aaSAndroid Build Coastguard Worker     for (int count = 0; count < 10; ++count) {
5561*c8dee2aaSAndroid Build Coastguard Worker         SkPath path;
5562*c8dee2aaSAndroid Build Coastguard Worker         for (int add = 0; add < count; ++add) {
5563*c8dee2aaSAndroid Build Coastguard Worker             // just add some stuff, so we have something to copy/append in addPath()
5564*c8dee2aaSAndroid Build Coastguard Worker             path.moveTo(1, 2).lineTo(3, 4).cubicTo(1,2,3,4,5,6).conicTo(1,2,3,4,5);
5565*c8dee2aaSAndroid Build Coastguard Worker         }
5566*c8dee2aaSAndroid Build Coastguard Worker         path.addPath(path, 1, 2);
5567*c8dee2aaSAndroid Build Coastguard Worker         path.addPath(path, 3, 4);
5568*c8dee2aaSAndroid Build Coastguard Worker     }
5569*c8dee2aaSAndroid Build Coastguard Worker }
5570*c8dee2aaSAndroid Build Coastguard Worker 
draw_triangle(SkCanvas * canvas,const SkPoint pts[])5571*c8dee2aaSAndroid Build Coastguard Worker static void draw_triangle(SkCanvas* canvas, const SkPoint pts[]) {
5572*c8dee2aaSAndroid Build Coastguard Worker     // draw in different ways, looking for an assert
5573*c8dee2aaSAndroid Build Coastguard Worker 
5574*c8dee2aaSAndroid Build Coastguard Worker     {
5575*c8dee2aaSAndroid Build Coastguard Worker         SkPath path;
5576*c8dee2aaSAndroid Build Coastguard Worker         path.addPoly(pts, 3, false);
5577*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPath(path, SkPaint());
5578*c8dee2aaSAndroid Build Coastguard Worker     }
5579*c8dee2aaSAndroid Build Coastguard Worker 
5580*c8dee2aaSAndroid Build Coastguard Worker     const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, SK_ColorBLACK };
5581*c8dee2aaSAndroid Build Coastguard Worker     auto v = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, 3, pts, nullptr, colors);
5582*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawVertices(v, SkBlendMode::kSrcOver, SkPaint());
5583*c8dee2aaSAndroid Build Coastguard Worker }
5584*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(triangle_onehalf,reporter)5585*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(triangle_onehalf, reporter) {
5586*c8dee2aaSAndroid Build Coastguard Worker     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100)));
5587*c8dee2aaSAndroid Build Coastguard Worker 
5588*c8dee2aaSAndroid Build Coastguard Worker     const SkPoint pts[] = {
5589*c8dee2aaSAndroid Build Coastguard Worker         {  0.499069244f, 9.63295173f },
5590*c8dee2aaSAndroid Build Coastguard Worker         {  0.499402374f, 7.88207579f },
5591*c8dee2aaSAndroid Build Coastguard Worker         { 10.2363272f,   0.49999997f }
5592*c8dee2aaSAndroid Build Coastguard Worker     };
5593*c8dee2aaSAndroid Build Coastguard Worker     draw_triangle(surface->getCanvas(), pts);
5594*c8dee2aaSAndroid Build Coastguard Worker }
5595*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(triangle_big,reporter)5596*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(triangle_big, reporter) {
5597*c8dee2aaSAndroid Build Coastguard Worker     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(4, 4304)));
5598*c8dee2aaSAndroid Build Coastguard Worker 
5599*c8dee2aaSAndroid Build Coastguard Worker     // The first two points, when sent through our fixed-point SkEdge, can walk negative beyond
5600*c8dee2aaSAndroid Build Coastguard Worker     // -0.5 due to accumulated += error of the slope. We have since make the bounds calculation
5601*c8dee2aaSAndroid Build Coastguard Worker     // be conservative, so we invoke clipping if we get in this situation.
5602*c8dee2aaSAndroid Build Coastguard Worker     // This test was added to demonstrate the need for this conservative bounds calc.
5603*c8dee2aaSAndroid Build Coastguard Worker     // (found by a fuzzer)
5604*c8dee2aaSAndroid Build Coastguard Worker     const SkPoint pts[] = {
5605*c8dee2aaSAndroid Build Coastguard Worker         { 0.327190518f, -114.945152f },
5606*c8dee2aaSAndroid Build Coastguard Worker         { -0.5f, 1.00003874f },
5607*c8dee2aaSAndroid Build Coastguard Worker         { 0.666425824f, 4304.26172f },
5608*c8dee2aaSAndroid Build Coastguard Worker     };
5609*c8dee2aaSAndroid Build Coastguard Worker     draw_triangle(surface->getCanvas(), pts);
5610*c8dee2aaSAndroid Build Coastguard Worker }
5611*c8dee2aaSAndroid Build Coastguard Worker 
add_verbs(SkPath * path,int count)5612*c8dee2aaSAndroid Build Coastguard Worker static void add_verbs(SkPath* path, int count) {
5613*c8dee2aaSAndroid Build Coastguard Worker     path->moveTo(0, 0);
5614*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < count; ++i) {
5615*c8dee2aaSAndroid Build Coastguard Worker         switch (i & 3) {
5616*c8dee2aaSAndroid Build Coastguard Worker             case 0: path->lineTo(10, 20); break;
5617*c8dee2aaSAndroid Build Coastguard Worker             case 1: path->quadTo(5, 6, 7, 8); break;
5618*c8dee2aaSAndroid Build Coastguard Worker             case 2: path->conicTo(1, 2, 3, 4, 0.5f); break;
5619*c8dee2aaSAndroid Build Coastguard Worker             case 3: path->cubicTo(2, 4, 6, 8, 10, 12); break;
5620*c8dee2aaSAndroid Build Coastguard Worker         }
5621*c8dee2aaSAndroid Build Coastguard Worker     }
5622*c8dee2aaSAndroid Build Coastguard Worker }
5623*c8dee2aaSAndroid Build Coastguard Worker 
5624*c8dee2aaSAndroid Build Coastguard Worker // Make sure when we call shrinkToFit() that we always shrink (or stay the same)
5625*c8dee2aaSAndroid Build Coastguard Worker // and that if we call twice, we stay the same.
DEF_TEST(Path_shrinkToFit,reporter)5626*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(Path_shrinkToFit, reporter) {
5627*c8dee2aaSAndroid Build Coastguard Worker     for (int verbs = 0; verbs < 100; ++verbs) {
5628*c8dee2aaSAndroid Build Coastguard Worker         SkPath unique_path, shared_path;
5629*c8dee2aaSAndroid Build Coastguard Worker         add_verbs(&unique_path, verbs);
5630*c8dee2aaSAndroid Build Coastguard Worker         add_verbs(&shared_path, verbs);
5631*c8dee2aaSAndroid Build Coastguard Worker 
5632*c8dee2aaSAndroid Build Coastguard Worker         const SkPath copy = shared_path;
5633*c8dee2aaSAndroid Build Coastguard Worker 
5634*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, shared_path == unique_path);
5635*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, shared_path == copy);
5636*c8dee2aaSAndroid Build Coastguard Worker 
5637*c8dee2aaSAndroid Build Coastguard Worker         uint32_t uID = unique_path.getGenerationID();
5638*c8dee2aaSAndroid Build Coastguard Worker         uint32_t sID = shared_path.getGenerationID();
5639*c8dee2aaSAndroid Build Coastguard Worker         uint32_t cID =        copy.getGenerationID();
5640*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, sID == cID);
5641*c8dee2aaSAndroid Build Coastguard Worker 
5642*c8dee2aaSAndroid Build Coastguard Worker         SkPathPriv::ShrinkToFit(&unique_path);
5643*c8dee2aaSAndroid Build Coastguard Worker         SkPathPriv::ShrinkToFit(&shared_path);
5644*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, shared_path == unique_path);
5645*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, shared_path == copy);
5646*c8dee2aaSAndroid Build Coastguard Worker 
5647*c8dee2aaSAndroid Build Coastguard Worker         // since the unique_path is "unique", it's genID need not have changed even though
5648*c8dee2aaSAndroid Build Coastguard Worker         // unique_path has changed (been shrunk)
5649*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, uID == unique_path.getGenerationID());
5650*c8dee2aaSAndroid Build Coastguard Worker         // since the copy has not been changed, its ID should be the same
5651*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, cID == copy.getGenerationID());
5652*c8dee2aaSAndroid Build Coastguard Worker         // but since shared_path has changed, and was not uniquely owned, it's gen ID needs to have
5653*c8dee2aaSAndroid Build Coastguard Worker         // changed, breaking the "sharing" -- this is done defensively in case there were any
5654*c8dee2aaSAndroid Build Coastguard Worker         // outstanding Iterators active on copy, which could have been invalidated during
5655*c8dee2aaSAndroid Build Coastguard Worker         // shrinkToFit.
5656*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, sID != shared_path.getGenerationID());
5657*c8dee2aaSAndroid Build Coastguard Worker     }
5658*c8dee2aaSAndroid Build Coastguard Worker }
5659*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(Path_setLastPt,r)5660*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(Path_setLastPt, r) {
5661*c8dee2aaSAndroid Build Coastguard Worker     // There was a time where SkPath::setLastPoint() didn't invalidate cached path bounds.
5662*c8dee2aaSAndroid Build Coastguard Worker     SkPath p;
5663*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(0,0);
5664*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(20,01);
5665*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(20,10);
5666*c8dee2aaSAndroid Build Coastguard Worker     p.moveTo(20,61);
5667*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, p.getBounds() == SkRect::MakeLTRB(0,0, 20,61));
5668*c8dee2aaSAndroid Build Coastguard Worker 
5669*c8dee2aaSAndroid Build Coastguard Worker     p.setLastPt(30,01);
5670*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, p.getBounds() == SkRect::MakeLTRB(0,0, 30,10));  // was {0,0, 20,61}
5671*c8dee2aaSAndroid Build Coastguard Worker 
5672*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, p.isValid());
5673*c8dee2aaSAndroid Build Coastguard Worker }
5674*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(Path_increserve_handle_neg_crbug_883666,r)5675*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(Path_increserve_handle_neg_crbug_883666, r) {
5676*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
5677*c8dee2aaSAndroid Build Coastguard Worker 
5678*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo({0, 0}, {1, 1}, SK_FloatNegativeInfinity);
5679*c8dee2aaSAndroid Build Coastguard Worker 
5680*c8dee2aaSAndroid Build Coastguard Worker     // <== use a copy path object to force SkPathRef::copy() and SkPathRef::resetToSize()
5681*c8dee2aaSAndroid Build Coastguard Worker     SkPath shallowPath = path;
5682*c8dee2aaSAndroid Build Coastguard Worker 
5683*c8dee2aaSAndroid Build Coastguard Worker     // make sure we don't assert/crash on this.
5684*c8dee2aaSAndroid Build Coastguard Worker     shallowPath.incReserve(0xffffffff);
5685*c8dee2aaSAndroid Build Coastguard Worker }
5686*c8dee2aaSAndroid Build Coastguard Worker 
5687*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////////////////////
5688*c8dee2aaSAndroid Build Coastguard Worker 
5689*c8dee2aaSAndroid Build Coastguard Worker /*
5690*c8dee2aaSAndroid Build Coastguard Worker  *  For speed, we tried to preserve useful/expensive attributes about paths,
5691*c8dee2aaSAndroid Build Coastguard Worker  *      - convexity, isrect, isoval, ...
5692*c8dee2aaSAndroid Build Coastguard Worker  *  Axis-aligned shapes (rect, oval, rrect) should survive, including convexity if the matrix
5693*c8dee2aaSAndroid Build Coastguard Worker  *  is axis-aligned (e.g. scale+translate)
5694*c8dee2aaSAndroid Build Coastguard Worker  */
5695*c8dee2aaSAndroid Build Coastguard Worker 
5696*c8dee2aaSAndroid Build Coastguard Worker struct Xforms {
5697*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix    fIM, fTM, fSM, fRM;
5698*c8dee2aaSAndroid Build Coastguard Worker 
XformsXforms5699*c8dee2aaSAndroid Build Coastguard Worker     Xforms() {
5700*c8dee2aaSAndroid Build Coastguard Worker         fIM.reset();
5701*c8dee2aaSAndroid Build Coastguard Worker         fTM.setTranslate(10, 20);
5702*c8dee2aaSAndroid Build Coastguard Worker         fSM.setScale(2, 3);
5703*c8dee2aaSAndroid Build Coastguard Worker         fRM.setRotate(30);
5704*c8dee2aaSAndroid Build Coastguard Worker     }
5705*c8dee2aaSAndroid Build Coastguard Worker };
5706*c8dee2aaSAndroid Build Coastguard Worker 
conditional_convex(const SkPath & path,bool is_convex)5707*c8dee2aaSAndroid Build Coastguard Worker static bool conditional_convex(const SkPath& path, bool is_convex) {
5708*c8dee2aaSAndroid Build Coastguard Worker     SkPathConvexity c = SkPathPriv::GetConvexityOrUnknown(path);
5709*c8dee2aaSAndroid Build Coastguard Worker     return is_convex ? (c == SkPathConvexity::kConvex) : (c != SkPathConvexity::kConvex);
5710*c8dee2aaSAndroid Build Coastguard Worker }
5711*c8dee2aaSAndroid Build Coastguard Worker 
5712*c8dee2aaSAndroid Build Coastguard Worker // expect axis-aligned shape to survive assignment, identity and scale/translate matrices
5713*c8dee2aaSAndroid Build Coastguard Worker template <typename ISA>
survive(SkPath * path,const Xforms & x,bool isAxisAligned,skiatest::Reporter * reporter,ISA isa_proc)5714*c8dee2aaSAndroid Build Coastguard Worker void survive(SkPath* path, const Xforms& x, bool isAxisAligned, skiatest::Reporter* reporter,
5715*c8dee2aaSAndroid Build Coastguard Worker              ISA isa_proc) {
5716*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, isa_proc(*path));
5717*c8dee2aaSAndroid Build Coastguard Worker     // force the issue (computing convexity) the first time.
5718*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, path->isConvex());
5719*c8dee2aaSAndroid Build Coastguard Worker 
5720*c8dee2aaSAndroid Build Coastguard Worker     SkPath path2;
5721*c8dee2aaSAndroid Build Coastguard Worker 
5722*c8dee2aaSAndroid Build Coastguard Worker     // a path's isa and convexity should survive assignment
5723*c8dee2aaSAndroid Build Coastguard Worker     path2 = *path;
5724*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, isa_proc(path2));
5725*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathPriv::GetConvexityOrUnknown(path2) == SkPathConvexity::kConvex);
5726*c8dee2aaSAndroid Build Coastguard Worker 
5727*c8dee2aaSAndroid Build Coastguard Worker     // a path's isa and convexity should identity transform
5728*c8dee2aaSAndroid Build Coastguard Worker     path->transform(x.fIM, &path2);
5729*c8dee2aaSAndroid Build Coastguard Worker     path->transform(x.fIM);
5730*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, isa_proc(path2));
5731*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathPriv::GetConvexityOrUnknown(path2) == SkPathConvexity::kConvex);
5732*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, isa_proc(*path));
5733*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathPriv::GetConvexityOrUnknown(*path) == SkPathConvexity::kConvex);
5734*c8dee2aaSAndroid Build Coastguard Worker 
5735*c8dee2aaSAndroid Build Coastguard Worker     // a path's isa should survive translation, convexity depends on axis alignment
5736*c8dee2aaSAndroid Build Coastguard Worker     path->transform(x.fTM, &path2);
5737*c8dee2aaSAndroid Build Coastguard Worker     path->transform(x.fTM);
5738*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, isa_proc(path2));
5739*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, isa_proc(*path));
5740*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, conditional_convex(path2, isAxisAligned));
5741*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, conditional_convex(*path, isAxisAligned));
5742*c8dee2aaSAndroid Build Coastguard Worker 
5743*c8dee2aaSAndroid Build Coastguard Worker     // a path's isa should survive scaling, convexity depends on axis alignment
5744*c8dee2aaSAndroid Build Coastguard Worker     path->transform(x.fSM, &path2);
5745*c8dee2aaSAndroid Build Coastguard Worker     path->transform(x.fSM);
5746*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, isa_proc(path2));
5747*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, isa_proc(*path));
5748*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, conditional_convex(path2, isAxisAligned));
5749*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, conditional_convex(*path, isAxisAligned));
5750*c8dee2aaSAndroid Build Coastguard Worker 
5751*c8dee2aaSAndroid Build Coastguard Worker     // For security, post-rotation, we can't assume we're still convex. It might prove to be,
5752*c8dee2aaSAndroid Build Coastguard Worker     // in fact, still be convex, be we can't have cached that setting, hence the call to
5753*c8dee2aaSAndroid Build Coastguard Worker     // getConvexityOrUnknown() instead of getConvexity().
5754*c8dee2aaSAndroid Build Coastguard Worker     path->transform(x.fRM, &path2);
5755*c8dee2aaSAndroid Build Coastguard Worker     path->transform(x.fRM);
5756*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathPriv::GetConvexityOrUnknown(path2) != SkPathConvexity::kConvex);
5757*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkPathPriv::GetConvexityOrUnknown(*path) != SkPathConvexity::kConvex);
5758*c8dee2aaSAndroid Build Coastguard Worker 
5759*c8dee2aaSAndroid Build Coastguard Worker     if (isAxisAligned) {
5760*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !isa_proc(path2));
5761*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !isa_proc(*path));
5762*c8dee2aaSAndroid Build Coastguard Worker     }
5763*c8dee2aaSAndroid Build Coastguard Worker }
5764*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(Path_survive_transform,r)5765*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(Path_survive_transform, r) {
5766*c8dee2aaSAndroid Build Coastguard Worker     const Xforms x;
5767*c8dee2aaSAndroid Build Coastguard Worker 
5768*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
5769*c8dee2aaSAndroid Build Coastguard Worker     path.addRect({10, 10, 40, 50});
5770*c8dee2aaSAndroid Build Coastguard Worker     survive(&path, x, true, r, [](const SkPath& p) { return p.isRect(nullptr); });
5771*c8dee2aaSAndroid Build Coastguard Worker 
5772*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
5773*c8dee2aaSAndroid Build Coastguard Worker     path.addOval({10, 10, 40, 50});
5774*c8dee2aaSAndroid Build Coastguard Worker     survive(&path, x, true, r, [](const SkPath& p) { return p.isOval(nullptr); });
5775*c8dee2aaSAndroid Build Coastguard Worker 
5776*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
5777*c8dee2aaSAndroid Build Coastguard Worker     path.addRRect(SkRRect::MakeRectXY({10, 10, 40, 50}, 5, 5));
5778*c8dee2aaSAndroid Build Coastguard Worker     survive(&path, x, true, r, [](const SkPath& p) { return p.isRRect(nullptr); });
5779*c8dee2aaSAndroid Build Coastguard Worker 
5780*c8dee2aaSAndroid Build Coastguard Worker     // make a trapazoid; definitely convex, but not marked as axis-aligned (e.g. oval, rrect)
5781*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
5782*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0).lineTo(100, 0).lineTo(70, 100).lineTo(30, 100);
5783*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, path.isConvex());
5784*c8dee2aaSAndroid Build Coastguard Worker     survive(&path, x, false, r, [](const SkPath& p) { return true; });
5785*c8dee2aaSAndroid Build Coastguard Worker }
5786*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(path_last_move_to_index,r)5787*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(path_last_move_to_index, r) {
5788*c8dee2aaSAndroid Build Coastguard Worker     // Make sure that copyPath is safe after the call to path.offset().
5789*c8dee2aaSAndroid Build Coastguard Worker     // Previously, we would leave its fLastMoveToIndex alone after the copy, but now we should
5790*c8dee2aaSAndroid Build Coastguard Worker     // set it to path's value inside SkPath::transform()
5791*c8dee2aaSAndroid Build Coastguard Worker 
5792*c8dee2aaSAndroid Build Coastguard Worker     const char text[] = "hello";
5793*c8dee2aaSAndroid Build Coastguard Worker     constexpr size_t len = sizeof(text) - 1;
5794*c8dee2aaSAndroid Build Coastguard Worker     SkGlyphID glyphs[len];
5795*c8dee2aaSAndroid Build Coastguard Worker 
5796*c8dee2aaSAndroid Build Coastguard Worker     SkFont font = ToolUtils::DefaultFont();
5797*c8dee2aaSAndroid Build Coastguard Worker     font.textToGlyphs(text, len, SkTextEncoding::kUTF8, glyphs, len);
5798*c8dee2aaSAndroid Build Coastguard Worker 
5799*c8dee2aaSAndroid Build Coastguard Worker     SkPath copyPath;
5800*c8dee2aaSAndroid Build Coastguard Worker     font.getPaths(glyphs, len, [](const SkPath* src, const SkMatrix& mx, void* ctx) {
5801*c8dee2aaSAndroid Build Coastguard Worker         if (src) {
5802*c8dee2aaSAndroid Build Coastguard Worker             ((SkPath*)ctx)->addPath(*src, mx);
5803*c8dee2aaSAndroid Build Coastguard Worker         }
5804*c8dee2aaSAndroid Build Coastguard Worker     }, &copyPath);
5805*c8dee2aaSAndroid Build Coastguard Worker 
5806*c8dee2aaSAndroid Build Coastguard Worker     SkScalar radii[] = { 80, 100, 0, 0, 40, 60, 0, 0 };
5807*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
5808*c8dee2aaSAndroid Build Coastguard Worker     path.addRoundRect({10, 10, 110, 110}, radii);
5809*c8dee2aaSAndroid Build Coastguard Worker     path.offset(0, 5, &(copyPath));                     // <== change buffer copyPath.fPathRef->fPoints but not reset copyPath.fLastMoveToIndex lead to out of bound
5810*c8dee2aaSAndroid Build Coastguard Worker 
5811*c8dee2aaSAndroid Build Coastguard Worker     copyPath.rConicTo(1, 1, 3, 3, 0.707107f);
5812*c8dee2aaSAndroid Build Coastguard Worker }
5813*c8dee2aaSAndroid Build Coastguard Worker 
test_edger(skiatest::Reporter * r,const std::initializer_list<SkPath::Verb> & in,const std::initializer_list<SkPath::Verb> & expected)5814*c8dee2aaSAndroid Build Coastguard Worker static void test_edger(skiatest::Reporter* r,
5815*c8dee2aaSAndroid Build Coastguard Worker                        const std::initializer_list<SkPath::Verb>& in,
5816*c8dee2aaSAndroid Build Coastguard Worker                        const std::initializer_list<SkPath::Verb>& expected) {
5817*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
5818*c8dee2aaSAndroid Build Coastguard Worker     SkScalar x = 0, y = 0;
5819*c8dee2aaSAndroid Build Coastguard Worker     for (auto v : in) {
5820*c8dee2aaSAndroid Build Coastguard Worker         switch (v) {
5821*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kMove_Verb: path.moveTo(x++, y++); break;
5822*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kLine_Verb: path.lineTo(x++, y++); break;
5823*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kClose_Verb: path.close(); break;
5824*c8dee2aaSAndroid Build Coastguard Worker             default: SkASSERT(false);
5825*c8dee2aaSAndroid Build Coastguard Worker         }
5826*c8dee2aaSAndroid Build Coastguard Worker     }
5827*c8dee2aaSAndroid Build Coastguard Worker 
5828*c8dee2aaSAndroid Build Coastguard Worker     SkPathEdgeIter iter(path);
5829*c8dee2aaSAndroid Build Coastguard Worker     for (auto v : expected) {
5830*c8dee2aaSAndroid Build Coastguard Worker         auto e = iter.next();
5831*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, e);
5832*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, SkPathEdgeIter::EdgeToVerb(e.fEdge) == v);
5833*c8dee2aaSAndroid Build Coastguard Worker     }
5834*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, !iter.next());
5835*c8dee2aaSAndroid Build Coastguard Worker }
5836*c8dee2aaSAndroid Build Coastguard Worker 
assert_points(skiatest::Reporter * reporter,const SkPath & path,const std::initializer_list<SkPoint> & list)5837*c8dee2aaSAndroid Build Coastguard Worker static void assert_points(skiatest::Reporter* reporter,
5838*c8dee2aaSAndroid Build Coastguard Worker                           const SkPath& path, const std::initializer_list<SkPoint>& list) {
5839*c8dee2aaSAndroid Build Coastguard Worker     const SkPoint* expected = list.begin();
5840*c8dee2aaSAndroid Build Coastguard Worker     SkPath::RawIter iter(path);
5841*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0;;) {
5842*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pts[4];
5843*c8dee2aaSAndroid Build Coastguard Worker         switch (iter.next(pts)) {
5844*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kDone_Verb:
5845*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, i == list.size());
5846*c8dee2aaSAndroid Build Coastguard Worker                 return;
5847*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kMove_Verb:
5848*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, pts[0] == expected[i]);
5849*c8dee2aaSAndroid Build Coastguard Worker                 i++;
5850*c8dee2aaSAndroid Build Coastguard Worker                 break;
5851*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kLine_Verb:
5852*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, pts[1] == expected[i]);
5853*c8dee2aaSAndroid Build Coastguard Worker                 i++;
5854*c8dee2aaSAndroid Build Coastguard Worker                 break;
5855*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kClose_Verb: break;
5856*c8dee2aaSAndroid Build Coastguard Worker             default: SkASSERT(false);
5857*c8dee2aaSAndroid Build Coastguard Worker         }
5858*c8dee2aaSAndroid Build Coastguard Worker     }
5859*c8dee2aaSAndroid Build Coastguard Worker }
5860*c8dee2aaSAndroid Build Coastguard Worker 
test_addRect_and_trailing_lineTo(skiatest::Reporter * reporter)5861*c8dee2aaSAndroid Build Coastguard Worker static void test_addRect_and_trailing_lineTo(skiatest::Reporter* reporter) {
5862*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
5863*c8dee2aaSAndroid Build Coastguard Worker     const SkRect r = {1, 2, 3, 4};
5864*c8dee2aaSAndroid Build Coastguard Worker     // build our default p-array clockwise
5865*c8dee2aaSAndroid Build Coastguard Worker     const SkPoint p[] = {
5866*c8dee2aaSAndroid Build Coastguard Worker         {r.fLeft,  r.fTop},    {r.fRight, r.fTop},
5867*c8dee2aaSAndroid Build Coastguard Worker         {r.fRight, r.fBottom}, {r.fLeft,  r.fBottom},
5868*c8dee2aaSAndroid Build Coastguard Worker     };
5869*c8dee2aaSAndroid Build Coastguard Worker 
5870*c8dee2aaSAndroid Build Coastguard Worker     for (auto dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) {
5871*c8dee2aaSAndroid Build Coastguard Worker         int increment = dir == SkPathDirection::kCW ? 1 : 3;
5872*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < 4; ++i) {
5873*c8dee2aaSAndroid Build Coastguard Worker             path.reset();
5874*c8dee2aaSAndroid Build Coastguard Worker             path.addRect(r, dir, i);
5875*c8dee2aaSAndroid Build Coastguard Worker 
5876*c8dee2aaSAndroid Build Coastguard Worker             // check that we return the 4 ponts in the expected order
5877*c8dee2aaSAndroid Build Coastguard Worker             SkPoint e[4];
5878*c8dee2aaSAndroid Build Coastguard Worker             for (int j = 0; j < 4; ++j) {
5879*c8dee2aaSAndroid Build Coastguard Worker                 int index = (i + j*increment) % 4;
5880*c8dee2aaSAndroid Build Coastguard Worker                 e[j] = p[index];
5881*c8dee2aaSAndroid Build Coastguard Worker             }
5882*c8dee2aaSAndroid Build Coastguard Worker             assert_points(reporter, path, {
5883*c8dee2aaSAndroid Build Coastguard Worker                 e[0], e[1], e[2], e[3]
5884*c8dee2aaSAndroid Build Coastguard Worker             });
5885*c8dee2aaSAndroid Build Coastguard Worker 
5886*c8dee2aaSAndroid Build Coastguard Worker             // check that the new line begins where the rect began
5887*c8dee2aaSAndroid Build Coastguard Worker             path.lineTo(7,8);
5888*c8dee2aaSAndroid Build Coastguard Worker             assert_points(reporter, path, {
5889*c8dee2aaSAndroid Build Coastguard Worker                 e[0], e[1], e[2], e[3],
5890*c8dee2aaSAndroid Build Coastguard Worker                 e[0], {7,8},
5891*c8dee2aaSAndroid Build Coastguard Worker             });
5892*c8dee2aaSAndroid Build Coastguard Worker         }
5893*c8dee2aaSAndroid Build Coastguard Worker     }
5894*c8dee2aaSAndroid Build Coastguard Worker 
5895*c8dee2aaSAndroid Build Coastguard Worker     // now add a moveTo before the rect, just to be sure we don't always look at
5896*c8dee2aaSAndroid Build Coastguard Worker     // the "first" point in the path when we handle the trailing lineTo
5897*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
5898*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(7, 8);
5899*c8dee2aaSAndroid Build Coastguard Worker     path.addRect(r, SkPathDirection::kCW, 2);
5900*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(5, 6);
5901*c8dee2aaSAndroid Build Coastguard Worker 
5902*c8dee2aaSAndroid Build Coastguard Worker     assert_points(reporter, path, {
5903*c8dee2aaSAndroid Build Coastguard Worker         {7,8},                  // initial moveTo
5904*c8dee2aaSAndroid Build Coastguard Worker         p[2], p[3], p[0], p[1], // rect
5905*c8dee2aaSAndroid Build Coastguard Worker         p[2], {5, 6},           // trailing line
5906*c8dee2aaSAndroid Build Coastguard Worker     });
5907*c8dee2aaSAndroid Build Coastguard Worker }
5908*c8dee2aaSAndroid Build Coastguard Worker 
5909*c8dee2aaSAndroid Build Coastguard Worker /*
5910*c8dee2aaSAndroid Build Coastguard Worker  *  SkPath allows the caller to "skip" calling moveTo for contours. If lineTo (or a curve) is
5911*c8dee2aaSAndroid Build Coastguard Worker  *  called on an empty path, a 'moveTo(0,0)' will automatically be injected. If the path is
5912*c8dee2aaSAndroid Build Coastguard Worker  *  not empty, but its last contour has been "closed", then it will inject a moveTo corresponding
5913*c8dee2aaSAndroid Build Coastguard Worker  *  to where the last contour itself started (i.e. its moveTo).
5914*c8dee2aaSAndroid Build Coastguard Worker  *
5915*c8dee2aaSAndroid Build Coastguard Worker  *  This test exercises this in a particular case:
5916*c8dee2aaSAndroid Build Coastguard Worker  *      path.moveTo(...)                <-- needed to show the bug
5917*c8dee2aaSAndroid Build Coastguard Worker  *      path.moveTo....close()
5918*c8dee2aaSAndroid Build Coastguard Worker  *      // at this point, the path's verbs are: M M ... C
5919*c8dee2aaSAndroid Build Coastguard Worker  *
5920*c8dee2aaSAndroid Build Coastguard Worker  *      path.lineTo(...)
5921*c8dee2aaSAndroid Build Coastguard Worker  *      // after lineTo,  the path's verbs are: M M ... C M L
5922*c8dee2aaSAndroid Build Coastguard Worker  */
test_addPath_and_injected_moveTo(skiatest::Reporter * reporter)5923*c8dee2aaSAndroid Build Coastguard Worker static void test_addPath_and_injected_moveTo(skiatest::Reporter* reporter) {
5924*c8dee2aaSAndroid Build Coastguard Worker     /*
5925*c8dee2aaSAndroid Build Coastguard Worker      *  Given a path, and the expected last-point and last-move-to in it,
5926*c8dee2aaSAndroid Build Coastguard Worker      *  assert that, after a lineTo(), that the injected moveTo corresponds
5927*c8dee2aaSAndroid Build Coastguard Worker      *  to the expected value.
5928*c8dee2aaSAndroid Build Coastguard Worker      */
5929*c8dee2aaSAndroid Build Coastguard Worker     auto test_before_after_lineto = [reporter](SkPath& path,
5930*c8dee2aaSAndroid Build Coastguard Worker                                                SkPoint expectedLastPt,
5931*c8dee2aaSAndroid Build Coastguard Worker                                                SkPoint expectedMoveTo) {
5932*c8dee2aaSAndroid Build Coastguard Worker         SkPoint p = path.getPoint(path.countPoints() - 1);
5933*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, p == expectedLastPt);
5934*c8dee2aaSAndroid Build Coastguard Worker 
5935*c8dee2aaSAndroid Build Coastguard Worker         const SkPoint newLineTo = {1234, 5678};
5936*c8dee2aaSAndroid Build Coastguard Worker         path.lineTo(newLineTo);
5937*c8dee2aaSAndroid Build Coastguard Worker 
5938*c8dee2aaSAndroid Build Coastguard Worker         p = path.getPoint(path.countPoints() - 2);
5939*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, p == expectedMoveTo); // this was injected by lineTo()
5940*c8dee2aaSAndroid Build Coastguard Worker 
5941*c8dee2aaSAndroid Build Coastguard Worker         p = path.getPoint(path.countPoints() - 1);
5942*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, p == newLineTo);
5943*c8dee2aaSAndroid Build Coastguard Worker     };
5944*c8dee2aaSAndroid Build Coastguard Worker 
5945*c8dee2aaSAndroid Build Coastguard Worker     SkPath path1;
5946*c8dee2aaSAndroid Build Coastguard Worker     path1.moveTo(230, 230); // Needed to show the bug: a moveTo before the addRect
5947*c8dee2aaSAndroid Build Coastguard Worker     path1.moveTo(20,30).lineTo(40,30).lineTo(40,50).lineTo(20,50);
5948*c8dee2aaSAndroid Build Coastguard Worker     SkPath path1c(path1);
5949*c8dee2aaSAndroid Build Coastguard Worker     path1c.close();
5950*c8dee2aaSAndroid Build Coastguard Worker 
5951*c8dee2aaSAndroid Build Coastguard Worker     SkPath path2;
5952*c8dee2aaSAndroid Build Coastguard Worker     // If path2 contains zero points, the update calculation isn't tested.
5953*c8dee2aaSAndroid Build Coastguard Worker     path2.moveTo(144, 72);
5954*c8dee2aaSAndroid Build Coastguard Worker     path2.lineTo(146, 72);
5955*c8dee2aaSAndroid Build Coastguard Worker     SkPath path2c(path2);
5956*c8dee2aaSAndroid Build Coastguard Worker     path2c.close();
5957*c8dee2aaSAndroid Build Coastguard Worker     SkPath path3(path2);
5958*c8dee2aaSAndroid Build Coastguard Worker     SkPath path3c(path2c);
5959*c8dee2aaSAndroid Build Coastguard Worker 
5960*c8dee2aaSAndroid Build Coastguard Worker     // Test addPath, adding a path that ends with close.
5961*c8dee2aaSAndroid Build Coastguard Worker     // The start point of the last contour added,
5962*c8dee2aaSAndroid Build Coastguard Worker     // and the internal flag tracking whether it is closed,
5963*c8dee2aaSAndroid Build Coastguard Worker     // must be updated correctly.
5964*c8dee2aaSAndroid Build Coastguard Worker     path2.addPath(path1c);
5965*c8dee2aaSAndroid Build Coastguard Worker     path2c.addPath(path1c);
5966*c8dee2aaSAndroid Build Coastguard Worker     // At this point, path1c, path2, and path2c should end the same way.
5967*c8dee2aaSAndroid Build Coastguard Worker     test_before_after_lineto(path1c, {20,50}, {20,30});
5968*c8dee2aaSAndroid Build Coastguard Worker     test_before_after_lineto(path2, {20,50}, {20,30});
5969*c8dee2aaSAndroid Build Coastguard Worker     test_before_after_lineto(path2c, {20,50}, {20,30});
5970*c8dee2aaSAndroid Build Coastguard Worker 
5971*c8dee2aaSAndroid Build Coastguard Worker     // Test addPath, adding a path not ending in close.
5972*c8dee2aaSAndroid Build Coastguard Worker     path3.addPath(path1);
5973*c8dee2aaSAndroid Build Coastguard Worker     path3c.addPath(path1);
5974*c8dee2aaSAndroid Build Coastguard Worker     // At this point, path1, path3, and path3c should end the same way.
5975*c8dee2aaSAndroid Build Coastguard Worker     test_before_after_lineto(path1, {20,50}, {20,50});
5976*c8dee2aaSAndroid Build Coastguard Worker     test_before_after_lineto(path3, {20,50}, {20,50});
5977*c8dee2aaSAndroid Build Coastguard Worker     test_before_after_lineto(path3c, {20,50}, {20,50});
5978*c8dee2aaSAndroid Build Coastguard Worker }
5979*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(pathedger,r)5980*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(pathedger, r) {
5981*c8dee2aaSAndroid Build Coastguard Worker     auto M = SkPath::kMove_Verb;
5982*c8dee2aaSAndroid Build Coastguard Worker     auto L = SkPath::kLine_Verb;
5983*c8dee2aaSAndroid Build Coastguard Worker     auto C = SkPath::kClose_Verb;
5984*c8dee2aaSAndroid Build Coastguard Worker 
5985*c8dee2aaSAndroid Build Coastguard Worker     test_edger(r, { M }, {});
5986*c8dee2aaSAndroid Build Coastguard Worker     test_edger(r, { M, M }, {});
5987*c8dee2aaSAndroid Build Coastguard Worker     test_edger(r, { M, C }, {});
5988*c8dee2aaSAndroid Build Coastguard Worker     test_edger(r, { M, M, C }, {});
5989*c8dee2aaSAndroid Build Coastguard Worker     test_edger(r, { M, L }, { L, L });
5990*c8dee2aaSAndroid Build Coastguard Worker     test_edger(r, { M, L, C }, { L, L });
5991*c8dee2aaSAndroid Build Coastguard Worker     test_edger(r, { M, L, L }, { L, L, L });
5992*c8dee2aaSAndroid Build Coastguard Worker     test_edger(r, { M, L, L, C }, { L, L, L });
5993*c8dee2aaSAndroid Build Coastguard Worker 
5994*c8dee2aaSAndroid Build Coastguard Worker     test_edger(r, { M, L, L, M, L, L }, { L, L, L,   L, L, L });
5995*c8dee2aaSAndroid Build Coastguard Worker 
5996*c8dee2aaSAndroid Build Coastguard Worker     test_addRect_and_trailing_lineTo(r);
5997*c8dee2aaSAndroid Build Coastguard Worker     test_addPath_and_injected_moveTo(r);
5998*c8dee2aaSAndroid Build Coastguard Worker }
5999*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(path_addpath_crbug_1153516,r)6000*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(path_addpath_crbug_1153516, r) {
6001*c8dee2aaSAndroid Build Coastguard Worker     // When we add a closed path to another path, verify
6002*c8dee2aaSAndroid Build Coastguard Worker     // that the result has the right value for last contour start point.
6003*c8dee2aaSAndroid Build Coastguard Worker     SkPath p1, p2;
6004*c8dee2aaSAndroid Build Coastguard Worker     p2.lineTo(10,20);
6005*c8dee2aaSAndroid Build Coastguard Worker     p1.addRect({143,226,200,241});
6006*c8dee2aaSAndroid Build Coastguard Worker     p2.addPath(p1);
6007*c8dee2aaSAndroid Build Coastguard Worker     p2.lineTo(262,513); // this should not assert
6008*c8dee2aaSAndroid Build Coastguard Worker     SkPoint rectangleStart = {143, 226};
6009*c8dee2aaSAndroid Build Coastguard Worker     SkPoint lineEnd = {262, 513};
6010*c8dee2aaSAndroid Build Coastguard Worker     SkPoint actualMoveTo = p2.getPoint(p2.countPoints() - 2);
6011*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, actualMoveTo == rectangleStart );
6012*c8dee2aaSAndroid Build Coastguard Worker     SkPoint actualLineTo = p2.getPoint(p2.countPoints() - 1);
6013*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, actualLineTo == lineEnd);
6014*c8dee2aaSAndroid Build Coastguard Worker 
6015*c8dee2aaSAndroid Build Coastguard Worker     // Verify adding a closed path to itself
6016*c8dee2aaSAndroid Build Coastguard Worker     p1.addPath(p1);
6017*c8dee2aaSAndroid Build Coastguard Worker     p1.lineTo(262,513);
6018*c8dee2aaSAndroid Build Coastguard Worker     actualMoveTo = p1.getPoint(p1.countPoints() - 2);
6019*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, actualMoveTo == rectangleStart );
6020*c8dee2aaSAndroid Build Coastguard Worker     actualLineTo = p1.getPoint(p1.countPoints() - 1);
6021*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, actualLineTo == lineEnd);
6022*c8dee2aaSAndroid Build Coastguard Worker  }
6023*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(path_convexity_scale_way_down,r)6024*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(path_convexity_scale_way_down, r) {
6025*c8dee2aaSAndroid Build Coastguard Worker     SkPath path = SkPathBuilder().moveTo(0,0).lineTo(1, 0)
6026*c8dee2aaSAndroid Build Coastguard Worker                                  .lineTo(1,1).lineTo(0,1)
6027*c8dee2aaSAndroid Build Coastguard Worker                                  .detach();
6028*c8dee2aaSAndroid Build Coastguard Worker 
6029*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, path.isConvex());
6030*c8dee2aaSAndroid Build Coastguard Worker     SkPath path2;
6031*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar scale = 1e-8f;
6032*c8dee2aaSAndroid Build Coastguard Worker     path.transform(SkMatrix::Scale(scale, scale), &path2);
6033*c8dee2aaSAndroid Build Coastguard Worker     SkPathPriv::ForceComputeConvexity(path2);
6034*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, path2.isConvex());
6035*c8dee2aaSAndroid Build Coastguard Worker }
6036*c8dee2aaSAndroid Build Coastguard Worker 
6037*c8dee2aaSAndroid Build Coastguard Worker // crbug.com/1187385
DEF_TEST(path_moveto_addrect,r)6038*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(path_moveto_addrect, r) {
6039*c8dee2aaSAndroid Build Coastguard Worker     // Test both an empty and non-empty rect passed to SkPath::addRect
6040*c8dee2aaSAndroid Build Coastguard Worker     SkRect rects[] = {{207.0f, 237.0f, 300.0f, 237.0f},
6041*c8dee2aaSAndroid Build Coastguard Worker                       {207.0f, 237.0f, 300.0f, 267.0f}};
6042*c8dee2aaSAndroid Build Coastguard Worker 
6043*c8dee2aaSAndroid Build Coastguard Worker     for (SkRect rect: rects) {
6044*c8dee2aaSAndroid Build Coastguard Worker         for (int numExtraMoveTos : {0, 1, 2, 3}) {
6045*c8dee2aaSAndroid Build Coastguard Worker             SkPath path;
6046*c8dee2aaSAndroid Build Coastguard Worker             // Convexity and contains functions treat the path as a simple fill, so consecutive
6047*c8dee2aaSAndroid Build Coastguard Worker             // moveTos are collapsed together.
6048*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < numExtraMoveTos; ++i) {
6049*c8dee2aaSAndroid Build Coastguard Worker                 path.moveTo(i, i);
6050*c8dee2aaSAndroid Build Coastguard Worker             }
6051*c8dee2aaSAndroid Build Coastguard Worker             path.addRect(rect);
6052*c8dee2aaSAndroid Build Coastguard Worker 
6053*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(r, (numExtraMoveTos + 1) == SkPathPriv::LeadingMoveToCount(path));
6054*c8dee2aaSAndroid Build Coastguard Worker 
6055*c8dee2aaSAndroid Build Coastguard Worker             // addRect should mark the path as known convex automatically (i.e. it wasn't set
6056*c8dee2aaSAndroid Build Coastguard Worker             // to unknown after edits)
6057*c8dee2aaSAndroid Build Coastguard Worker             SkPathConvexity origConvexity = SkPathPriv::GetConvexityOrUnknown(path);
6058*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(r, origConvexity == SkPathConvexity::kConvex);
6059*c8dee2aaSAndroid Build Coastguard Worker 
6060*c8dee2aaSAndroid Build Coastguard Worker             // but it should also agree with the regular convexity computation
6061*c8dee2aaSAndroid Build Coastguard Worker             SkPathPriv::ForceComputeConvexity(path);
6062*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(r, path.isConvex());
6063*c8dee2aaSAndroid Build Coastguard Worker 
6064*c8dee2aaSAndroid Build Coastguard Worker             SkRect query = rect.makeInset(10.f, 0.f);
6065*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(r, path.conservativelyContainsRect(query));
6066*c8dee2aaSAndroid Build Coastguard Worker         }
6067*c8dee2aaSAndroid Build Coastguard Worker     }
6068*c8dee2aaSAndroid Build Coastguard Worker }
6069*c8dee2aaSAndroid Build Coastguard Worker 
6070*c8dee2aaSAndroid Build Coastguard Worker // crbug.com/1220754
DEF_TEST(path_moveto_twopass_convexity,r)6071*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(path_moveto_twopass_convexity, r) {
6072*c8dee2aaSAndroid Build Coastguard Worker     // There had been a bug when the last moveTo index > 0, the calculated point count was incorrect
6073*c8dee2aaSAndroid Build Coastguard Worker     // and the BySign convexity pass would not evaluate the entire path, effectively only using the
6074*c8dee2aaSAndroid Build Coastguard Worker     // winding rule for determining convexity.
6075*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
6076*c8dee2aaSAndroid Build Coastguard Worker     path.setFillType(SkPathFillType::kWinding);
6077*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(3.25f, 115.5f);
6078*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(9.98099e+17f, 2.83874e+15f, 1.75098e-30f, 1.75097e-30f, 1.05385e+18f);
6079*c8dee2aaSAndroid Build Coastguard Worker     path.conicTo(9.96938e+17f, 6.3804e+19f, 9.96934e+17f, 1.75096e-30f, 1.75096e-30f);
6080*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(1.28886e+10f, 9.9647e+17f, 9.98101e+17f, 2.61006e+15f);
6081*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, !path.isConvex());
6082*c8dee2aaSAndroid Build Coastguard Worker 
6083*c8dee2aaSAndroid Build Coastguard Worker     SkPath pathWithExtraMoveTo;
6084*c8dee2aaSAndroid Build Coastguard Worker     pathWithExtraMoveTo.setFillType(SkPathFillType::kWinding);
6085*c8dee2aaSAndroid Build Coastguard Worker     pathWithExtraMoveTo.moveTo(5.90043e-39f, 1.34525e-43f);
6086*c8dee2aaSAndroid Build Coastguard Worker     pathWithExtraMoveTo.addPath(path);
6087*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, !pathWithExtraMoveTo.isConvex());
6088*c8dee2aaSAndroid Build Coastguard Worker }
6089*c8dee2aaSAndroid Build Coastguard Worker 
6090*c8dee2aaSAndroid Build Coastguard Worker // crbug.com/1154864
DEF_TEST(path_walk_simple_edges_1154864,r)6091*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(path_walk_simple_edges_1154864, r) {
6092*c8dee2aaSAndroid Build Coastguard Worker     // Drawing this path triggered an assert in walk_simple_edges:
6093*c8dee2aaSAndroid Build Coastguard Worker     auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(32, 32));
6094*c8dee2aaSAndroid Build Coastguard Worker 
6095*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
6096*c8dee2aaSAndroid Build Coastguard Worker     path.setFillType(SkPathFillType::kWinding);
6097*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0.00665998459f, 2);
6098*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(0.00665998459f, 4, -1.99334002f, 4);
6099*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(-3.99334002f, 4, -3.99334002f, 2);
6100*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(-3.99334002f, 0, -1.99334002f, 0);
6101*c8dee2aaSAndroid Build Coastguard Worker     path.quadTo(0.00665998459f, 0, 0.00665998459f, 2);
6102*c8dee2aaSAndroid Build Coastguard Worker     path.close();
6103*c8dee2aaSAndroid Build Coastguard Worker 
6104*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
6105*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(true);
6106*c8dee2aaSAndroid Build Coastguard Worker     surface->getCanvas()->drawPath(path, paint);
6107*c8dee2aaSAndroid Build Coastguard Worker }
6108