Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / tests / PathTest.cpp
1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7
8 #include "SkCanvas.h"
9 #include "SkPaint.h"
10 #include "SkParse.h"
11 #include "SkParsePath.h"
12 #include "SkPath.h"
13 #include "SkPathEffect.h"
14 #include "SkRRect.h"
15 #include "SkRandom.h"
16 #include "SkReader32.h"
17 #include "SkSize.h"
18 #include "SkStream.h"
19 #include "SkSurface.h"
20 #include "SkTypes.h"
21 #include "SkWriter32.h"
22 #include "Test.h"
23
24 static void make_path_crbug364224(SkPath* path) {
25     path->reset();
26     path->moveTo(3.747501373f, 2.724499941f);
27     path->lineTo(3.747501373f, 3.75f);
28     path->cubicTo(3.747501373f, 3.88774991f, 3.635501385f, 4.0f, 3.497501373f, 4.0f);
29     path->lineTo(0.7475013733f, 4.0f);
30     path->cubicTo(0.6095013618f, 4.0f, 0.4975013733f, 3.88774991f, 0.4975013733f, 3.75f);
31     path->lineTo(0.4975013733f, 1.0f);
32     path->cubicTo(0.4975013733f, 0.8622499704f, 0.6095013618f, 0.75f, 0.7475013733f,0.75f);
33     path->lineTo(3.497501373f, 0.75f);
34     path->cubicTo(3.50275135f, 0.75f, 3.5070014f, 0.7527500391f, 3.513001442f, 0.753000021f);
35     path->lineTo(3.715001345f, 0.5512499809f);
36     path->cubicTo(3.648251295f, 0.5194999576f, 3.575501442f, 0.4999999702f, 3.497501373f, 0.4999999702f);
37     path->lineTo(0.7475013733f, 0.4999999702f);
38     path->cubicTo(0.4715013802f, 0.4999999702f, 0.2475013733f, 0.7239999771f, 0.2475013733f, 1.0f);
39     path->lineTo(0.2475013733f, 3.75f);
40     path->cubicTo(0.2475013733f, 4.026000023f, 0.4715013504f, 4.25f, 0.7475013733f, 4.25f);
41     path->lineTo(3.497501373f, 4.25f);
42     path->cubicTo(3.773501396f, 4.25f, 3.997501373f, 4.026000023f, 3.997501373f, 3.75f);
43     path->lineTo(3.997501373f, 2.474750042f);
44     path->lineTo(3.747501373f, 2.724499941f);
45     path->close();
46 }
47
48 static void make_path_crbug364224_simplified(SkPath* path) {
49     path->moveTo(3.747501373f, 2.724499941f);
50     path->cubicTo(3.648251295f, 0.5194999576f, 3.575501442f, 0.4999999702f, 3.497501373f, 0.4999999702f);
51     path->close();
52 }
53
54 static void test_path_crbug364224() {
55     SkPath path;
56     SkPaint paint;
57     SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(84, 88));
58     SkCanvas* canvas = surface->getCanvas();
59
60     make_path_crbug364224_simplified(&path);
61     canvas->drawPath(path, paint);
62
63     make_path_crbug364224(&path);
64     canvas->drawPath(path, paint);
65 }
66
67 static void make_path0(SkPath* path) {
68     // from  *  https://code.google.com/p/skia/issues/detail?id=1706
69
70     path->moveTo(146.939f, 1012.84f);
71     path->lineTo(181.747f, 1009.18f);
72     path->lineTo(182.165f, 1013.16f);
73     path->lineTo(147.357f, 1016.82f);
74     path->lineTo(146.939f, 1012.84f);
75     path->close();
76 }
77
78 static void make_path1(SkPath* path) {
79     path->addRect(SkRect::MakeXYWH(10, 10, 10, 1));
80 }
81
82 typedef void (*PathProc)(SkPath*);
83
84 /*
85  *  Regression test: we used to crash (overwrite internal storage) during
86  *  construction of the region when the path was INVERSE. That is now fixed,
87  *  so test these regions (which used to assert/crash).
88  *
89  *  https://code.google.com/p/skia/issues/detail?id=1706
90  */
91 static void test_path_to_region(skiatest::Reporter* reporter) {
92     PathProc procs[] = {
93         make_path0,
94         make_path1,
95     };
96
97     SkRegion clip;
98     clip.setRect(0, 0, 1255, 1925);
99
100     for (size_t i = 0; i < SK_ARRAY_COUNT(procs); ++i) {
101         SkPath path;
102         procs[i](&path);
103
104         SkRegion rgn;
105         rgn.setPath(path, clip);
106         path.toggleInverseFillType();
107         rgn.setPath(path, clip);
108     }
109 }
110
111 #if defined(WIN32)
112     #define SUPPRESS_VISIBILITY_WARNING
113 #else
114     #define SUPPRESS_VISIBILITY_WARNING __attribute__((visibility("hidden")))
115 #endif
116
117 static void test_path_close_issue1474(skiatest::Reporter* reporter) {
118     // This test checks that r{Line,Quad,Conic,Cubic}To following a close()
119     // are relative to the point we close to, not relative to the point we close from.
120     SkPath path;
121     SkPoint last;
122
123     // Test rLineTo().
124     path.rLineTo(0, 100);
125     path.rLineTo(100, 0);
126     path.close();          // Returns us back to 0,0.
127     path.rLineTo(50, 50);  // This should go to 50,50.
128
129     path.getLastPt(&last);
130     REPORTER_ASSERT(reporter, 50 == last.fX);
131     REPORTER_ASSERT(reporter, 50 == last.fY);
132
133     // Test rQuadTo().
134     path.rewind();
135     path.rLineTo(0, 100);
136     path.rLineTo(100, 0);
137     path.close();
138     path.rQuadTo(50, 50, 75, 75);
139
140     path.getLastPt(&last);
141     REPORTER_ASSERT(reporter, 75 == last.fX);
142     REPORTER_ASSERT(reporter, 75 == last.fY);
143
144     // Test rConicTo().
145     path.rewind();
146     path.rLineTo(0, 100);
147     path.rLineTo(100, 0);
148     path.close();
149     path.rConicTo(50, 50, 85, 85, 2);
150
151     path.getLastPt(&last);
152     REPORTER_ASSERT(reporter, 85 == last.fX);
153     REPORTER_ASSERT(reporter, 85 == last.fY);
154
155     // Test rCubicTo().
156     path.rewind();
157     path.rLineTo(0, 100);
158     path.rLineTo(100, 0);
159     path.close();
160     path.rCubicTo(50, 50, 85, 85, 95, 95);
161
162     path.getLastPt(&last);
163     REPORTER_ASSERT(reporter, 95 == last.fX);
164     REPORTER_ASSERT(reporter, 95 == last.fY);
165 }
166
167 static void test_android_specific_behavior(skiatest::Reporter* reporter) {
168 #ifdef SK_BUILD_FOR_ANDROID
169     // Make sure we treat fGenerationID and fSourcePath correctly for each of
170     // copy, assign, rewind, reset, and swap.
171     SkPath original, source, anotherSource;
172     original.setSourcePath(&source);
173     original.moveTo(0, 0);
174     original.lineTo(1, 1);
175     REPORTER_ASSERT(reporter, original.getSourcePath() == &source);
176
177     uint32_t copyID, assignID;
178
179     // Test copy constructor.  Copy generation ID, copy source path.
180     SkPath copy(original);
181     REPORTER_ASSERT(reporter, copy.getGenerationID() == original.getGenerationID());
182     REPORTER_ASSERT(reporter, copy.getSourcePath() == original.getSourcePath());
183
184     // Test assigment operator.  Change generation ID, copy source path.
185     SkPath assign;
186     assignID = assign.getGenerationID();
187     assign = original;
188     REPORTER_ASSERT(reporter, assign.getGenerationID() != assignID);
189     REPORTER_ASSERT(reporter, assign.getSourcePath() == original.getSourcePath());
190
191     // Test rewind.  Change generation ID, don't touch source path.
192     copyID = copy.getGenerationID();
193     copy.rewind();
194     REPORTER_ASSERT(reporter, copy.getGenerationID() != copyID);
195     REPORTER_ASSERT(reporter, copy.getSourcePath() == original.getSourcePath());
196
197     // Test reset.  Change generation ID, don't touch source path.
198     assignID = assign.getGenerationID();
199     assign.reset();
200     REPORTER_ASSERT(reporter, assign.getGenerationID() != assignID);
201     REPORTER_ASSERT(reporter, assign.getSourcePath() == original.getSourcePath());
202
203     // Test swap.  Swap the generation IDs, swap source paths.
204     copy.reset();
205     copy.moveTo(2, 2);
206     copy.setSourcePath(&anotherSource);
207     copyID = copy.getGenerationID();
208     assign.moveTo(3, 3);
209     assignID = assign.getGenerationID();
210     copy.swap(assign);
211     REPORTER_ASSERT(reporter, copy.getGenerationID() != copyID);
212     REPORTER_ASSERT(reporter, assign.getGenerationID() != assignID);
213     REPORTER_ASSERT(reporter, copy.getSourcePath() == original.getSourcePath());
214     REPORTER_ASSERT(reporter, assign.getSourcePath() == &anotherSource);
215 #endif
216 }
217
218 static void test_gen_id(skiatest::Reporter* reporter) {
219     SkPath a, b;
220     REPORTER_ASSERT(reporter, a.getGenerationID() == b.getGenerationID());
221
222     a.moveTo(0, 0);
223     const uint32_t z = a.getGenerationID();
224     REPORTER_ASSERT(reporter, z != b.getGenerationID());
225
226     a.reset();
227     REPORTER_ASSERT(reporter, a.getGenerationID() == b.getGenerationID());
228
229     a.moveTo(1, 1);
230     const uint32_t y = a.getGenerationID();
231     REPORTER_ASSERT(reporter, z != y);
232
233     b.moveTo(2, 2);
234     const uint32_t x = b.getGenerationID();
235     REPORTER_ASSERT(reporter, x != y && x != z);
236
237     a.swap(b);
238     REPORTER_ASSERT(reporter, b.getGenerationID() == y && a.getGenerationID() == x);
239
240     b = a;
241     REPORTER_ASSERT(reporter, b.getGenerationID() == x);
242
243     SkPath c(a);
244     REPORTER_ASSERT(reporter, c.getGenerationID() == x);
245
246     c.lineTo(3, 3);
247     const uint32_t w = c.getGenerationID();
248     REPORTER_ASSERT(reporter, b.getGenerationID() == x);
249     REPORTER_ASSERT(reporter, a.getGenerationID() == x);
250     REPORTER_ASSERT(reporter, w != x);
251
252 #ifdef SK_BUILD_FOR_ANDROID
253     static bool kExpectGenIDToIgnoreFill = false;
254 #else
255     static bool kExpectGenIDToIgnoreFill = true;
256 #endif
257
258     c.toggleInverseFillType();
259     const uint32_t v = c.getGenerationID();
260     REPORTER_ASSERT(reporter, (v == w) == kExpectGenIDToIgnoreFill);
261
262     c.rewind();
263     REPORTER_ASSERT(reporter, v != c.getGenerationID());
264 }
265
266 // This used to assert in the debug build, as the edges did not all line-up.
267 static void test_bad_cubic_crbug234190() {
268     SkPath path;
269     path.moveTo(13.8509f, 3.16858f);
270     path.cubicTo(-2.35893e+08f, -4.21044e+08f,
271                  -2.38991e+08f, -4.26573e+08f,
272                  -2.41016e+08f, -4.30188e+08f);
273
274     SkPaint paint;
275     paint.setAntiAlias(true);
276     SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(84, 88));
277     surface->getCanvas()->drawPath(path, paint);
278 }
279
280 static void test_bad_cubic_crbug229478() {
281     const SkPoint pts[] = {
282         { 4595.91064f,    -11596.9873f },
283         { 4597.2168f,    -11595.9414f },
284         { 4598.52344f,    -11594.8955f },
285         { 4599.83008f,    -11593.8496f },
286     };
287
288     SkPath path;
289     path.moveTo(pts[0]);
290     path.cubicTo(pts[1], pts[2], pts[3]);
291
292     SkPaint paint;
293     paint.setStyle(SkPaint::kStroke_Style);
294     paint.setStrokeWidth(20);
295
296     SkPath dst;
297     // Before the fix, this would infinite-recurse, and run out of stack
298     // because we would keep trying to subdivide a degenerate cubic segment.
299     paint.getFillPath(path, &dst, NULL);
300 }
301
302 static void build_path_170666(SkPath& path) {
303     path.moveTo(17.9459f, 21.6344f);
304     path.lineTo(139.545f, -47.8105f);
305     path.lineTo(139.545f, -47.8105f);
306     path.lineTo(131.07f, -47.3888f);
307     path.lineTo(131.07f, -47.3888f);
308     path.lineTo(122.586f, -46.9532f);
309     path.lineTo(122.586f, -46.9532f);
310     path.lineTo(18076.6f, 31390.9f);
311     path.lineTo(18076.6f, 31390.9f);
312     path.lineTo(18085.1f, 31390.5f);
313     path.lineTo(18085.1f, 31390.5f);
314     path.lineTo(18076.6f, 31390.9f);
315     path.lineTo(18076.6f, 31390.9f);
316     path.lineTo(17955, 31460.3f);
317     path.lineTo(17955, 31460.3f);
318     path.lineTo(17963.5f, 31459.9f);
319     path.lineTo(17963.5f, 31459.9f);
320     path.lineTo(17971.9f, 31459.5f);
321     path.lineTo(17971.9f, 31459.5f);
322     path.lineTo(17.9551f, 21.6205f);
323     path.lineTo(17.9551f, 21.6205f);
324     path.lineTo(9.47091f, 22.0561f);
325     path.lineTo(9.47091f, 22.0561f);
326     path.lineTo(17.9459f, 21.6344f);
327     path.lineTo(17.9459f, 21.6344f);
328     path.close();path.moveTo(0.995934f, 22.4779f);
329     path.lineTo(0.986725f, 22.4918f);
330     path.lineTo(0.986725f, 22.4918f);
331     path.lineTo(17955, 31460.4f);
332     path.lineTo(17955, 31460.4f);
333     path.lineTo(17971.9f, 31459.5f);
334     path.lineTo(17971.9f, 31459.5f);
335     path.lineTo(18093.6f, 31390.1f);
336     path.lineTo(18093.6f, 31390.1f);
337     path.lineTo(18093.6f, 31390);
338     path.lineTo(18093.6f, 31390);
339     path.lineTo(139.555f, -47.8244f);
340     path.lineTo(139.555f, -47.8244f);
341     path.lineTo(122.595f, -46.9671f);
342     path.lineTo(122.595f, -46.9671f);
343     path.lineTo(0.995934f, 22.4779f);
344     path.lineTo(0.995934f, 22.4779f);
345     path.close();
346     path.moveTo(5.43941f, 25.5223f);
347     path.lineTo(798267, -28871.1f);
348     path.lineTo(798267, -28871.1f);
349     path.lineTo(3.12512e+06f, -113102);
350     path.lineTo(3.12512e+06f, -113102);
351     path.cubicTo(5.16324e+06f, -186882, 8.15247e+06f, -295092, 1.1957e+07f, -432813);
352     path.cubicTo(1.95659e+07f, -708257, 3.04359e+07f, -1.10175e+06f, 4.34798e+07f, -1.57394e+06f);
353     path.cubicTo(6.95677e+07f, -2.51831e+06f, 1.04352e+08f, -3.77748e+06f, 1.39135e+08f, -5.03666e+06f);
354     path.cubicTo(1.73919e+08f, -6.29583e+06f, 2.08703e+08f, -7.555e+06f, 2.34791e+08f, -8.49938e+06f);
355     path.cubicTo(2.47835e+08f, -8.97157e+06f, 2.58705e+08f, -9.36506e+06f, 2.66314e+08f, -9.6405e+06f);
356     path.cubicTo(2.70118e+08f, -9.77823e+06f, 2.73108e+08f, -9.88644e+06f, 2.75146e+08f, -9.96022e+06f);
357     path.cubicTo(2.76165e+08f, -9.99711e+06f, 2.76946e+08f, -1.00254e+07f, 2.77473e+08f, -1.00444e+07f);
358     path.lineTo(2.78271e+08f, -1.00733e+07f);
359     path.lineTo(2.78271e+08f, -1.00733e+07f);
360     path.cubicTo(2.78271e+08f, -1.00733e+07f, 2.08703e+08f, -7.555e+06f, 135.238f, 23.3517f);
361     path.cubicTo(131.191f, 23.4981f, 125.995f, 23.7976f, 123.631f, 24.0206f);
362     path.cubicTo(121.267f, 24.2436f, 122.631f, 24.3056f, 126.677f, 24.1591f);
363     path.cubicTo(2.08703e+08f, -7.555e+06f, 2.78271e+08f, -1.00733e+07f, 2.78271e+08f, -1.00733e+07f);
364     path.lineTo(2.77473e+08f, -1.00444e+07f);
365     path.lineTo(2.77473e+08f, -1.00444e+07f);
366     path.cubicTo(2.76946e+08f, -1.00254e+07f, 2.76165e+08f, -9.99711e+06f, 2.75146e+08f, -9.96022e+06f);
367     path.cubicTo(2.73108e+08f, -9.88644e+06f, 2.70118e+08f, -9.77823e+06f, 2.66314e+08f, -9.6405e+06f);
368     path.cubicTo(2.58705e+08f, -9.36506e+06f, 2.47835e+08f, -8.97157e+06f, 2.34791e+08f, -8.49938e+06f);
369     path.cubicTo(2.08703e+08f, -7.555e+06f, 1.73919e+08f, -6.29583e+06f, 1.39135e+08f, -5.03666e+06f);
370     path.cubicTo(1.04352e+08f, -3.77749e+06f, 6.95677e+07f, -2.51831e+06f, 4.34798e+07f, -1.57394e+06f);
371     path.cubicTo(3.04359e+07f, -1.10175e+06f, 1.95659e+07f, -708258, 1.1957e+07f, -432814);
372     path.cubicTo(8.15248e+06f, -295092, 5.16324e+06f, -186883, 3.12513e+06f, -113103);
373     path.lineTo(798284, -28872);
374     path.lineTo(798284, -28872);
375     path.lineTo(22.4044f, 24.6677f);
376     path.lineTo(22.4044f, 24.6677f);
377     path.cubicTo(22.5186f, 24.5432f, 18.8134f, 24.6337f, 14.1287f, 24.8697f);
378     path.cubicTo(9.4439f, 25.1057f, 5.55359f, 25.3978f, 5.43941f, 25.5223f);
379     path.close();
380 }
381
382 static void build_path_simple_170666(SkPath& path) {
383     path.moveTo(126.677f, 24.1591f);
384     path.cubicTo(2.08703e+08f, -7.555e+06f, 2.78271e+08f, -1.00733e+07f, 2.78271e+08f, -1.00733e+07f);
385 }
386
387 // This used to assert in the SK_DEBUG build, as the clip step would fail with
388 // too-few interations in our cubic-line intersection code. That code now runs
389 // 24 interations (instead of 16).
390 static void test_crbug_170666() {
391     SkPath path;
392     SkPaint paint;
393     paint.setAntiAlias(true);
394
395     SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(1000, 1000));
396
397     build_path_simple_170666(path);
398     surface->getCanvas()->drawPath(path, paint);
399
400     build_path_170666(path);
401     surface->getCanvas()->drawPath(path, paint);
402 }
403
404 static void test_addrect(skiatest::Reporter* reporter) {
405     SkPath path;
406     path.lineTo(0, 0);
407     path.addRect(SkRect::MakeWH(50, 100));
408     REPORTER_ASSERT(reporter, path.isRect(NULL));
409
410     path.reset();
411     path.lineTo(FLT_EPSILON, FLT_EPSILON);
412     path.addRect(SkRect::MakeWH(50, 100));
413     REPORTER_ASSERT(reporter, !path.isRect(NULL));
414
415     path.reset();
416     path.quadTo(0, 0, 0, 0);
417     path.addRect(SkRect::MakeWH(50, 100));
418     REPORTER_ASSERT(reporter, !path.isRect(NULL));
419
420     path.reset();
421     path.conicTo(0, 0, 0, 0, 0.5f);
422     path.addRect(SkRect::MakeWH(50, 100));
423     REPORTER_ASSERT(reporter, !path.isRect(NULL));
424
425     path.reset();
426     path.cubicTo(0, 0, 0, 0, 0, 0);
427     path.addRect(SkRect::MakeWH(50, 100));
428     REPORTER_ASSERT(reporter, !path.isRect(NULL));
429 }
430
431 // Make sure we stay non-finite once we get there (unless we reset or rewind).
432 static void test_addrect_isfinite(skiatest::Reporter* reporter) {
433     SkPath path;
434
435     path.addRect(SkRect::MakeWH(50, 100));
436     REPORTER_ASSERT(reporter, path.isFinite());
437
438     path.moveTo(0, 0);
439     path.lineTo(SK_ScalarInfinity, 42);
440     REPORTER_ASSERT(reporter, !path.isFinite());
441
442     path.addRect(SkRect::MakeWH(50, 100));
443     REPORTER_ASSERT(reporter, !path.isFinite());
444
445     path.reset();
446     REPORTER_ASSERT(reporter, path.isFinite());
447
448     path.addRect(SkRect::MakeWH(50, 100));
449     REPORTER_ASSERT(reporter, path.isFinite());
450 }
451
452 static void build_big_path(SkPath* path, bool reducedCase) {
453     if (reducedCase) {
454         path->moveTo(577330, 1971.72f);
455         path->cubicTo(10.7082f, -116.596f, 262.057f, 45.6468f, 294.694f, 1.96237f);
456     } else {
457         path->moveTo(60.1631f, 7.70567f);
458         path->quadTo(60.1631f, 7.70567f, 0.99474f, 0.901199f);
459         path->lineTo(577379, 1977.77f);
460         path->quadTo(577364, 1979.57f, 577325, 1980.26f);
461         path->quadTo(577286, 1980.95f, 577245, 1980.13f);
462         path->quadTo(577205, 1979.3f, 577187, 1977.45f);
463         path->quadTo(577168, 1975.6f, 577183, 1973.8f);
464         path->quadTo(577198, 1972, 577238, 1971.31f);
465         path->quadTo(577277, 1970.62f, 577317, 1971.45f);
466         path->quadTo(577330, 1971.72f, 577341, 1972.11f);
467         path->cubicTo(10.7082f, -116.596f, 262.057f, 45.6468f, 294.694f, 1.96237f);
468         path->moveTo(306.718f, -32.912f);
469         path->cubicTo(30.531f, 10.0005f, 1502.47f, 13.2804f, 84.3088f, 9.99601f);
470     }
471 }
472
473 static void test_clipped_cubic() {
474     SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(640, 480));
475
476     // This path used to assert, because our cubic-chopping code incorrectly
477     // moved control points after the chop. This test should be run in SK_DEBUG
478     // mode to ensure that we no long assert.
479     SkPath path;
480     for (int doReducedCase = 0; doReducedCase <= 1; ++doReducedCase) {
481         build_big_path(&path, SkToBool(doReducedCase));
482
483         SkPaint paint;
484         for (int doAA = 0; doAA <= 1; ++doAA) {
485             paint.setAntiAlias(SkToBool(doAA));
486             surface->getCanvas()->drawPath(path, paint);
487         }
488     }
489 }
490
491 // Inspired by http://ie.microsoft.com/testdrive/Performance/Chalkboard/
492 // which triggered an assert, from a tricky cubic. This test replicates that
493 // example, so we can ensure that we handle it (in SkEdge.cpp), and don't
494 // assert in the SK_DEBUG build.
495 static void test_tricky_cubic() {
496     const SkPoint pts[] = {
497         { SkDoubleToScalar(18.8943768),    SkDoubleToScalar(129.121277) },
498         { SkDoubleToScalar(18.8937435),    SkDoubleToScalar(129.121689) },
499         { SkDoubleToScalar(18.8950119),    SkDoubleToScalar(129.120422) },
500         { SkDoubleToScalar(18.5030727),    SkDoubleToScalar(129.13121)  },
501     };
502
503     SkPath path;
504     path.moveTo(pts[0]);
505     path.cubicTo(pts[1], pts[2], pts[3]);
506
507     SkPaint paint;
508     paint.setAntiAlias(true);
509
510     SkSurface* surface = SkSurface::NewRasterPMColor(19, 130);
511     surface->getCanvas()->drawPath(path, paint);
512     surface->unref();
513 }
514
515 // Inspired by http://code.google.com/p/chromium/issues/detail?id=141651
516 //
517 static void test_isfinite_after_transform(skiatest::Reporter* reporter) {
518     SkPath path;
519     path.quadTo(157, 366, 286, 208);
520     path.arcTo(37, 442, 315, 163, 957494590897113.0f);
521
522     SkMatrix matrix;
523     matrix.setScale(1000*1000, 1000*1000);
524
525     // Be sure that path::transform correctly updates isFinite and the bounds
526     // if the transformation overflows. The previous bug was that isFinite was
527     // set to true in this case, but the bounds were not set to empty (which
528     // they should be).
529     while (path.isFinite()) {
530         REPORTER_ASSERT(reporter, path.getBounds().isFinite());
531         REPORTER_ASSERT(reporter, !path.getBounds().isEmpty());
532         path.transform(matrix);
533     }
534     REPORTER_ASSERT(reporter, path.getBounds().isEmpty());
535
536     matrix.setTranslate(SK_Scalar1, SK_Scalar1);
537     path.transform(matrix);
538     // we need to still be non-finite
539     REPORTER_ASSERT(reporter, !path.isFinite());
540     REPORTER_ASSERT(reporter, path.getBounds().isEmpty());
541 }
542
543 static void add_corner_arc(SkPath* path, const SkRect& rect,
544                            SkScalar xIn, SkScalar yIn,
545                            int startAngle)
546 {
547
548     SkScalar rx = SkMinScalar(rect.width(), xIn);
549     SkScalar ry = SkMinScalar(rect.height(), yIn);
550
551     SkRect arcRect;
552     arcRect.set(-rx, -ry, rx, ry);
553     switch (startAngle) {
554     case 0:
555         arcRect.offset(rect.fRight - arcRect.fRight, rect.fBottom - arcRect.fBottom);
556         break;
557     case 90:
558         arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fBottom - arcRect.fBottom);
559         break;
560     case 180:
561         arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fTop - arcRect.fTop);
562         break;
563     case 270:
564         arcRect.offset(rect.fRight - arcRect.fRight, rect.fTop - arcRect.fTop);
565         break;
566     default:
567         break;
568     }
569
570     path->arcTo(arcRect, SkIntToScalar(startAngle), SkIntToScalar(90), false);
571 }
572
573 static void make_arb_round_rect(SkPath* path, const SkRect& r,
574                                 SkScalar xCorner, SkScalar yCorner) {
575     // we are lazy here and use the same x & y for each corner
576     add_corner_arc(path, r, xCorner, yCorner, 270);
577     add_corner_arc(path, r, xCorner, yCorner, 0);
578     add_corner_arc(path, r, xCorner, yCorner, 90);
579     add_corner_arc(path, r, xCorner, yCorner, 180);
580     path->close();
581 }
582
583 // Chrome creates its own round rects with each corner possibly being different.
584 // Performance will suffer if they are not convex.
585 // Note: PathBench::ArbRoundRectBench performs almost exactly
586 // the same test (but with drawing)
587 static void test_arb_round_rect_is_convex(skiatest::Reporter* reporter) {
588     SkRandom rand;
589     SkRect r;
590
591     for (int i = 0; i < 5000; ++i) {
592
593         SkScalar size = rand.nextUScalar1() * 30;
594         if (size < SK_Scalar1) {
595             continue;
596         }
597         r.fLeft = rand.nextUScalar1() * 300;
598         r.fTop =  rand.nextUScalar1() * 300;
599         r.fRight =  r.fLeft + 2 * size;
600         r.fBottom = r.fTop + 2 * size;
601
602         SkPath temp;
603
604         make_arb_round_rect(&temp, r, r.width() / 10, r.height() / 15);
605
606         REPORTER_ASSERT(reporter, temp.isConvex());
607     }
608 }
609
610 // Chrome will sometimes create a 0 radius round rect. The degenerate
611 // quads prevent the path from being converted to a rect
612 // Note: PathBench::ArbRoundRectBench performs almost exactly
613 // the same test (but with drawing)
614 static void test_arb_zero_rad_round_rect_is_rect(skiatest::Reporter* reporter) {
615     SkRandom rand;
616     SkRect r;
617
618     for (int i = 0; i < 5000; ++i) {
619
620         SkScalar size = rand.nextUScalar1() * 30;
621         if (size < SK_Scalar1) {
622             continue;
623         }
624         r.fLeft = rand.nextUScalar1() * 300;
625         r.fTop =  rand.nextUScalar1() * 300;
626         r.fRight =  r.fLeft + 2 * size;
627         r.fBottom = r.fTop + 2 * size;
628
629         SkPath temp;
630
631         make_arb_round_rect(&temp, r, 0, 0);
632
633         SkRect result;
634         REPORTER_ASSERT(reporter, temp.isRect(&result));
635         REPORTER_ASSERT(reporter, r == result);
636     }
637 }
638
639 static void test_rect_isfinite(skiatest::Reporter* reporter) {
640     const SkScalar inf = SK_ScalarInfinity;
641     const SkScalar negInf = SK_ScalarNegativeInfinity;
642     const SkScalar nan = SK_ScalarNaN;
643
644     SkRect r;
645     r.setEmpty();
646     REPORTER_ASSERT(reporter, r.isFinite());
647     r.set(0, 0, inf, negInf);
648     REPORTER_ASSERT(reporter, !r.isFinite());
649     r.set(0, 0, nan, 0);
650     REPORTER_ASSERT(reporter, !r.isFinite());
651
652     SkPoint pts[] = {
653         { 0, 0 },
654         { SK_Scalar1, 0 },
655         { 0, SK_Scalar1 },
656     };
657
658     bool isFine = r.setBoundsCheck(pts, 3);
659     REPORTER_ASSERT(reporter, isFine);
660     REPORTER_ASSERT(reporter, !r.isEmpty());
661
662     pts[1].set(inf, 0);
663     isFine = r.setBoundsCheck(pts, 3);
664     REPORTER_ASSERT(reporter, !isFine);
665     REPORTER_ASSERT(reporter, r.isEmpty());
666
667     pts[1].set(nan, 0);
668     isFine = r.setBoundsCheck(pts, 3);
669     REPORTER_ASSERT(reporter, !isFine);
670     REPORTER_ASSERT(reporter, r.isEmpty());
671 }
672
673 static void test_path_isfinite(skiatest::Reporter* reporter) {
674     const SkScalar inf = SK_ScalarInfinity;
675     const SkScalar negInf = SK_ScalarNegativeInfinity;
676     const SkScalar nan = SK_ScalarNaN;
677
678     SkPath path;
679     REPORTER_ASSERT(reporter, path.isFinite());
680
681     path.reset();
682     REPORTER_ASSERT(reporter, path.isFinite());
683
684     path.reset();
685     path.moveTo(SK_Scalar1, 0);
686     REPORTER_ASSERT(reporter, path.isFinite());
687
688     path.reset();
689     path.moveTo(inf, negInf);
690     REPORTER_ASSERT(reporter, !path.isFinite());
691
692     path.reset();
693     path.moveTo(nan, 0);
694     REPORTER_ASSERT(reporter, !path.isFinite());
695 }
696
697 static void test_isfinite(skiatest::Reporter* reporter) {
698     test_rect_isfinite(reporter);
699     test_path_isfinite(reporter);
700 }
701
702 // assert that we always
703 //  start with a moveTo
704 //  only have 1 moveTo
705 //  only have Lines after that
706 //  end with a single close
707 //  only have (at most) 1 close
708 //
709 static void test_poly(skiatest::Reporter* reporter, const SkPath& path,
710                       const SkPoint srcPts[], bool expectClose) {
711     SkPath::RawIter iter(path);
712     SkPoint         pts[4];
713
714     bool firstTime = true;
715     bool foundClose = false;
716     for (;;) {
717         switch (iter.next(pts)) {
718             case SkPath::kMove_Verb:
719                 REPORTER_ASSERT(reporter, firstTime);
720                 REPORTER_ASSERT(reporter, pts[0] == srcPts[0]);
721                 srcPts++;
722                 firstTime = false;
723                 break;
724             case SkPath::kLine_Verb:
725                 REPORTER_ASSERT(reporter, !firstTime);
726                 REPORTER_ASSERT(reporter, pts[1] == srcPts[0]);
727                 srcPts++;
728                 break;
729             case SkPath::kQuad_Verb:
730                 REPORTER_ASSERT_MESSAGE(reporter, false, "unexpected quad verb");
731                 break;
732             case SkPath::kConic_Verb:
733                 REPORTER_ASSERT_MESSAGE(reporter, false, "unexpected conic verb");
734                 break;
735             case SkPath::kCubic_Verb:
736                 REPORTER_ASSERT_MESSAGE(reporter, false, "unexpected cubic verb");
737                 break;
738             case SkPath::kClose_Verb:
739                 REPORTER_ASSERT(reporter, !firstTime);
740                 REPORTER_ASSERT(reporter, !foundClose);
741                 REPORTER_ASSERT(reporter, expectClose);
742                 foundClose = true;
743                 break;
744             case SkPath::kDone_Verb:
745                 goto DONE;
746         }
747     }
748 DONE:
749     REPORTER_ASSERT(reporter, foundClose == expectClose);
750 }
751
752 static void test_addPoly(skiatest::Reporter* reporter) {
753     SkPoint pts[32];
754     SkRandom rand;
755
756     for (size_t i = 0; i < SK_ARRAY_COUNT(pts); ++i) {
757         pts[i].fX = rand.nextSScalar1();
758         pts[i].fY = rand.nextSScalar1();
759     }
760
761     for (int doClose = 0; doClose <= 1; ++doClose) {
762         for (size_t count = 1; count <= SK_ARRAY_COUNT(pts); ++count) {
763             SkPath path;
764             path.addPoly(pts, count, SkToBool(doClose));
765             test_poly(reporter, path, pts, SkToBool(doClose));
766         }
767     }
768 }
769
770 static void test_strokerec(skiatest::Reporter* reporter) {
771     SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
772     REPORTER_ASSERT(reporter, rec.isFillStyle());
773
774     rec.setHairlineStyle();
775     REPORTER_ASSERT(reporter, rec.isHairlineStyle());
776
777     rec.setStrokeStyle(SK_Scalar1, false);
778     REPORTER_ASSERT(reporter, SkStrokeRec::kStroke_Style == rec.getStyle());
779
780     rec.setStrokeStyle(SK_Scalar1, true);
781     REPORTER_ASSERT(reporter, SkStrokeRec::kStrokeAndFill_Style == rec.getStyle());
782
783     rec.setStrokeStyle(0, false);
784     REPORTER_ASSERT(reporter, SkStrokeRec::kHairline_Style == rec.getStyle());
785
786     rec.setStrokeStyle(0, true);
787     REPORTER_ASSERT(reporter, SkStrokeRec::kFill_Style == rec.getStyle());
788 }
789
790 // Set this for paths that don't have a consistent direction such as a bowtie.
791 // (cheapComputeDirection is not expected to catch these.)
792 static const SkPath::Direction kDontCheckDir = static_cast<SkPath::Direction>(-1);
793
794 static void check_direction(skiatest::Reporter* reporter, const SkPath& path,
795                             SkPath::Direction expected) {
796     if (expected == kDontCheckDir) {
797         return;
798     }
799     SkPath copy(path); // we make a copy so that we don't cache the result on the passed in path.
800
801     SkPath::Direction dir;
802     if (copy.cheapComputeDirection(&dir)) {
803         REPORTER_ASSERT(reporter, dir == expected);
804     } else {
805         REPORTER_ASSERT(reporter, SkPath::kUnknown_Direction == expected);
806     }
807 }
808
809 static void test_direction(skiatest::Reporter* reporter) {
810     size_t i;
811     SkPath path;
812     REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
813     REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCW_Direction));
814     REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCCW_Direction));
815     REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kUnknown_Direction));
816
817     static const char* gDegen[] = {
818         "M 10 10",
819         "M 10 10 M 20 20",
820         "M 10 10 L 20 20",
821         "M 10 10 L 10 10 L 10 10",
822         "M 10 10 Q 10 10 10 10",
823         "M 10 10 C 10 10 10 10 10 10",
824     };
825     for (i = 0; i < SK_ARRAY_COUNT(gDegen); ++i) {
826         path.reset();
827         bool valid = SkParsePath::FromSVGString(gDegen[i], &path);
828         REPORTER_ASSERT(reporter, valid);
829         REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
830     }
831
832     static const char* gCW[] = {
833         "M 10 10 L 10 10 Q 20 10 20 20",
834         "M 10 10 C 20 10 20 20 20 20",
835         "M 20 10 Q 20 20 30 20 L 10 20", // test double-back at y-max
836         // rect with top two corners replaced by cubics with identical middle
837         // control points
838         "M 10 10 C 10 0 10 0 20 0 L 40 0 C 50 0 50 0 50 10",
839         "M 20 10 L 0 10 Q 10 10 20 0",  // left, degenerate serif
840     };
841     for (i = 0; i < SK_ARRAY_COUNT(gCW); ++i) {
842         path.reset();
843         bool valid = SkParsePath::FromSVGString(gCW[i], &path);
844         REPORTER_ASSERT(reporter, valid);
845         check_direction(reporter, path, SkPath::kCW_Direction);
846     }
847
848     static const char* gCCW[] = {
849         "M 10 10 L 10 10 Q 20 10 20 -20",
850         "M 10 10 C 20 10 20 -20 20 -20",
851         "M 20 10 Q 20 20 10 20 L 30 20", // test double-back at y-max
852         // rect with top two corners replaced by cubics with identical middle
853         // control points
854         "M 50 10 C 50 0 50 0 40 0 L 20 0 C 10 0 10 0 10 10",
855         "M 10 10 L 30 10 Q 20 10 10 0",  // right, degenerate serif
856     };
857     for (i = 0; i < SK_ARRAY_COUNT(gCCW); ++i) {
858         path.reset();
859         bool valid = SkParsePath::FromSVGString(gCCW[i], &path);
860         REPORTER_ASSERT(reporter, valid);
861         check_direction(reporter, path, SkPath::kCCW_Direction);
862     }
863
864     // Test two donuts, each wound a different direction. Only the outer contour
865     // determines the cheap direction
866     path.reset();
867     path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCW_Direction);
868     path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCCW_Direction);
869     check_direction(reporter, path, SkPath::kCW_Direction);
870
871     path.reset();
872     path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCW_Direction);
873     path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCCW_Direction);
874     check_direction(reporter, path, SkPath::kCCW_Direction);
875
876     // triangle with one point really far from the origin.
877     path.reset();
878     // the first point is roughly 1.05e10, 1.05e10
879     path.moveTo(SkBits2Float(0x501c7652), SkBits2Float(0x501c7652));
880     path.lineTo(110 * SK_Scalar1, -10 * SK_Scalar1);
881     path.lineTo(-10 * SK_Scalar1, 60 * SK_Scalar1);
882     check_direction(reporter, path, SkPath::kCCW_Direction);
883
884     path.reset();
885     path.conicTo(20, 0, 20, 20, 0.5f);
886     path.close();
887     check_direction(reporter, path, SkPath::kCW_Direction);
888
889     path.reset();
890     path.lineTo(1, 1e7f);
891     path.lineTo(1e7f, 2e7f);
892     path.close();
893     REPORTER_ASSERT(reporter, SkPath::kConvex_Convexity == path.getConvexity());
894     check_direction(reporter, path, SkPath::kCCW_Direction);
895 }
896
897 static void add_rect(SkPath* path, const SkRect& r) {
898     path->moveTo(r.fLeft, r.fTop);
899     path->lineTo(r.fRight, r.fTop);
900     path->lineTo(r.fRight, r.fBottom);
901     path->lineTo(r.fLeft, r.fBottom);
902     path->close();
903 }
904
905 static void test_bounds(skiatest::Reporter* reporter) {
906     static const SkRect rects[] = {
907         { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(160) },
908         { SkIntToScalar(610), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(199) },
909         { SkIntToScalar(10), SkIntToScalar(198), SkIntToScalar(610), SkIntToScalar(199) },
910         { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(10), SkIntToScalar(199) },
911     };
912
913     SkPath path0, path1;
914     for (size_t i = 0; i < SK_ARRAY_COUNT(rects); ++i) {
915         path0.addRect(rects[i]);
916         add_rect(&path1, rects[i]);
917     }
918
919     REPORTER_ASSERT(reporter, path0.getBounds() == path1.getBounds());
920 }
921
922 static void stroke_cubic(const SkPoint pts[4]) {
923     SkPath path;
924     path.moveTo(pts[0]);
925     path.cubicTo(pts[1], pts[2], pts[3]);
926
927     SkPaint paint;
928     paint.setStyle(SkPaint::kStroke_Style);
929     paint.setStrokeWidth(SK_Scalar1 * 2);
930
931     SkPath fill;
932     paint.getFillPath(path, &fill);
933 }
934
935 // just ensure this can run w/o any SkASSERTS firing in the debug build
936 // we used to assert due to differences in how we determine a degenerate vector
937 // but that was fixed with the introduction of SkPoint::CanNormalize
938 static void stroke_tiny_cubic() {
939     SkPoint p0[] = {
940         { 372.0f,   92.0f },
941         { 372.0f,   92.0f },
942         { 372.0f,   92.0f },
943         { 372.0f,   92.0f },
944     };
945
946     stroke_cubic(p0);
947
948     SkPoint p1[] = {
949         { 372.0f,       92.0f },
950         { 372.0007f,    92.000755f },
951         { 371.99927f,   92.003922f },
952         { 371.99826f,   92.003899f },
953     };
954
955     stroke_cubic(p1);
956 }
957
958 static void check_close(skiatest::Reporter* reporter, const SkPath& path) {
959     for (int i = 0; i < 2; ++i) {
960         SkPath::Iter iter(path, SkToBool(i));
961         SkPoint mv;
962         SkPoint pts[4];
963         SkPath::Verb v;
964         int nMT = 0;
965         int nCL = 0;
966         mv.set(0, 0);
967         while (SkPath::kDone_Verb != (v = iter.next(pts))) {
968             switch (v) {
969                 case SkPath::kMove_Verb:
970                     mv = pts[0];
971                     ++nMT;
972                     break;
973                 case SkPath::kClose_Verb:
974                     REPORTER_ASSERT(reporter, mv == pts[0]);
975                     ++nCL;
976                     break;
977                 default:
978                     break;
979             }
980         }
981         // if we force a close on the interator we should have a close
982         // for every moveTo
983         REPORTER_ASSERT(reporter, !i || nMT == nCL);
984     }
985 }
986
987 static void test_close(skiatest::Reporter* reporter) {
988     SkPath closePt;
989     closePt.moveTo(0, 0);
990     closePt.close();
991     check_close(reporter, closePt);
992
993     SkPath openPt;
994     openPt.moveTo(0, 0);
995     check_close(reporter, openPt);
996
997     SkPath empty;
998     check_close(reporter, empty);
999     empty.close();
1000     check_close(reporter, empty);
1001
1002     SkPath rect;
1003     rect.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
1004     check_close(reporter, rect);
1005     rect.close();
1006     check_close(reporter, rect);
1007
1008     SkPath quad;
1009     quad.quadTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
1010     check_close(reporter, quad);
1011     quad.close();
1012     check_close(reporter, quad);
1013
1014     SkPath cubic;
1015     quad.cubicTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1,
1016                  10*SK_Scalar1, 20 * SK_Scalar1, 20*SK_Scalar1);
1017     check_close(reporter, cubic);
1018     cubic.close();
1019     check_close(reporter, cubic);
1020
1021     SkPath line;
1022     line.moveTo(SK_Scalar1, SK_Scalar1);
1023     line.lineTo(10 * SK_Scalar1, 10*SK_Scalar1);
1024     check_close(reporter, line);
1025     line.close();
1026     check_close(reporter, line);
1027
1028     SkPath rect2;
1029     rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
1030     rect2.close();
1031     rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
1032     check_close(reporter, rect2);
1033     rect2.close();
1034     check_close(reporter, rect2);
1035
1036     SkPath oval3;
1037     oval3.addOval(SkRect::MakeWH(SK_Scalar1*100,SK_Scalar1*100));
1038     oval3.close();
1039     oval3.addOval(SkRect::MakeWH(SK_Scalar1*200,SK_Scalar1*200));
1040     check_close(reporter, oval3);
1041     oval3.close();
1042     check_close(reporter, oval3);
1043
1044     SkPath moves;
1045     moves.moveTo(SK_Scalar1, SK_Scalar1);
1046     moves.moveTo(5 * SK_Scalar1, SK_Scalar1);
1047     moves.moveTo(SK_Scalar1, 10 * SK_Scalar1);
1048     moves.moveTo(10 *SK_Scalar1, SK_Scalar1);
1049     check_close(reporter, moves);
1050
1051     stroke_tiny_cubic();
1052 }
1053
1054 static void check_convexity(skiatest::Reporter* reporter, const SkPath& path,
1055                             SkPath::Convexity expected) {
1056     SkPath copy(path); // we make a copy so that we don't cache the result on the passed in path.
1057     SkPath::Convexity c = copy.getConvexity();
1058     REPORTER_ASSERT(reporter, c == expected);
1059 }
1060
1061 static void test_convexity2(skiatest::Reporter* reporter) {
1062     SkPath pt;
1063     pt.moveTo(0, 0);
1064     pt.close();
1065     check_convexity(reporter, pt, SkPath::kConvex_Convexity);
1066     check_direction(reporter, pt, SkPath::kUnknown_Direction);
1067
1068     SkPath line;
1069     line.moveTo(12*SK_Scalar1, 20*SK_Scalar1);
1070     line.lineTo(-12*SK_Scalar1, -20*SK_Scalar1);
1071     line.close();
1072     check_convexity(reporter, line, SkPath::kConvex_Convexity);
1073     check_direction(reporter, line, SkPath::kUnknown_Direction);
1074
1075     SkPath triLeft;
1076     triLeft.moveTo(0, 0);
1077     triLeft.lineTo(SK_Scalar1, 0);
1078     triLeft.lineTo(SK_Scalar1, SK_Scalar1);
1079     triLeft.close();
1080     check_convexity(reporter, triLeft, SkPath::kConvex_Convexity);
1081     check_direction(reporter, triLeft, SkPath::kCW_Direction);
1082
1083     SkPath triRight;
1084     triRight.moveTo(0, 0);
1085     triRight.lineTo(-SK_Scalar1, 0);
1086     triRight.lineTo(SK_Scalar1, SK_Scalar1);
1087     triRight.close();
1088     check_convexity(reporter, triRight, SkPath::kConvex_Convexity);
1089     check_direction(reporter, triRight, SkPath::kCCW_Direction);
1090
1091     SkPath square;
1092     square.moveTo(0, 0);
1093     square.lineTo(SK_Scalar1, 0);
1094     square.lineTo(SK_Scalar1, SK_Scalar1);
1095     square.lineTo(0, SK_Scalar1);
1096     square.close();
1097     check_convexity(reporter, square, SkPath::kConvex_Convexity);
1098     check_direction(reporter, square, SkPath::kCW_Direction);
1099
1100     SkPath redundantSquare;
1101     redundantSquare.moveTo(0, 0);
1102     redundantSquare.lineTo(0, 0);
1103     redundantSquare.lineTo(0, 0);
1104     redundantSquare.lineTo(SK_Scalar1, 0);
1105     redundantSquare.lineTo(SK_Scalar1, 0);
1106     redundantSquare.lineTo(SK_Scalar1, 0);
1107     redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
1108     redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
1109     redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
1110     redundantSquare.lineTo(0, SK_Scalar1);
1111     redundantSquare.lineTo(0, SK_Scalar1);
1112     redundantSquare.lineTo(0, SK_Scalar1);
1113     redundantSquare.close();
1114     check_convexity(reporter, redundantSquare, SkPath::kConvex_Convexity);
1115     check_direction(reporter, redundantSquare, SkPath::kCW_Direction);
1116
1117     SkPath bowTie;
1118     bowTie.moveTo(0, 0);
1119     bowTie.lineTo(0, 0);
1120     bowTie.lineTo(0, 0);
1121     bowTie.lineTo(SK_Scalar1, SK_Scalar1);
1122     bowTie.lineTo(SK_Scalar1, SK_Scalar1);
1123     bowTie.lineTo(SK_Scalar1, SK_Scalar1);
1124     bowTie.lineTo(SK_Scalar1, 0);
1125     bowTie.lineTo(SK_Scalar1, 0);
1126     bowTie.lineTo(SK_Scalar1, 0);
1127     bowTie.lineTo(0, SK_Scalar1);
1128     bowTie.lineTo(0, SK_Scalar1);
1129     bowTie.lineTo(0, SK_Scalar1);
1130     bowTie.close();
1131     check_convexity(reporter, bowTie, SkPath::kConcave_Convexity);
1132     check_direction(reporter, bowTie, kDontCheckDir);
1133
1134     SkPath spiral;
1135     spiral.moveTo(0, 0);
1136     spiral.lineTo(100*SK_Scalar1, 0);
1137     spiral.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
1138     spiral.lineTo(0, 100*SK_Scalar1);
1139     spiral.lineTo(0, 50*SK_Scalar1);
1140     spiral.lineTo(50*SK_Scalar1, 50*SK_Scalar1);
1141     spiral.lineTo(50*SK_Scalar1, 75*SK_Scalar1);
1142     spiral.close();
1143     check_convexity(reporter, spiral, SkPath::kConcave_Convexity);
1144     check_direction(reporter, spiral, kDontCheckDir);
1145
1146     SkPath dent;
1147     dent.moveTo(0, 0);
1148     dent.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
1149     dent.lineTo(0, 100*SK_Scalar1);
1150     dent.lineTo(-50*SK_Scalar1, 200*SK_Scalar1);
1151     dent.lineTo(-200*SK_Scalar1, 100*SK_Scalar1);
1152     dent.close();
1153     check_convexity(reporter, dent, SkPath::kConcave_Convexity);
1154     check_direction(reporter, dent, SkPath::kCW_Direction);
1155
1156     // http://skbug.com/2235
1157     SkPath strokedSin;
1158     for (int i = 0; i < 2000; i++) {
1159         SkScalar x = SkIntToScalar(i) / 2;
1160         SkScalar y = 500 - (x + SkScalarSin(x / 100) * 40) / 3;
1161         if (0 == i) {
1162             strokedSin.moveTo(x, y);
1163         } else {
1164             strokedSin.lineTo(x, y);
1165         }
1166     }
1167     SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
1168     stroke.setStrokeStyle(2 * SK_Scalar1);
1169     stroke.applyToPath(&strokedSin, strokedSin);
1170     check_convexity(reporter, strokedSin, SkPath::kConcave_Convexity);
1171     check_direction(reporter, strokedSin, kDontCheckDir);
1172 }
1173
1174 static void check_convex_bounds(skiatest::Reporter* reporter, const SkPath& p,
1175                                 const SkRect& bounds) {
1176     REPORTER_ASSERT(reporter, p.isConvex());
1177     REPORTER_ASSERT(reporter, p.getBounds() == bounds);
1178
1179     SkPath p2(p);
1180     REPORTER_ASSERT(reporter, p2.isConvex());
1181     REPORTER_ASSERT(reporter, p2.getBounds() == bounds);
1182
1183     SkPath other;
1184     other.swap(p2);
1185     REPORTER_ASSERT(reporter, other.isConvex());
1186     REPORTER_ASSERT(reporter, other.getBounds() == bounds);
1187 }
1188
1189 static void setFromString(SkPath* path, const char str[]) {
1190     bool first = true;
1191     while (str) {
1192         SkScalar x, y;
1193         str = SkParse::FindScalar(str, &x);
1194         if (NULL == str) {
1195             break;
1196         }
1197         str = SkParse::FindScalar(str, &y);
1198         SkASSERT(str);
1199         if (first) {
1200             path->moveTo(x, y);
1201             first = false;
1202         } else {
1203             path->lineTo(x, y);
1204         }
1205     }
1206 }
1207
1208 static void test_convexity(skiatest::Reporter* reporter) {
1209     SkPath path;
1210
1211     check_convexity(reporter, path, SkPath::kConvex_Convexity);
1212     path.addCircle(0, 0, SkIntToScalar(10));
1213     check_convexity(reporter, path, SkPath::kConvex_Convexity);
1214     path.addCircle(0, 0, SkIntToScalar(10));   // 2nd circle
1215     check_convexity(reporter, path, SkPath::kConcave_Convexity);
1216
1217     path.reset();
1218     path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCCW_Direction);
1219     check_convexity(reporter, path, SkPath::kConvex_Convexity);
1220     REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCCW_Direction));
1221
1222     path.reset();
1223     path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCW_Direction);
1224     check_convexity(reporter, path, SkPath::kConvex_Convexity);
1225     REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCW_Direction));
1226
1227     static const struct {
1228         const char*         fPathStr;
1229         SkPath::Convexity   fExpectedConvexity;
1230         SkPath::Direction   fExpectedDirection;
1231     } gRec[] = {
1232         { "", SkPath::kConvex_Convexity, SkPath::kUnknown_Direction },
1233         { "0 0", SkPath::kConvex_Convexity, SkPath::kUnknown_Direction },
1234         { "0 0 10 10", SkPath::kConvex_Convexity, SkPath::kUnknown_Direction },
1235         { "0 0 10 10 20 20 0 0 10 10", SkPath::kConcave_Convexity, SkPath::kUnknown_Direction },
1236         { "0 0 10 10 10 20", SkPath::kConvex_Convexity, SkPath::kCW_Direction },
1237         { "0 0 10 10 10 0", SkPath::kConvex_Convexity, SkPath::kCCW_Direction },
1238         { "0 0 10 10 10 0 0 10", SkPath::kConcave_Convexity, kDontCheckDir },
1239         { "0 0 10 0 0 10 -10 -10", SkPath::kConcave_Convexity, SkPath::kCW_Direction },
1240     };
1241
1242     for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
1243         SkPath path;
1244         setFromString(&path, gRec[i].fPathStr);
1245         check_convexity(reporter, path, gRec[i].fExpectedConvexity);
1246         check_direction(reporter, path, gRec[i].fExpectedDirection);
1247         // check after setting the initial convex and direction
1248         if (kDontCheckDir != gRec[i].fExpectedDirection) {
1249             SkPath copy(path);
1250             SkPath::Direction dir;
1251             bool foundDir = copy.cheapComputeDirection(&dir);
1252             REPORTER_ASSERT(reporter, (gRec[i].fExpectedDirection == SkPath::kUnknown_Direction)
1253                     ^ foundDir);
1254             REPORTER_ASSERT(reporter, !foundDir || gRec[i].fExpectedDirection == dir);
1255             check_convexity(reporter, copy, gRec[i].fExpectedConvexity);
1256         }
1257         REPORTER_ASSERT(reporter, gRec[i].fExpectedConvexity == path.getConvexity());
1258         check_direction(reporter, path, gRec[i].fExpectedDirection);
1259     }
1260 }
1261
1262 static void test_isLine(skiatest::Reporter* reporter) {
1263     SkPath path;
1264     SkPoint pts[2];
1265     const SkScalar value = SkIntToScalar(5);
1266
1267     REPORTER_ASSERT(reporter, !path.isLine(NULL));
1268
1269     // set some non-zero values
1270     pts[0].set(value, value);
1271     pts[1].set(value, value);
1272     REPORTER_ASSERT(reporter, !path.isLine(pts));
1273     // check that pts was untouched
1274     REPORTER_ASSERT(reporter, pts[0].equals(value, value));
1275     REPORTER_ASSERT(reporter, pts[1].equals(value, value));
1276
1277     const SkScalar moveX = SkIntToScalar(1);
1278     const SkScalar moveY = SkIntToScalar(2);
1279     REPORTER_ASSERT(reporter, value != moveX && value != moveY);
1280
1281     path.moveTo(moveX, moveY);
1282     REPORTER_ASSERT(reporter, !path.isLine(NULL));
1283     REPORTER_ASSERT(reporter, !path.isLine(pts));
1284     // check that pts was untouched
1285     REPORTER_ASSERT(reporter, pts[0].equals(value, value));
1286     REPORTER_ASSERT(reporter, pts[1].equals(value, value));
1287
1288     const SkScalar lineX = SkIntToScalar(2);
1289     const SkScalar lineY = SkIntToScalar(2);
1290     REPORTER_ASSERT(reporter, value != lineX && value != lineY);
1291
1292     path.lineTo(lineX, lineY);
1293     REPORTER_ASSERT(reporter, path.isLine(NULL));
1294
1295     REPORTER_ASSERT(reporter, !pts[0].equals(moveX, moveY));
1296     REPORTER_ASSERT(reporter, !pts[1].equals(lineX, lineY));
1297     REPORTER_ASSERT(reporter, path.isLine(pts));
1298     REPORTER_ASSERT(reporter, pts[0].equals(moveX, moveY));
1299     REPORTER_ASSERT(reporter, pts[1].equals(lineX, lineY));
1300
1301     path.lineTo(0, 0);  // too many points/verbs
1302     REPORTER_ASSERT(reporter, !path.isLine(NULL));
1303     REPORTER_ASSERT(reporter, !path.isLine(pts));
1304     REPORTER_ASSERT(reporter, pts[0].equals(moveX, moveY));
1305     REPORTER_ASSERT(reporter, pts[1].equals(lineX, lineY));
1306
1307     path.reset();
1308     path.quadTo(1, 1, 2, 2);
1309     REPORTER_ASSERT(reporter, !path.isLine(NULL));
1310 }
1311
1312 static void test_conservativelyContains(skiatest::Reporter* reporter) {
1313     SkPath path;
1314
1315     // kBaseRect is used to construct most our test paths: a rect, a circle, and a round-rect.
1316     static const SkRect kBaseRect = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
1317
1318     // A circle that bounds kBaseRect (with a significant amount of slop)
1319     SkScalar circleR = SkMaxScalar(kBaseRect.width(), kBaseRect.height());
1320     circleR = SkScalarMul(circleR, 1.75f) / 2;
1321     static const SkPoint kCircleC = {kBaseRect.centerX(), kBaseRect.centerY()};
1322
1323     // round-rect radii
1324     static const SkScalar kRRRadii[] = {SkIntToScalar(5), SkIntToScalar(3)};
1325
1326     static const struct SUPPRESS_VISIBILITY_WARNING {
1327         SkRect fQueryRect;
1328         bool   fInRect;
1329         bool   fInCircle;
1330         bool   fInRR;
1331         bool   fInCubicRR;
1332     } kQueries[] = {
1333         {kBaseRect, true, true, false, false},
1334
1335         // rect well inside of kBaseRect
1336         {SkRect::MakeLTRB(kBaseRect.fLeft + 0.25f*kBaseRect.width(),
1337                           kBaseRect.fTop + 0.25f*kBaseRect.height(),
1338                           kBaseRect.fRight - 0.25f*kBaseRect.width(),
1339                           kBaseRect.fBottom - 0.25f*kBaseRect.height()),
1340                           true, true, true, true},
1341
1342         // rects with edges off by one from kBaseRect's edges
1343         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop,
1344                           kBaseRect.width(), kBaseRect.height() + 1),
1345          false, true, false, false},
1346         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop,
1347                           kBaseRect.width() + 1, kBaseRect.height()),
1348          false, true, false, false},
1349         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop,
1350                           kBaseRect.width() + 1, kBaseRect.height() + 1),
1351          false, true, false, false},
1352         {SkRect::MakeXYWH(kBaseRect.fLeft - 1, kBaseRect.fTop,
1353                           kBaseRect.width(), kBaseRect.height()),
1354          false, true, false, false},
1355         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop - 1,
1356                           kBaseRect.width(), kBaseRect.height()),
1357          false, true, false, false},
1358         {SkRect::MakeXYWH(kBaseRect.fLeft - 1, kBaseRect.fTop,
1359                           kBaseRect.width() + 2, kBaseRect.height()),
1360          false, true, false, false},
1361         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop - 1,
1362                           kBaseRect.width() + 2, kBaseRect.height()),
1363          false, true, false, false},
1364
1365         // zero-w/h rects at each corner of kBaseRect
1366         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop, 0, 0), true, true, false, false},
1367         {SkRect::MakeXYWH(kBaseRect.fRight, kBaseRect.fTop, 0, 0), true, true, false, true},
1368         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fBottom, 0, 0), true, true, false, true},
1369         {SkRect::MakeXYWH(kBaseRect.fRight, kBaseRect.fBottom, 0, 0), true, true, false, true},
1370
1371         // far away rect
1372         {SkRect::MakeXYWH(10 * kBaseRect.fRight, 10 * kBaseRect.fBottom,
1373                           SkIntToScalar(10), SkIntToScalar(10)),
1374          false, false, false, false},
1375
1376         // very large rect containing kBaseRect
1377         {SkRect::MakeXYWH(kBaseRect.fLeft - 5 * kBaseRect.width(),
1378                           kBaseRect.fTop - 5 * kBaseRect.height(),
1379                           11 * kBaseRect.width(), 11 * kBaseRect.height()),
1380          false, false, false, false},
1381
1382         // skinny rect that spans same y-range as kBaseRect
1383         {SkRect::MakeXYWH(kBaseRect.centerX(), kBaseRect.fTop,
1384                           SkIntToScalar(1), kBaseRect.height()),
1385          true, true, true, true},
1386
1387         // short rect that spans same x-range as kBaseRect
1388         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.centerY(), kBaseRect.width(), SkScalar(1)),
1389          true, true, true, true},
1390
1391         // skinny rect that spans slightly larger y-range than kBaseRect
1392         {SkRect::MakeXYWH(kBaseRect.centerX(), kBaseRect.fTop,
1393                           SkIntToScalar(1), kBaseRect.height() + 1),
1394          false, true, false, false},
1395
1396         // short rect that spans slightly larger x-range than kBaseRect
1397         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.centerY(),
1398                           kBaseRect.width() + 1, SkScalar(1)),
1399          false, true, false, false},
1400     };
1401
1402     for (int inv = 0; inv < 4; ++inv) {
1403         for (size_t q = 0; q < SK_ARRAY_COUNT(kQueries); ++q) {
1404             SkRect qRect = kQueries[q].fQueryRect;
1405             if (inv & 0x1) {
1406                 SkTSwap(qRect.fLeft, qRect.fRight);
1407             }
1408             if (inv & 0x2) {
1409                 SkTSwap(qRect.fTop, qRect.fBottom);
1410             }
1411             for (int d = 0; d < 2; ++d) {
1412                 SkPath::Direction dir = d ? SkPath::kCCW_Direction : SkPath::kCW_Direction;
1413                 path.reset();
1414                 path.addRect(kBaseRect, dir);
1415                 REPORTER_ASSERT(reporter, kQueries[q].fInRect ==
1416                                           path.conservativelyContainsRect(qRect));
1417
1418                 path.reset();
1419                 path.addCircle(kCircleC.fX, kCircleC.fY, circleR, dir);
1420                 REPORTER_ASSERT(reporter, kQueries[q].fInCircle ==
1421                                           path.conservativelyContainsRect(qRect));
1422
1423                 path.reset();
1424                 path.addRoundRect(kBaseRect, kRRRadii[0], kRRRadii[1], dir);
1425                 REPORTER_ASSERT(reporter, kQueries[q].fInRR ==
1426                                           path.conservativelyContainsRect(qRect));
1427
1428                 path.reset();
1429                 path.moveTo(kBaseRect.fLeft + kRRRadii[0], kBaseRect.fTop);
1430                 path.cubicTo(kBaseRect.fLeft + kRRRadii[0] / 2, kBaseRect.fTop,
1431                              kBaseRect.fLeft, kBaseRect.fTop + kRRRadii[1] / 2,
1432                              kBaseRect.fLeft, kBaseRect.fTop + kRRRadii[1]);
1433                 path.lineTo(kBaseRect.fLeft, kBaseRect.fBottom);
1434                 path.lineTo(kBaseRect.fRight, kBaseRect.fBottom);
1435                 path.lineTo(kBaseRect.fRight, kBaseRect.fTop);
1436                 path.close();
1437                 REPORTER_ASSERT(reporter, kQueries[q].fInCubicRR ==
1438                                           path.conservativelyContainsRect(qRect));
1439
1440             }
1441             // Slightly non-convex shape, shouldn't contain any rects.
1442             path.reset();
1443             path.moveTo(0, 0);
1444             path.lineTo(SkIntToScalar(50), 0.05f);
1445             path.lineTo(SkIntToScalar(100), 0);
1446             path.lineTo(SkIntToScalar(100), SkIntToScalar(100));
1447             path.lineTo(0, SkIntToScalar(100));
1448             path.close();
1449             REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(qRect));
1450         }
1451     }
1452
1453     // make sure a minimal convex shape works, a right tri with edges along pos x and y axes.
1454     path.reset();
1455     path.moveTo(0, 0);
1456     path.lineTo(SkIntToScalar(100), 0);
1457     path.lineTo(0, SkIntToScalar(100));
1458
1459     // inside, on along top edge
1460     REPORTER_ASSERT(reporter, path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(50), 0,
1461                                                                                SkIntToScalar(10),
1462                                                                                SkIntToScalar(10))));
1463     // above
1464     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(
1465         SkRect::MakeXYWH(SkIntToScalar(50),
1466                          SkIntToScalar(-10),
1467                          SkIntToScalar(10),
1468                          SkIntToScalar(10))));
1469     // to the left
1470     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(-10),
1471                                                                                 SkIntToScalar(5),
1472                                                                                 SkIntToScalar(5),
1473                                                                                 SkIntToScalar(5))));
1474
1475     // outside the diagonal edge
1476     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(10),
1477                                                                                 SkIntToScalar(200),
1478                                                                                 SkIntToScalar(20),
1479                                                                                 SkIntToScalar(5))));
1480
1481     // same as above path and first test but with an extra moveTo.
1482     path.reset();
1483     path.moveTo(100, 100);
1484     path.moveTo(0, 0);
1485     path.lineTo(SkIntToScalar(100), 0);
1486     path.lineTo(0, SkIntToScalar(100));
1487
1488     REPORTER_ASSERT(reporter, path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(50), 0,
1489                                                                                SkIntToScalar(10),
1490                                                                                SkIntToScalar(10))));
1491
1492     path.reset();
1493     path.lineTo(100, 100);
1494     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeXYWH(0, 0, 1, 1)));
1495 }
1496
1497 static void test_isRect_open_close(skiatest::Reporter* reporter) {
1498     SkPath path;
1499     bool isClosed;
1500
1501     path.moveTo(0, 0); path.lineTo(1, 0); path.lineTo(1, 1); path.lineTo(0, 1);
1502     path.close();
1503
1504     REPORTER_ASSERT(reporter, path.isRect(NULL, NULL));
1505     REPORTER_ASSERT(reporter, path.isRect(&isClosed, NULL));
1506     REPORTER_ASSERT(reporter, isClosed);
1507     REPORTER_ASSERT(reporter, SkPath::kStroke_PathAsRect == path.asRect(NULL));
1508 }
1509
1510 // Simple isRect test is inline TestPath, below.
1511 // test_isRect provides more extensive testing.
1512 static void test_isRect(skiatest::Reporter* reporter) {
1513     test_isRect_open_close(reporter);
1514
1515     // passing tests (all moveTo / lineTo...
1516     SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
1517     SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
1518     SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
1519     SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
1520     SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
1521     SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
1522     SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
1523     SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
1524     SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
1525     SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f}, {1, 0}, {.5f, 0}};
1526     SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1}, {0, 1}, {0, .5f}};
1527     SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}};
1528     SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
1529     SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}};
1530     SkPoint rf[] = {{1, 0}, {8, 0}, {8, 8}, {0, 8}, {0, 0}};
1531
1532     // failing tests
1533     SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
1534     SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
1535     SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
1536     SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
1537     SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
1538     SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
1539     SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
1540     SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
1541     SkPoint f9[] = {{1, 0}, {8, 0}, {8, 8}, {0, 8}, {0, 0}, {2, 0}}; // overlaps
1542     SkPoint fa[] = {{1, 0}, {8, 0}, {8, 8}, {0, 8}, {0, -1}, {1, -1}}; // non colinear gap
1543     SkPoint fb[] = {{1, 0}, {8, 0}, {8, 8}, {0, 8}, {0, 1}}; // falls short
1544
1545     // no close, but we should detect them as fillably the same as a rect
1546     SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
1547     SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}};
1548     SkPoint c3[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}, {0, 0}}; // hit the start
1549
1550     // like c2, but we double-back on ourselves
1551     SkPoint d1[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}, {0, 2}};
1552     // like c2, but we overshoot the start point
1553     SkPoint d2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, -1}};
1554     SkPoint d3[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, -1}, {0, 0}};
1555
1556     struct IsRectTest {
1557         SkPoint *fPoints;
1558         size_t fPointCount;
1559         bool fClose;
1560         bool fIsRect;
1561     } tests[] = {
1562         { r1, SK_ARRAY_COUNT(r1), true, true },
1563         { r2, SK_ARRAY_COUNT(r2), true, true },
1564         { r3, SK_ARRAY_COUNT(r3), true, true },
1565         { r4, SK_ARRAY_COUNT(r4), true, true },
1566         { r5, SK_ARRAY_COUNT(r5), true, true },
1567         { r6, SK_ARRAY_COUNT(r6), true, true },
1568         { r7, SK_ARRAY_COUNT(r7), true, true },
1569         { r8, SK_ARRAY_COUNT(r8), true, true },
1570         { r9, SK_ARRAY_COUNT(r9), true, true },
1571         { ra, SK_ARRAY_COUNT(ra), true, true },
1572         { rb, SK_ARRAY_COUNT(rb), true, true },
1573         { rc, SK_ARRAY_COUNT(rc), true, true },
1574         { rd, SK_ARRAY_COUNT(rd), true, true },
1575         { re, SK_ARRAY_COUNT(re), true, true },
1576         { rf, SK_ARRAY_COUNT(rf), true, true },
1577
1578         { f1, SK_ARRAY_COUNT(f1), true, false },
1579         { f2, SK_ARRAY_COUNT(f2), true, false },
1580         { f3, SK_ARRAY_COUNT(f3), true, false },
1581         { f4, SK_ARRAY_COUNT(f4), true, false },
1582         { f5, SK_ARRAY_COUNT(f5), true, false },
1583         { f6, SK_ARRAY_COUNT(f6), true, false },
1584         { f7, SK_ARRAY_COUNT(f7), true, false },
1585         { f8, SK_ARRAY_COUNT(f8), true, false },
1586         { f9, SK_ARRAY_COUNT(f9), true, false },
1587         { fa, SK_ARRAY_COUNT(fa), true, false },
1588         { fb, SK_ARRAY_COUNT(fb), true, false },
1589
1590         { c1, SK_ARRAY_COUNT(c1), false, true },
1591         { c2, SK_ARRAY_COUNT(c2), false, true },
1592         { c3, SK_ARRAY_COUNT(c3), false, true },
1593
1594         { d1, SK_ARRAY_COUNT(d1), false, false },
1595         { d2, SK_ARRAY_COUNT(d2), false, false },
1596         { d3, SK_ARRAY_COUNT(d3), false, false },
1597     };
1598
1599     const size_t testCount = SK_ARRAY_COUNT(tests);
1600     size_t index;
1601     for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
1602         SkPath path;
1603         path.moveTo(tests[testIndex].fPoints[0].fX, tests[testIndex].fPoints[0].fY);
1604         for (index = 1; index < tests[testIndex].fPointCount; ++index) {
1605             path.lineTo(tests[testIndex].fPoints[index].fX, tests[testIndex].fPoints[index].fY);
1606         }
1607         if (tests[testIndex].fClose) {
1608             path.close();
1609         }
1610         REPORTER_ASSERT(reporter, tests[testIndex].fIsRect == path.isRect(NULL));
1611         REPORTER_ASSERT(reporter, tests[testIndex].fIsRect == path.isRect(NULL, NULL));
1612
1613         if (tests[testIndex].fIsRect) {
1614             SkRect computed, expected;
1615             expected.set(tests[testIndex].fPoints, tests[testIndex].fPointCount);
1616             REPORTER_ASSERT(reporter, path.isRect(&computed));
1617             REPORTER_ASSERT(reporter, expected == computed);
1618
1619             bool isClosed;
1620             SkPath::Direction direction, cheapDirection;
1621             REPORTER_ASSERT(reporter, path.cheapComputeDirection(&cheapDirection));
1622             REPORTER_ASSERT(reporter, path.isRect(&isClosed, &direction));
1623             REPORTER_ASSERT(reporter, isClosed == tests[testIndex].fClose);
1624             REPORTER_ASSERT(reporter, direction == cheapDirection);
1625             direction = (SkPath::Direction) -1;
1626             if (!tests[testIndex].fClose) {
1627                 REPORTER_ASSERT(reporter, SkPath::kFill_PathAsRect == path.asRect());
1628                 REPORTER_ASSERT(reporter, SkPath::kFill_PathAsRect == path.asRect(&direction));
1629             } else {
1630                 REPORTER_ASSERT(reporter, SkPath::kStroke_PathAsRect == path.asRect());
1631                 REPORTER_ASSERT(reporter, SkPath::kStroke_PathAsRect == path.asRect(&direction));
1632             }
1633             REPORTER_ASSERT(reporter, direction == cheapDirection);
1634         } else {
1635             SkRect computed;
1636             computed.set(123, 456, 789, 1011);
1637             REPORTER_ASSERT(reporter, !path.isRect(&computed));
1638             REPORTER_ASSERT(reporter, computed.fLeft == 123 && computed.fTop == 456);
1639             REPORTER_ASSERT(reporter, computed.fRight == 789 && computed.fBottom == 1011);
1640
1641             bool isClosed = (bool) -1;
1642             SkPath::Direction direction = (SkPath::Direction) -1;
1643             REPORTER_ASSERT(reporter, !path.isRect(&isClosed, &direction));
1644             REPORTER_ASSERT(reporter, isClosed == (bool) -1);
1645             REPORTER_ASSERT(reporter, direction == (SkPath::Direction) -1);
1646             REPORTER_ASSERT(reporter, SkPath::kNone_PathAsRect == path.asRect());
1647             REPORTER_ASSERT(reporter, SkPath::kNone_PathAsRect == path.asRect(&direction));
1648             REPORTER_ASSERT(reporter, direction == (SkPath::Direction) -1);
1649         }
1650     }
1651
1652     // fail, close then line
1653     SkPath path1;
1654     path1.moveTo(r1[0].fX, r1[0].fY);
1655     for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
1656         path1.lineTo(r1[index].fX, r1[index].fY);
1657     }
1658     path1.close();
1659     path1.lineTo(1, 0);
1660     REPORTER_ASSERT(reporter, !path1.isRect(NULL));
1661
1662     // fail, move in the middle
1663     path1.reset();
1664     path1.moveTo(r1[0].fX, r1[0].fY);
1665     for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
1666         if (index == 2) {
1667             path1.moveTo(1, .5f);
1668         }
1669         path1.lineTo(r1[index].fX, r1[index].fY);
1670     }
1671     path1.close();
1672     REPORTER_ASSERT(reporter, !path1.isRect(NULL));
1673
1674     // fail, move on the edge
1675     path1.reset();
1676     for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
1677         path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
1678         path1.lineTo(r1[index].fX, r1[index].fY);
1679     }
1680     path1.close();
1681     REPORTER_ASSERT(reporter, !path1.isRect(NULL));
1682
1683     // fail, quad
1684     path1.reset();
1685     path1.moveTo(r1[0].fX, r1[0].fY);
1686     for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
1687         if (index == 2) {
1688             path1.quadTo(1, .5f, 1, .5f);
1689         }
1690         path1.lineTo(r1[index].fX, r1[index].fY);
1691     }
1692     path1.close();
1693     REPORTER_ASSERT(reporter, !path1.isRect(NULL));
1694
1695     // fail, cubic
1696     path1.reset();
1697     path1.moveTo(r1[0].fX, r1[0].fY);
1698     for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
1699         if (index == 2) {
1700             path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
1701         }
1702         path1.lineTo(r1[index].fX, r1[index].fY);
1703     }
1704     path1.close();
1705     REPORTER_ASSERT(reporter, !path1.isRect(NULL));
1706 }
1707
1708 static void test_isNestedRects(skiatest::Reporter* reporter) {
1709     // passing tests (all moveTo / lineTo...
1710     SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // CW
1711     SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
1712     SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
1713     SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
1714     SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}}; // CCW
1715     SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
1716     SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
1717     SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
1718     SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
1719     SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f}, {1, 0}, {.5f, 0}}; // CCW
1720     SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1}, {0, 1}, {0, .5f}}; // CW
1721     SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}}; // CW
1722     SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}}; // CCW
1723     SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}}; // CW
1724
1725     // failing tests
1726     SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
1727     SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
1728     SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
1729     SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
1730     SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
1731     SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
1732     SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
1733     SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
1734
1735     // failing, no close
1736     SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match
1737     SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto
1738
1739     struct IsNestedRectTest {
1740         SkPoint *fPoints;
1741         size_t fPointCount;
1742         SkPath::Direction fDirection;
1743         bool fClose;
1744         bool fIsNestedRect; // nests with path.addRect(-1, -1, 2, 2);
1745     } tests[] = {
1746         { r1, SK_ARRAY_COUNT(r1), SkPath::kCW_Direction , true, true },
1747         { r2, SK_ARRAY_COUNT(r2), SkPath::kCW_Direction , true, true },
1748         { r3, SK_ARRAY_COUNT(r3), SkPath::kCW_Direction , true, true },
1749         { r4, SK_ARRAY_COUNT(r4), SkPath::kCW_Direction , true, true },
1750         { r5, SK_ARRAY_COUNT(r5), SkPath::kCCW_Direction, true, true },
1751         { r6, SK_ARRAY_COUNT(r6), SkPath::kCCW_Direction, true, true },
1752         { r7, SK_ARRAY_COUNT(r7), SkPath::kCCW_Direction, true, true },
1753         { r8, SK_ARRAY_COUNT(r8), SkPath::kCCW_Direction, true, true },
1754         { r9, SK_ARRAY_COUNT(r9), SkPath::kCCW_Direction, true, true },
1755         { ra, SK_ARRAY_COUNT(ra), SkPath::kCCW_Direction, true, true },
1756         { rb, SK_ARRAY_COUNT(rb), SkPath::kCW_Direction,  true, true },
1757         { rc, SK_ARRAY_COUNT(rc), SkPath::kCW_Direction,  true, true },
1758         { rd, SK_ARRAY_COUNT(rd), SkPath::kCCW_Direction, true, true },
1759         { re, SK_ARRAY_COUNT(re), SkPath::kCW_Direction,  true, true },
1760
1761         { f1, SK_ARRAY_COUNT(f1), SkPath::kUnknown_Direction, true, false },
1762         { f2, SK_ARRAY_COUNT(f2), SkPath::kUnknown_Direction, true, false },
1763         { f3, SK_ARRAY_COUNT(f3), SkPath::kUnknown_Direction, true, false },
1764         { f4, SK_ARRAY_COUNT(f4), SkPath::kUnknown_Direction, true, false },
1765         { f5, SK_ARRAY_COUNT(f5), SkPath::kUnknown_Direction, true, false },
1766         { f6, SK_ARRAY_COUNT(f6), SkPath::kUnknown_Direction, true, false },
1767         { f7, SK_ARRAY_COUNT(f7), SkPath::kUnknown_Direction, true, false },
1768         { f8, SK_ARRAY_COUNT(f8), SkPath::kUnknown_Direction, true, false },
1769
1770         { c1, SK_ARRAY_COUNT(c1), SkPath::kUnknown_Direction, false, false },
1771         { c2, SK_ARRAY_COUNT(c2), SkPath::kUnknown_Direction, false, false },
1772     };
1773
1774     const size_t testCount = SK_ARRAY_COUNT(tests);
1775     size_t index;
1776     for (int rectFirst = 0; rectFirst <= 1; ++rectFirst) {
1777         for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
1778             SkPath path;
1779             if (rectFirst) {
1780                 path.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
1781             }
1782             path.moveTo(tests[testIndex].fPoints[0].fX, tests[testIndex].fPoints[0].fY);
1783             for (index = 1; index < tests[testIndex].fPointCount; ++index) {
1784                 path.lineTo(tests[testIndex].fPoints[index].fX, tests[testIndex].fPoints[index].fY);
1785             }
1786             if (tests[testIndex].fClose) {
1787                 path.close();
1788             }
1789             if (!rectFirst) {
1790                 path.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
1791             }
1792             REPORTER_ASSERT(reporter, tests[testIndex].fIsNestedRect == path.isNestedRects(NULL));
1793             if (tests[testIndex].fIsNestedRect) {
1794                 SkRect expected[2], computed[2];
1795                 SkPath::Direction expectedDirs[2], computedDirs[2];
1796                 SkRect testBounds;
1797                 testBounds.set(tests[testIndex].fPoints, tests[testIndex].fPointCount);
1798                 expected[0] = SkRect::MakeLTRB(-1, -1, 2, 2);
1799                 expected[1] = testBounds;
1800                 if (rectFirst) {
1801                     expectedDirs[0] = SkPath::kCW_Direction;
1802                 } else {
1803                     expectedDirs[0] = SkPath::kCCW_Direction;
1804                 }
1805                 expectedDirs[1] = tests[testIndex].fDirection;
1806                 REPORTER_ASSERT(reporter, path.isNestedRects(computed, computedDirs));
1807                 REPORTER_ASSERT(reporter, expected[0] == computed[0]);
1808                 REPORTER_ASSERT(reporter, expected[1] == computed[1]);
1809                 REPORTER_ASSERT(reporter, expectedDirs[0] == computedDirs[0]);
1810                 REPORTER_ASSERT(reporter, expectedDirs[1] == computedDirs[1]);
1811             }
1812         }
1813
1814         // fail, close then line
1815         SkPath path1;
1816         if (rectFirst) {
1817             path1.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
1818         }
1819         path1.moveTo(r1[0].fX, r1[0].fY);
1820         for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
1821             path1.lineTo(r1[index].fX, r1[index].fY);
1822         }
1823         path1.close();
1824         path1.lineTo(1, 0);
1825         if (!rectFirst) {
1826             path1.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
1827         }
1828         REPORTER_ASSERT(reporter, !path1.isNestedRects(NULL));
1829
1830         // fail, move in the middle
1831         path1.reset();
1832         if (rectFirst) {
1833             path1.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
1834         }
1835         path1.moveTo(r1[0].fX, r1[0].fY);
1836         for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
1837             if (index == 2) {
1838                 path1.moveTo(1, .5f);
1839             }
1840             path1.lineTo(r1[index].fX, r1[index].fY);
1841         }
1842         path1.close();
1843         if (!rectFirst) {
1844             path1.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
1845         }
1846         REPORTER_ASSERT(reporter, !path1.isNestedRects(NULL));
1847
1848         // fail, move on the edge
1849         path1.reset();
1850         if (rectFirst) {
1851             path1.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
1852         }
1853         for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
1854             path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
1855             path1.lineTo(r1[index].fX, r1[index].fY);
1856         }
1857         path1.close();
1858         if (!rectFirst) {
1859             path1.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
1860         }
1861         REPORTER_ASSERT(reporter, !path1.isNestedRects(NULL));
1862
1863         // fail, quad
1864         path1.reset();
1865         if (rectFirst) {
1866             path1.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
1867         }
1868         path1.moveTo(r1[0].fX, r1[0].fY);
1869         for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
1870             if (index == 2) {
1871                 path1.quadTo(1, .5f, 1, .5f);
1872             }
1873             path1.lineTo(r1[index].fX, r1[index].fY);
1874         }
1875         path1.close();
1876         if (!rectFirst) {
1877             path1.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
1878         }
1879         REPORTER_ASSERT(reporter, !path1.isNestedRects(NULL));
1880
1881         // fail, cubic
1882         path1.reset();
1883         if (rectFirst) {
1884             path1.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
1885         }
1886         path1.moveTo(r1[0].fX, r1[0].fY);
1887         for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
1888             if (index == 2) {
1889                 path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
1890             }
1891             path1.lineTo(r1[index].fX, r1[index].fY);
1892         }
1893         path1.close();
1894         if (!rectFirst) {
1895             path1.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
1896         }
1897         REPORTER_ASSERT(reporter, !path1.isNestedRects(NULL));
1898
1899         // fail,  not nested
1900         path1.reset();
1901         path1.addRect(1, 1, 3, 3, SkPath::kCW_Direction);
1902         path1.addRect(2, 2, 4, 4, SkPath::kCW_Direction);
1903         REPORTER_ASSERT(reporter, !path1.isNestedRects(NULL));
1904     }
1905
1906     // pass, stroke rect
1907     SkPath src, dst;
1908     src.addRect(1, 1, 7, 7, SkPath::kCW_Direction);
1909     SkPaint strokePaint;
1910     strokePaint.setStyle(SkPaint::kStroke_Style);
1911     strokePaint.setStrokeWidth(2);
1912     strokePaint.getFillPath(src, &dst);
1913     REPORTER_ASSERT(reporter, dst.isNestedRects(NULL));
1914 }
1915
1916 static void write_and_read_back(skiatest::Reporter* reporter,
1917                                 const SkPath& p) {
1918     SkWriter32 writer;
1919     writer.writePath(p);
1920     size_t size = writer.bytesWritten();
1921     SkAutoMalloc storage(size);
1922     writer.flatten(storage.get());
1923     SkReader32 reader(storage.get(), size);
1924
1925     SkPath readBack;
1926     REPORTER_ASSERT(reporter, readBack != p);
1927     reader.readPath(&readBack);
1928     REPORTER_ASSERT(reporter, readBack == p);
1929
1930     REPORTER_ASSERT(reporter, readBack.getConvexityOrUnknown() ==
1931                               p.getConvexityOrUnknown());
1932
1933     REPORTER_ASSERT(reporter, readBack.isOval(NULL) == p.isOval(NULL));
1934
1935     const SkRect& origBounds = p.getBounds();
1936     const SkRect& readBackBounds = readBack.getBounds();
1937
1938     REPORTER_ASSERT(reporter, origBounds == readBackBounds);
1939 }
1940
1941 static void test_flattening(skiatest::Reporter* reporter) {
1942     SkPath p;
1943
1944     static const SkPoint pts[] = {
1945         { 0, 0 },
1946         { SkIntToScalar(10), SkIntToScalar(10) },
1947         { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
1948         { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
1949     };
1950     p.moveTo(pts[0]);
1951     p.lineTo(pts[1]);
1952     p.quadTo(pts[2], pts[3]);
1953     p.cubicTo(pts[4], pts[5], pts[6]);
1954
1955     write_and_read_back(reporter, p);
1956
1957     // create a buffer that should be much larger than the path so we don't
1958     // kill our stack if writer goes too far.
1959     char buffer[1024];
1960     size_t size1 = p.writeToMemory(NULL);
1961     size_t size2 = p.writeToMemory(buffer);
1962     REPORTER_ASSERT(reporter, size1 == size2);
1963
1964     SkPath p2;
1965     size_t size3 = p2.readFromMemory(buffer, 1024);
1966     REPORTER_ASSERT(reporter, size1 == size3);
1967     REPORTER_ASSERT(reporter, p == p2);
1968
1969     size3 = p2.readFromMemory(buffer, 0);
1970     REPORTER_ASSERT(reporter, !size3);
1971
1972     SkPath tooShort;
1973     size3 = tooShort.readFromMemory(buffer, size1 - 1);
1974     REPORTER_ASSERT(reporter, tooShort.isEmpty());
1975
1976     char buffer2[1024];
1977     size3 = p2.writeToMemory(buffer2);
1978     REPORTER_ASSERT(reporter, size1 == size3);
1979     REPORTER_ASSERT(reporter, memcmp(buffer, buffer2, size1) == 0);
1980
1981     // test persistence of the oval flag & convexity
1982     {
1983         SkPath oval;
1984         SkRect rect = SkRect::MakeWH(10, 10);
1985         oval.addOval(rect);
1986
1987         write_and_read_back(reporter, oval);
1988     }
1989 }
1990
1991 static void test_transform(skiatest::Reporter* reporter) {
1992     SkPath p;
1993
1994 #define CONIC_PERSPECTIVE_BUG_FIXED 0
1995     static const SkPoint pts[] = {
1996         { 0, 0 },  // move
1997         { SkIntToScalar(10), SkIntToScalar(10) },  // line
1998         { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },  // quad
1999         { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) },  // cubic
2000 #if CONIC_PERSPECTIVE_BUG_FIXED
2001         { 0, 0 }, { SkIntToScalar(20), SkIntToScalar(10) },  // conic
2002 #endif
2003     };
2004     const int kPtCount = SK_ARRAY_COUNT(pts);
2005
2006     p.moveTo(pts[0]);
2007     p.lineTo(pts[1]);
2008     p.quadTo(pts[2], pts[3]);
2009     p.cubicTo(pts[4], pts[5], pts[6]);
2010 #if CONIC_PERSPECTIVE_BUG_FIXED
2011     p.conicTo(pts[4], pts[5], 0.5f);
2012 #endif
2013     p.close();
2014
2015     {
2016         SkMatrix matrix;
2017         matrix.reset();
2018         SkPath p1;
2019         p.transform(matrix, &p1);
2020         REPORTER_ASSERT(reporter, p == p1);
2021     }
2022
2023
2024     {
2025         SkMatrix matrix;
2026         matrix.setScale(SK_Scalar1 * 2, SK_Scalar1 * 3);
2027
2028         SkPath p1;      // Leave p1 non-unique (i.e., the empty path)
2029
2030         p.transform(matrix, &p1);
2031         SkPoint pts1[kPtCount];
2032         int count = p1.getPoints(pts1, kPtCount);
2033         REPORTER_ASSERT(reporter, kPtCount == count);
2034         for (int i = 0; i < count; ++i) {
2035             SkPoint newPt = SkPoint::Make(pts[i].fX * 2, pts[i].fY * 3);
2036             REPORTER_ASSERT(reporter, newPt == pts1[i]);
2037         }
2038     }
2039
2040     {
2041         SkMatrix matrix;
2042         matrix.reset();
2043         matrix.setPerspX(SkScalarToPersp(4));
2044
2045         SkPath p1;
2046         p1.moveTo(SkPoint::Make(0, 0));
2047
2048         p.transform(matrix, &p1);
2049         REPORTER_ASSERT(reporter, matrix.invert(&matrix));
2050         p1.transform(matrix, NULL);
2051         SkRect pBounds = p.getBounds();
2052         SkRect p1Bounds = p1.getBounds();
2053         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(pBounds.fLeft, p1Bounds.fLeft));
2054         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(pBounds.fTop, p1Bounds.fTop));
2055         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(pBounds.fRight, p1Bounds.fRight));
2056         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(pBounds.fBottom, p1Bounds.fBottom));
2057     }
2058
2059     p.reset();
2060     p.addCircle(0, 0, 1, SkPath::kCW_Direction);
2061
2062     {
2063         SkMatrix matrix;
2064         matrix.reset();
2065         SkPath p1;
2066         p1.moveTo(SkPoint::Make(0, 0));
2067
2068         p.transform(matrix, &p1);
2069         REPORTER_ASSERT(reporter, p1.cheapIsDirection(SkPath::kCW_Direction));
2070     }
2071
2072
2073     {
2074         SkMatrix matrix;
2075         matrix.reset();
2076         matrix.setScaleX(-1);
2077         SkPath p1;
2078         p1.moveTo(SkPoint::Make(0, 0)); // Make p1 unique (i.e., not empty path)
2079
2080         p.transform(matrix, &p1);
2081         REPORTER_ASSERT(reporter, p1.cheapIsDirection(SkPath::kCCW_Direction));
2082     }
2083
2084     {
2085         SkMatrix matrix;
2086         matrix.setAll(1, 1, 0, 1, 1, 0, 0, 0, 1);
2087         SkPath p1;
2088         p1.moveTo(SkPoint::Make(0, 0)); // Make p1 unique (i.e., not empty path)
2089
2090         p.transform(matrix, &p1);
2091         REPORTER_ASSERT(reporter, p1.cheapIsDirection(SkPath::kUnknown_Direction));
2092     }
2093 }
2094
2095 static void test_zero_length_paths(skiatest::Reporter* reporter) {
2096     SkPath  p;
2097     uint8_t verbs[32];
2098
2099     struct SUPPRESS_VISIBILITY_WARNING zeroPathTestData {
2100         const char* testPath;
2101         const size_t numResultPts;
2102         const SkRect resultBound;
2103         const SkPath::Verb* resultVerbs;
2104         const size_t numResultVerbs;
2105     };
2106
2107     static const SkPath::Verb resultVerbs1[] = { SkPath::kMove_Verb };
2108     static const SkPath::Verb resultVerbs2[] = { SkPath::kMove_Verb, SkPath::kMove_Verb };
2109     static const SkPath::Verb resultVerbs3[] = { SkPath::kMove_Verb, SkPath::kClose_Verb };
2110     static const SkPath::Verb resultVerbs4[] = { SkPath::kMove_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kClose_Verb };
2111     static const SkPath::Verb resultVerbs5[] = { SkPath::kMove_Verb, SkPath::kLine_Verb };
2112     static const SkPath::Verb resultVerbs6[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kMove_Verb, SkPath::kLine_Verb };
2113     static const SkPath::Verb resultVerbs7[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb };
2114     static const SkPath::Verb resultVerbs8[] = {
2115         SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb
2116     };
2117     static const SkPath::Verb resultVerbs9[] = { SkPath::kMove_Verb, SkPath::kQuad_Verb };
2118     static const SkPath::Verb resultVerbs10[] = { SkPath::kMove_Verb, SkPath::kQuad_Verb, SkPath::kMove_Verb, SkPath::kQuad_Verb };
2119     static const SkPath::Verb resultVerbs11[] = { SkPath::kMove_Verb, SkPath::kQuad_Verb, SkPath::kClose_Verb };
2120     static const SkPath::Verb resultVerbs12[] = {
2121         SkPath::kMove_Verb, SkPath::kQuad_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kQuad_Verb, SkPath::kClose_Verb
2122     };
2123     static const SkPath::Verb resultVerbs13[] = { SkPath::kMove_Verb, SkPath::kCubic_Verb };
2124     static const SkPath::Verb resultVerbs14[] = { SkPath::kMove_Verb, SkPath::kCubic_Verb, SkPath::kMove_Verb, SkPath::kCubic_Verb };
2125     static const SkPath::Verb resultVerbs15[] = { SkPath::kMove_Verb, SkPath::kCubic_Verb, SkPath::kClose_Verb };
2126     static const SkPath::Verb resultVerbs16[] = {
2127         SkPath::kMove_Verb, SkPath::kCubic_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kCubic_Verb, SkPath::kClose_Verb
2128     };
2129     static const struct zeroPathTestData gZeroLengthTests[] = {
2130         { "M 1 1", 1, {0, 0, 0, 0}, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
2131         { "M 1 1 M 2 1", 2, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs2, SK_ARRAY_COUNT(resultVerbs2) },
2132         { "M 1 1 z", 1, {0, 0, 0, 0}, resultVerbs3, SK_ARRAY_COUNT(resultVerbs3) },
2133         { "M 1 1 z M 2 1 z", 2, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs4, SK_ARRAY_COUNT(resultVerbs4) },
2134         { "M 1 1 L 1 1", 2, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs5, SK_ARRAY_COUNT(resultVerbs5) },
2135         { "M 1 1 L 1 1 M 2 1 L 2 1", 4, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs6, SK_ARRAY_COUNT(resultVerbs6) },
2136         { "M 1 1 L 1 1 z", 2, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs7, SK_ARRAY_COUNT(resultVerbs7) },
2137         { "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, SK_ARRAY_COUNT(resultVerbs8) },
2138         { "M 1 1 Q 1 1 1 1", 3, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs9, SK_ARRAY_COUNT(resultVerbs9) },
2139         { "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, SK_ARRAY_COUNT(resultVerbs10) },
2140         { "M 1 1 Q 1 1 1 1 z", 3, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs11, SK_ARRAY_COUNT(resultVerbs11) },
2141         { "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, SK_ARRAY_COUNT(resultVerbs12) },
2142         { "M 1 1 C 1 1 1 1 1 1", 4, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs13, SK_ARRAY_COUNT(resultVerbs13) },
2143         { "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,
2144             SK_ARRAY_COUNT(resultVerbs14)
2145         },
2146         { "M 1 1 C 1 1 1 1 1 1 z", 4, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs15, SK_ARRAY_COUNT(resultVerbs15) },
2147         { "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,
2148             SK_ARRAY_COUNT(resultVerbs16)
2149         }
2150     };
2151
2152     for (size_t i = 0; i < SK_ARRAY_COUNT(gZeroLengthTests); ++i) {
2153         p.reset();
2154         bool valid = SkParsePath::FromSVGString(gZeroLengthTests[i].testPath, &p);
2155         REPORTER_ASSERT(reporter, valid);
2156         REPORTER_ASSERT(reporter, !p.isEmpty());
2157         REPORTER_ASSERT(reporter, gZeroLengthTests[i].numResultPts == (size_t)p.countPoints());
2158         REPORTER_ASSERT(reporter, gZeroLengthTests[i].resultBound == p.getBounds());
2159         REPORTER_ASSERT(reporter, gZeroLengthTests[i].numResultVerbs == (size_t)p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
2160         for (size_t j = 0; j < gZeroLengthTests[i].numResultVerbs; ++j) {
2161             REPORTER_ASSERT(reporter, gZeroLengthTests[i].resultVerbs[j] == verbs[j]);
2162         }
2163     }
2164 }
2165
2166 struct SegmentInfo {
2167     SkPath fPath;
2168     int    fPointCount;
2169 };
2170
2171 #define kCurveSegmentMask   (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)
2172
2173 static void test_segment_masks(skiatest::Reporter* reporter) {
2174     SkPath p, p2;
2175
2176     p.moveTo(0, 0);
2177     p.quadTo(100, 100, 200, 200);
2178     REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == p.getSegmentMasks());
2179     REPORTER_ASSERT(reporter, !p.isEmpty());
2180     p2 = p;
2181     REPORTER_ASSERT(reporter, p2.getSegmentMasks() == p.getSegmentMasks());
2182     p.cubicTo(100, 100, 200, 200, 300, 300);
2183     REPORTER_ASSERT(reporter, kCurveSegmentMask == p.getSegmentMasks());
2184     REPORTER_ASSERT(reporter, !p.isEmpty());
2185     p2 = p;
2186     REPORTER_ASSERT(reporter, p2.getSegmentMasks() == p.getSegmentMasks());
2187
2188     p.reset();
2189     p.moveTo(0, 0);
2190     p.cubicTo(100, 100, 200, 200, 300, 300);
2191     REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == p.getSegmentMasks());
2192     p2 = p;
2193     REPORTER_ASSERT(reporter, p2.getSegmentMasks() == p.getSegmentMasks());
2194
2195     REPORTER_ASSERT(reporter, !p.isEmpty());
2196 }
2197
2198 static void test_iter(skiatest::Reporter* reporter) {
2199     SkPath  p;
2200     SkPoint pts[4];
2201
2202     // Test an iterator with no path
2203     SkPath::Iter noPathIter;
2204     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
2205
2206     // Test that setting an empty path works
2207     noPathIter.setPath(p, false);
2208     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
2209
2210     // Test that close path makes no difference for an empty path
2211     noPathIter.setPath(p, true);
2212     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
2213
2214     // Test an iterator with an initial empty path
2215     SkPath::Iter iter(p, false);
2216     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
2217
2218     // Test that close path makes no difference
2219     iter.setPath(p, true);
2220     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
2221
2222
2223     struct iterTestData {
2224         const char* testPath;
2225         const bool forceClose;
2226         const bool consumeDegenerates;
2227         const size_t* numResultPtsPerVerb;
2228         const SkPoint* resultPts;
2229         const SkPath::Verb* resultVerbs;
2230         const size_t numResultVerbs;
2231     };
2232
2233     static const SkPath::Verb resultVerbs1[] = { SkPath::kDone_Verb };
2234     static const SkPath::Verb resultVerbs2[] = {
2235         SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kDone_Verb
2236     };
2237     static const SkPath::Verb resultVerbs3[] = {
2238         SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb, SkPath::kDone_Verb
2239     };
2240     static const SkPath::Verb resultVerbs4[] = {
2241         SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kMove_Verb, SkPath::kClose_Verb, SkPath::kDone_Verb
2242     };
2243     static const SkPath::Verb resultVerbs5[] = {
2244         SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kClose_Verb, SkPath::kDone_Verb
2245     };
2246     static const size_t resultPtsSizes1[] = { 0 };
2247     static const size_t resultPtsSizes2[] = { 1, 2, 2, 0 };
2248     static const size_t resultPtsSizes3[] = { 1, 2, 2, 2, 1, 0 };
2249     static const size_t resultPtsSizes4[] = { 1, 2, 1, 1, 0 };
2250     static const size_t resultPtsSizes5[] = { 1, 2, 1, 1, 1, 0 };
2251     static const SkPoint* resultPts1 = 0;
2252     static const SkPoint resultPts2[] = {
2253         { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, SK_Scalar1 }, { SK_Scalar1, SK_Scalar1 }, { 0, SK_Scalar1 }
2254     };
2255     static const SkPoint resultPts3[] = {
2256         { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, SK_Scalar1 }, { SK_Scalar1, SK_Scalar1 }, { 0, SK_Scalar1 },
2257         { 0, SK_Scalar1 }, { SK_Scalar1, 0 }, { SK_Scalar1, 0 }
2258     };
2259     static const SkPoint resultPts4[] = {
2260         { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { 0, 0 }, { 0, 0 }
2261     };
2262     static const SkPoint resultPts5[] = {
2263         { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { 0, 0 }, { 0, 0 }
2264     };
2265     static const struct iterTestData gIterTests[] = {
2266         { "M 1 0", false, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
2267         { "M 1 0 M 2 0 M 3 0 M 4 0 M 5 0", false, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
2268         { "M 1 0 M 1 0 M 3 0 M 4 0 M 5 0", true, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
2269         { "z", false, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
2270         { "z", true, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
2271         { "z M 1 0 z z M 2 0 z M 3 0 M 4 0 z", false, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
2272         { "z M 1 0 z z M 2 0 z M 3 0 M 4 0 z", true, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
2273         { "M 1 0 L 1 1 L 0 1 M 0 0 z", false, true, resultPtsSizes2, resultPts2, resultVerbs2, SK_ARRAY_COUNT(resultVerbs2) },
2274         { "M 1 0 L 1 1 L 0 1 M 0 0 z", true, true, resultPtsSizes3, resultPts3, resultVerbs3, SK_ARRAY_COUNT(resultVerbs3) },
2275         { "M 1 0 L 1 0 M 0 0 z", false, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
2276         { "M 1 0 L 1 0 M 0 0 z", true, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
2277         { "M 1 0 L 1 0 M 0 0 z", false, false, resultPtsSizes4, resultPts4, resultVerbs4, SK_ARRAY_COUNT(resultVerbs4) },
2278         { "M 1 0 L 1 0 M 0 0 z", true, false, resultPtsSizes5, resultPts5, resultVerbs5, SK_ARRAY_COUNT(resultVerbs5) }
2279     };
2280
2281     for (size_t i = 0; i < SK_ARRAY_COUNT(gIterTests); ++i) {
2282         p.reset();
2283         bool valid = SkParsePath::FromSVGString(gIterTests[i].testPath, &p);
2284         REPORTER_ASSERT(reporter, valid);
2285         iter.setPath(p, gIterTests[i].forceClose);
2286         int j = 0, l = 0;
2287         do {
2288             REPORTER_ASSERT(reporter, iter.next(pts, gIterTests[i].consumeDegenerates) == gIterTests[i].resultVerbs[j]);
2289             for (int k = 0; k < (int)gIterTests[i].numResultPtsPerVerb[j]; ++k) {
2290                 REPORTER_ASSERT(reporter, pts[k] == gIterTests[i].resultPts[l++]);
2291             }
2292         } while (gIterTests[i].resultVerbs[j++] != SkPath::kDone_Verb);
2293         REPORTER_ASSERT(reporter, j == (int)gIterTests[i].numResultVerbs);
2294     }
2295
2296     p.reset();
2297     iter.setPath(p, false);
2298     REPORTER_ASSERT(reporter, !iter.isClosedContour());
2299     p.lineTo(1, 1);
2300     p.close();
2301     iter.setPath(p, false);
2302     REPORTER_ASSERT(reporter, iter.isClosedContour());
2303     p.reset();
2304     iter.setPath(p, true);
2305     REPORTER_ASSERT(reporter, !iter.isClosedContour());
2306     p.lineTo(1, 1);
2307     iter.setPath(p, true);
2308     REPORTER_ASSERT(reporter, iter.isClosedContour());
2309     p.moveTo(0, 0);
2310     p.lineTo(2, 2);
2311     iter.setPath(p, false);
2312     REPORTER_ASSERT(reporter, !iter.isClosedContour());
2313
2314     // this checks to see if the NaN logic is executed in SkPath::autoClose(), but does not
2315     // check to see if the result is correct.
2316     for (int setNaN = 0; setNaN < 4; ++setNaN) {
2317         p.reset();
2318         p.moveTo(setNaN == 0 ? SK_ScalarNaN : 0, setNaN == 1 ? SK_ScalarNaN : 0);
2319         p.lineTo(setNaN == 2 ? SK_ScalarNaN : 1, setNaN == 3 ? SK_ScalarNaN : 1);
2320         iter.setPath(p, true);
2321         iter.next(pts, false);
2322         iter.next(pts, false);
2323         REPORTER_ASSERT(reporter, SkPath::kClose_Verb == iter.next(pts, false));
2324     }
2325
2326     p.reset();
2327     p.quadTo(0, 0, 0, 0);
2328     iter.setPath(p, false);
2329     iter.next(pts, false);
2330     REPORTER_ASSERT(reporter, SkPath::kQuad_Verb == iter.next(pts, false));
2331     iter.setPath(p, false);
2332     iter.next(pts, false);
2333     REPORTER_ASSERT(reporter, SkPath::kDone_Verb == iter.next(pts, true));
2334
2335     p.reset();
2336     p.conicTo(0, 0, 0, 0, 0.5f);
2337     iter.setPath(p, false);
2338     iter.next(pts, false);
2339     REPORTER_ASSERT(reporter, SkPath::kConic_Verb == iter.next(pts, false));
2340     iter.setPath(p, false);
2341     iter.next(pts, false);
2342     REPORTER_ASSERT(reporter, SkPath::kDone_Verb == iter.next(pts, true));
2343
2344     p.reset();
2345     p.cubicTo(0, 0, 0, 0, 0, 0);
2346     iter.setPath(p, false);
2347     iter.next(pts, false);
2348     REPORTER_ASSERT(reporter, SkPath::kCubic_Verb == iter.next(pts, false));
2349     iter.setPath(p, false);
2350     iter.next(pts, false);
2351     REPORTER_ASSERT(reporter, SkPath::kDone_Verb == iter.next(pts, true));
2352
2353     p.moveTo(1, 1);  // add a trailing moveto
2354     iter.setPath(p, false);
2355     iter.next(pts, false);
2356     REPORTER_ASSERT(reporter, SkPath::kCubic_Verb == iter.next(pts, false));
2357     iter.setPath(p, false);
2358     iter.next(pts, false);
2359     REPORTER_ASSERT(reporter, SkPath::kDone_Verb == iter.next(pts, true));
2360
2361     // The GM degeneratesegments.cpp test is more extensive
2362 }
2363
2364 static void test_raw_iter(skiatest::Reporter* reporter) {
2365     SkPath p;
2366     SkPoint pts[4];
2367
2368     // Test an iterator with no path
2369     SkPath::RawIter noPathIter;
2370     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
2371     // Test that setting an empty path works
2372     noPathIter.setPath(p);
2373     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
2374
2375     // Test an iterator with an initial empty path
2376     SkPath::RawIter iter(p);
2377     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
2378
2379     // Test that a move-only path returns the move.
2380     p.moveTo(SK_Scalar1, 0);
2381     iter.setPath(p);
2382     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
2383     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
2384     REPORTER_ASSERT(reporter, pts[0].fY == 0);
2385     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
2386
2387     // No matter how many moves we add, we should get them all back
2388     p.moveTo(SK_Scalar1*2, SK_Scalar1);
2389     p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
2390     iter.setPath(p);
2391     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
2392     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
2393     REPORTER_ASSERT(reporter, pts[0].fY == 0);
2394     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
2395     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
2396     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
2397     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
2398     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
2399     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
2400     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
2401
2402     // Initial close is never ever stored
2403     p.reset();
2404     p.close();
2405     iter.setPath(p);
2406     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
2407
2408     // Move/close sequences
2409     p.reset();
2410     p.close(); // Not stored, no purpose
2411     p.moveTo(SK_Scalar1, 0);
2412     p.close();
2413     p.close(); // Not stored, no purpose
2414     p.moveTo(SK_Scalar1*2, SK_Scalar1);
2415     p.close();
2416     p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
2417     p.moveTo(SK_Scalar1*4, SK_Scalar1*3);
2418     p.close();
2419     iter.setPath(p);
2420     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
2421     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
2422     REPORTER_ASSERT(reporter, pts[0].fY == 0);
2423     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
2424     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
2425     REPORTER_ASSERT(reporter, pts[0].fY == 0);
2426     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
2427     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
2428     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
2429     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
2430     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
2431     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
2432     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
2433     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
2434     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
2435     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
2436     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
2437     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
2438     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
2439     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
2440     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
2441     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
2442
2443     // Generate random paths and verify
2444     SkPoint randomPts[25];
2445     for (int i = 0; i < 5; ++i) {
2446         for (int j = 0; j < 5; ++j) {
2447             randomPts[i*5+j].set(SK_Scalar1*i, SK_Scalar1*j);
2448         }
2449     }
2450
2451     // Max of 10 segments, max 3 points per segment
2452     SkRandom rand(9876543);
2453     SkPoint          expectedPts[31]; // May have leading moveTo
2454     SkPath::Verb     expectedVerbs[22]; // May have leading moveTo
2455     SkPath::Verb     nextVerb;
2456
2457     for (int i = 0; i < 500; ++i) {
2458         p.reset();
2459         bool lastWasClose = true;
2460         bool haveMoveTo = false;
2461         SkPoint lastMoveToPt = { 0, 0 };
2462         int numPoints = 0;
2463         int numVerbs = (rand.nextU() >> 16) % 10;
2464         int numIterVerbs = 0;
2465         for (int j = 0; j < numVerbs; ++j) {
2466             do {
2467                 nextVerb = static_cast<SkPath::Verb>((rand.nextU() >> 16) % SkPath::kDone_Verb);
2468             } while (lastWasClose && nextVerb == SkPath::kClose_Verb);
2469             switch (nextVerb) {
2470                 case SkPath::kMove_Verb:
2471                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
2472                     p.moveTo(expectedPts[numPoints]);
2473                     lastMoveToPt = expectedPts[numPoints];
2474                     numPoints += 1;
2475                     lastWasClose = false;
2476                     haveMoveTo = true;
2477                     break;
2478                 case SkPath::kLine_Verb:
2479                     if (!haveMoveTo) {
2480                         expectedPts[numPoints++] = lastMoveToPt;
2481                         expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
2482                         haveMoveTo = true;
2483                     }
2484                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
2485                     p.lineTo(expectedPts[numPoints]);
2486                     numPoints += 1;
2487                     lastWasClose = false;
2488                     break;
2489                 case SkPath::kQuad_Verb:
2490                     if (!haveMoveTo) {
2491                         expectedPts[numPoints++] = lastMoveToPt;
2492                         expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
2493                         haveMoveTo = true;
2494                     }
2495                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
2496                     expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
2497                     p.quadTo(expectedPts[numPoints], expectedPts[numPoints + 1]);
2498                     numPoints += 2;
2499                     lastWasClose = false;
2500                     break;
2501                 case SkPath::kConic_Verb:
2502                     if (!haveMoveTo) {
2503                         expectedPts[numPoints++] = lastMoveToPt;
2504                         expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
2505                         haveMoveTo = true;
2506                     }
2507                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
2508                     expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
2509                     p.conicTo(expectedPts[numPoints], expectedPts[numPoints + 1],
2510                               rand.nextUScalar1() * 4);
2511                     numPoints += 2;
2512                     lastWasClose = false;
2513                     break;
2514                 case SkPath::kCubic_Verb:
2515                     if (!haveMoveTo) {
2516                         expectedPts[numPoints++] = lastMoveToPt;
2517                         expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
2518                         haveMoveTo = true;
2519                     }
2520                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
2521                     expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
2522                     expectedPts[numPoints + 2] = randomPts[(rand.nextU() >> 16) % 25];
2523                     p.cubicTo(expectedPts[numPoints], expectedPts[numPoints + 1],
2524                               expectedPts[numPoints + 2]);
2525                     numPoints += 3;
2526                     lastWasClose = false;
2527                     break;
2528                 case SkPath::kClose_Verb:
2529                     p.close();
2530                     haveMoveTo = false;
2531                     lastWasClose = true;
2532                     break;
2533                 default:
2534                     SkDEBUGFAIL("unexpected verb");
2535             }
2536             expectedVerbs[numIterVerbs++] = nextVerb;
2537         }
2538
2539         iter.setPath(p);
2540         numVerbs = numIterVerbs;
2541         numIterVerbs = 0;
2542         int numIterPts = 0;
2543         SkPoint lastMoveTo;
2544         SkPoint lastPt;
2545         lastMoveTo.set(0, 0);
2546         lastPt.set(0, 0);
2547         while ((nextVerb = iter.next(pts)) != SkPath::kDone_Verb) {
2548             REPORTER_ASSERT(reporter, nextVerb == expectedVerbs[numIterVerbs]);
2549             numIterVerbs++;
2550             switch (nextVerb) {
2551                 case SkPath::kMove_Verb:
2552                     REPORTER_ASSERT(reporter, numIterPts < numPoints);
2553                     REPORTER_ASSERT(reporter, pts[0] == expectedPts[numIterPts]);
2554                     lastPt = lastMoveTo = pts[0];
2555                     numIterPts += 1;
2556                     break;
2557                 case SkPath::kLine_Verb:
2558                     REPORTER_ASSERT(reporter, numIterPts < numPoints + 1);
2559                     REPORTER_ASSERT(reporter, pts[0] == lastPt);
2560                     REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
2561                     lastPt = pts[1];
2562                     numIterPts += 1;
2563                     break;
2564                 case SkPath::kQuad_Verb:
2565                 case SkPath::kConic_Verb:
2566                     REPORTER_ASSERT(reporter, numIterPts < numPoints + 2);
2567                     REPORTER_ASSERT(reporter, pts[0] == lastPt);
2568                     REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
2569                     REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
2570                     lastPt = pts[2];
2571                     numIterPts += 2;
2572                     break;
2573                 case SkPath::kCubic_Verb:
2574                     REPORTER_ASSERT(reporter, numIterPts < numPoints + 3);
2575                     REPORTER_ASSERT(reporter, pts[0] == lastPt);
2576                     REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
2577                     REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
2578                     REPORTER_ASSERT(reporter, pts[3] == expectedPts[numIterPts + 2]);
2579                     lastPt = pts[3];
2580                     numIterPts += 3;
2581                     break;
2582                 case SkPath::kClose_Verb:
2583                     REPORTER_ASSERT(reporter, pts[0] == lastMoveTo);
2584                     lastPt = lastMoveTo;
2585                     break;
2586                 default:
2587                     SkDEBUGFAIL("unexpected verb");
2588             }
2589         }
2590         REPORTER_ASSERT(reporter, numIterPts == numPoints);
2591         REPORTER_ASSERT(reporter, numIterVerbs == numVerbs);
2592     }
2593 }
2594
2595 static void check_for_circle(skiatest::Reporter* reporter,
2596                              const SkPath& path,
2597                              bool expectedCircle,
2598                              SkPath::Direction expectedDir) {
2599     SkRect rect = SkRect::MakeEmpty();
2600     REPORTER_ASSERT(reporter, path.isOval(&rect) == expectedCircle);
2601     REPORTER_ASSERT(reporter, path.cheapIsDirection(expectedDir));
2602
2603     if (expectedCircle) {
2604         REPORTER_ASSERT(reporter, rect.height() == rect.width());
2605     }
2606 }
2607
2608 static void test_circle_skew(skiatest::Reporter* reporter,
2609                              const SkPath& path,
2610                              SkPath::Direction dir) {
2611     SkPath tmp;
2612
2613     SkMatrix m;
2614     m.setSkew(SkIntToScalar(3), SkIntToScalar(5));
2615     path.transform(m, &tmp);
2616     // this matrix reverses the direction.
2617     if (SkPath::kCCW_Direction == dir) {
2618         dir = SkPath::kCW_Direction;
2619     } else {
2620         REPORTER_ASSERT(reporter, SkPath::kCW_Direction == dir);
2621         dir = SkPath::kCCW_Direction;
2622     }
2623     check_for_circle(reporter, tmp, false, dir);
2624 }
2625
2626 static void test_circle_translate(skiatest::Reporter* reporter,
2627                                   const SkPath& path,
2628                                   SkPath::Direction dir) {
2629     SkPath tmp;
2630
2631     // translate at small offset
2632     SkMatrix m;
2633     m.setTranslate(SkIntToScalar(15), SkIntToScalar(15));
2634     path.transform(m, &tmp);
2635     check_for_circle(reporter, tmp, true, dir);
2636
2637     tmp.reset();
2638     m.reset();
2639
2640     // translate at a relatively big offset
2641     m.setTranslate(SkIntToScalar(1000), SkIntToScalar(1000));
2642     path.transform(m, &tmp);
2643     check_for_circle(reporter, tmp, true, dir);
2644 }
2645
2646 static void test_circle_rotate(skiatest::Reporter* reporter,
2647                                const SkPath& path,
2648                                SkPath::Direction dir) {
2649     for (int angle = 0; angle < 360; ++angle) {
2650         SkPath tmp;
2651         SkMatrix m;
2652         m.setRotate(SkIntToScalar(angle));
2653         path.transform(m, &tmp);
2654
2655         // TODO: a rotated circle whose rotated angle is not a multiple of 90
2656         // degrees is not an oval anymore, this can be improved.  we made this
2657         // for the simplicity of our implementation.
2658         if (angle % 90 == 0) {
2659             check_for_circle(reporter, tmp, true, dir);
2660         } else {
2661             check_for_circle(reporter, tmp, false, dir);
2662         }
2663     }
2664 }
2665
2666 static void test_circle_mirror_x(skiatest::Reporter* reporter,
2667                                  const SkPath& path,
2668                                  SkPath::Direction dir) {
2669     SkPath tmp;
2670     SkMatrix m;
2671     m.reset();
2672     m.setScaleX(-SK_Scalar1);
2673     path.transform(m, &tmp);
2674
2675     if (SkPath::kCW_Direction == dir) {
2676         dir = SkPath::kCCW_Direction;
2677     } else {
2678         REPORTER_ASSERT(reporter, SkPath::kCCW_Direction == dir);
2679         dir = SkPath::kCW_Direction;
2680     }
2681
2682     check_for_circle(reporter, tmp, true, dir);
2683 }
2684
2685 static void test_circle_mirror_y(skiatest::Reporter* reporter,
2686                                  const SkPath& path,
2687                                  SkPath::Direction dir) {
2688     SkPath tmp;
2689     SkMatrix m;
2690     m.reset();
2691     m.setScaleY(-SK_Scalar1);
2692     path.transform(m, &tmp);
2693
2694     if (SkPath::kCW_Direction == dir) {
2695         dir = SkPath::kCCW_Direction;
2696     } else {
2697         REPORTER_ASSERT(reporter, SkPath::kCCW_Direction == dir);
2698         dir = SkPath::kCW_Direction;
2699     }
2700
2701     check_for_circle(reporter, tmp, true, dir);
2702 }
2703
2704 static void test_circle_mirror_xy(skiatest::Reporter* reporter,
2705                                  const SkPath& path,
2706                                  SkPath::Direction dir) {
2707     SkPath tmp;
2708     SkMatrix m;
2709     m.reset();
2710     m.setScaleX(-SK_Scalar1);
2711     m.setScaleY(-SK_Scalar1);
2712     path.transform(m, &tmp);
2713
2714     check_for_circle(reporter, tmp, true, dir);
2715 }
2716
2717 static void test_circle_with_direction(skiatest::Reporter* reporter,
2718                                        SkPath::Direction dir) {
2719     SkPath path;
2720
2721     // circle at origin
2722     path.addCircle(0, 0, SkIntToScalar(20), dir);
2723     check_for_circle(reporter, path, true, dir);
2724     test_circle_rotate(reporter, path, dir);
2725     test_circle_translate(reporter, path, dir);
2726     test_circle_skew(reporter, path, dir);
2727
2728     // circle at an offset at (10, 10)
2729     path.reset();
2730     path.addCircle(SkIntToScalar(10), SkIntToScalar(10),
2731                    SkIntToScalar(20), dir);
2732     check_for_circle(reporter, path, true, dir);
2733     test_circle_rotate(reporter, path, dir);
2734     test_circle_translate(reporter, path, dir);
2735     test_circle_skew(reporter, path, dir);
2736     test_circle_mirror_x(reporter, path, dir);
2737     test_circle_mirror_y(reporter, path, dir);
2738     test_circle_mirror_xy(reporter, path, dir);
2739 }
2740
2741 static void test_circle_with_add_paths(skiatest::Reporter* reporter) {
2742     SkPath path;
2743     SkPath circle;
2744     SkPath rect;
2745     SkPath empty;
2746
2747     static const SkPath::Direction kCircleDir = SkPath::kCW_Direction;
2748     static const SkPath::Direction kCircleDirOpposite = SkPath::kCCW_Direction;
2749
2750     circle.addCircle(0, 0, SkIntToScalar(10), kCircleDir);
2751     rect.addRect(SkIntToScalar(5), SkIntToScalar(5),
2752                  SkIntToScalar(20), SkIntToScalar(20), SkPath::kCW_Direction);
2753
2754     SkMatrix translate;
2755     translate.setTranslate(SkIntToScalar(12), SkIntToScalar(12));
2756
2757     // Although all the path concatenation related operations leave
2758     // the path a circle, most mark it as a non-circle for simplicity
2759
2760     // empty + circle (translate)
2761     path = empty;
2762     path.addPath(circle, translate);
2763     check_for_circle(reporter, path, false, kCircleDir);
2764
2765     // circle + empty (translate)
2766     path = circle;
2767     path.addPath(empty, translate);
2768     check_for_circle(reporter, path, true, kCircleDir);
2769
2770     // test reverseAddPath
2771     path = circle;
2772     path.reverseAddPath(rect);
2773     check_for_circle(reporter, path, false, kCircleDirOpposite);
2774 }
2775
2776 static void test_circle(skiatest::Reporter* reporter) {
2777     test_circle_with_direction(reporter, SkPath::kCW_Direction);
2778     test_circle_with_direction(reporter, SkPath::kCCW_Direction);
2779
2780     // multiple addCircle()
2781     SkPath path;
2782     path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
2783     path.addCircle(0, 0, SkIntToScalar(20), SkPath::kCW_Direction);
2784     check_for_circle(reporter, path, false, SkPath::kCW_Direction);
2785
2786     // some extra lineTo() would make isOval() fail
2787     path.reset();
2788     path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
2789     path.lineTo(0, 0);
2790     check_for_circle(reporter, path, false, SkPath::kCW_Direction);
2791
2792     // not back to the original point
2793     path.reset();
2794     path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
2795     path.setLastPt(SkIntToScalar(5), SkIntToScalar(5));
2796     check_for_circle(reporter, path, false, SkPath::kCW_Direction);
2797
2798     test_circle_with_add_paths(reporter);
2799
2800     // test negative radius
2801     path.reset();
2802     path.addCircle(0, 0, -1, SkPath::kCW_Direction);
2803     REPORTER_ASSERT(reporter, path.isEmpty());
2804 }
2805
2806 static void test_oval(skiatest::Reporter* reporter) {
2807     SkRect rect;
2808     SkMatrix m;
2809     SkPath path;
2810
2811     rect = SkRect::MakeWH(SkIntToScalar(30), SkIntToScalar(50));
2812     path.addOval(rect);
2813
2814     REPORTER_ASSERT(reporter, path.isOval(NULL));
2815
2816     m.setRotate(SkIntToScalar(90));
2817     SkPath tmp;
2818     path.transform(m, &tmp);
2819     // an oval rotated 90 degrees is still an oval.
2820     REPORTER_ASSERT(reporter, tmp.isOval(NULL));
2821
2822     m.reset();
2823     m.setRotate(SkIntToScalar(30));
2824     tmp.reset();
2825     path.transform(m, &tmp);
2826     // an oval rotated 30 degrees is not an oval anymore.
2827     REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
2828
2829     // since empty path being transformed.
2830     path.reset();
2831     tmp.reset();
2832     m.reset();
2833     path.transform(m, &tmp);
2834     REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
2835
2836     // empty path is not an oval
2837     tmp.reset();
2838     REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
2839
2840     // only has moveTo()s
2841     tmp.reset();
2842     tmp.moveTo(0, 0);
2843     tmp.moveTo(SkIntToScalar(10), SkIntToScalar(10));
2844     REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
2845
2846     // mimic WebKit's calling convention,
2847     // call moveTo() first and then call addOval()
2848     path.reset();
2849     path.moveTo(0, 0);
2850     path.addOval(rect);
2851     REPORTER_ASSERT(reporter, path.isOval(NULL));
2852
2853     // copy path
2854     path.reset();
2855     tmp.reset();
2856     tmp.addOval(rect);
2857     path = tmp;
2858     REPORTER_ASSERT(reporter, path.isOval(NULL));
2859 }
2860
2861 static void test_empty(skiatest::Reporter* reporter, const SkPath& p) {
2862     SkPath  empty;
2863
2864     REPORTER_ASSERT(reporter, p.isEmpty());
2865     REPORTER_ASSERT(reporter, 0 == p.countPoints());
2866     REPORTER_ASSERT(reporter, 0 == p.countVerbs());
2867     REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
2868     REPORTER_ASSERT(reporter, p.isConvex());
2869     REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType);
2870     REPORTER_ASSERT(reporter, !p.isInverseFillType());
2871     REPORTER_ASSERT(reporter, p == empty);
2872     REPORTER_ASSERT(reporter, !(p != empty));
2873 }
2874
2875 static void test_rrect_is_convex(skiatest::Reporter* reporter, SkPath* path,
2876                                  SkPath::Direction dir) {
2877     REPORTER_ASSERT(reporter, path->isConvex());
2878     REPORTER_ASSERT(reporter, path->cheapIsDirection(dir));
2879     path->setConvexity(SkPath::kUnknown_Convexity);
2880     REPORTER_ASSERT(reporter, path->isConvex());
2881     path->reset();
2882 }
2883
2884 static void test_rrect(skiatest::Reporter* reporter) {
2885     SkPath p;
2886     SkRRect rr;
2887     SkVector radii[] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
2888     SkRect r = {10, 20, 30, 40};
2889     rr.setRectRadii(r, radii);
2890     p.addRRect(rr);
2891     test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
2892     p.addRRect(rr, SkPath::kCCW_Direction);
2893     test_rrect_is_convex(reporter, &p, SkPath::kCCW_Direction);
2894     p.addRoundRect(r, &radii[0].fX);
2895     test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
2896     p.addRoundRect(r, &radii[0].fX, SkPath::kCCW_Direction);
2897     test_rrect_is_convex(reporter, &p, SkPath::kCCW_Direction);
2898     p.addRoundRect(r, radii[1].fX, radii[1].fY);
2899     test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
2900     p.addRoundRect(r, radii[1].fX, radii[1].fY, SkPath::kCCW_Direction);
2901     test_rrect_is_convex(reporter, &p, SkPath::kCCW_Direction);
2902     for (size_t i = 0; i < SK_ARRAY_COUNT(radii); ++i) {
2903         SkVector save = radii[i];
2904         radii[i].set(0, 0);
2905         rr.setRectRadii(r, radii);
2906         p.addRRect(rr);
2907         test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
2908         radii[i] = save;
2909     }
2910     p.addRoundRect(r, 0, 0);
2911     SkRect returnedRect;
2912     REPORTER_ASSERT(reporter, p.isRect(&returnedRect));
2913     REPORTER_ASSERT(reporter, returnedRect == r);
2914     test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
2915     SkVector zeroRadii[] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}};
2916     rr.setRectRadii(r, zeroRadii);
2917     p.addRRect(rr);
2918     bool closed;
2919     SkPath::Direction dir;
2920     REPORTER_ASSERT(reporter, p.isRect(&closed, &dir));
2921     REPORTER_ASSERT(reporter, closed);
2922     REPORTER_ASSERT(reporter, SkPath::kCW_Direction == dir);
2923     test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
2924     p.addRRect(rr, SkPath::kCW_Direction);
2925     p.addRRect(rr, SkPath::kCW_Direction);
2926     REPORTER_ASSERT(reporter, !p.isConvex());
2927     p.reset();
2928     p.addRRect(rr, SkPath::kCCW_Direction);
2929     p.addRRect(rr, SkPath::kCCW_Direction);
2930     REPORTER_ASSERT(reporter, !p.isConvex());
2931     p.reset();
2932     SkRect emptyR = {10, 20, 10, 30};
2933     rr.setRectRadii(emptyR, radii);
2934     p.addRRect(rr);
2935     REPORTER_ASSERT(reporter, p.isEmpty());
2936     SkRect largeR = {0, 0, SK_ScalarMax, SK_ScalarMax};
2937     rr.setRectRadii(largeR, radii);
2938     p.addRRect(rr);
2939     test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
2940     SkRect infR = {0, 0, SK_ScalarMax, SK_ScalarInfinity};
2941     rr.setRectRadii(infR, radii);
2942     p.addRRect(rr);
2943     test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
2944     SkRect tinyR = {0, 0, 1e-9f, 1e-9f};
2945     p.addRoundRect(tinyR, 5e-11f, 5e-11f);
2946     test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
2947 }
2948
2949 static void test_arc(skiatest::Reporter* reporter) {
2950     SkPath p;
2951     SkRect emptyOval = {10, 20, 30, 20};
2952     REPORTER_ASSERT(reporter, emptyOval.isEmpty());
2953     p.addArc(emptyOval, 1, 2);
2954     REPORTER_ASSERT(reporter, p.isEmpty());
2955     p.reset();
2956     SkRect oval = {10, 20, 30, 40};
2957     p.addArc(oval, 1, 0);
2958     REPORTER_ASSERT(reporter, p.isEmpty());
2959     p.reset();
2960     SkPath cwOval;
2961     cwOval.addOval(oval);
2962     p.addArc(oval, 1, 360);
2963     REPORTER_ASSERT(reporter, p == cwOval);
2964     p.reset();
2965     SkPath ccwOval;
2966     ccwOval.addOval(oval, SkPath::kCCW_Direction);
2967     p.addArc(oval, 1, -360);
2968     REPORTER_ASSERT(reporter, p == ccwOval);
2969     p.reset();
2970     p.addArc(oval, 1, 180);
2971     REPORTER_ASSERT(reporter, p.isConvex());
2972     REPORTER_ASSERT(reporter, p.cheapIsDirection(SkPath::kCW_Direction));
2973     p.setConvexity(SkPath::kUnknown_Convexity);
2974     REPORTER_ASSERT(reporter, p.isConvex());
2975 }
2976
2977 static void check_move(skiatest::Reporter* reporter, SkPath::RawIter* iter,
2978                        SkScalar x0, SkScalar y0) {
2979     SkPoint pts[4];
2980     SkPath::Verb v = iter->next(pts);
2981     REPORTER_ASSERT(reporter, v == SkPath::kMove_Verb);
2982     REPORTER_ASSERT(reporter, pts[0].fX == x0);
2983     REPORTER_ASSERT(reporter, pts[0].fY == y0);
2984 }
2985
2986 static void check_line(skiatest::Reporter* reporter, SkPath::RawIter* iter,
2987                        SkScalar x1, SkScalar y1) {
2988     SkPoint pts[4];
2989     SkPath::Verb v = iter->next(pts);
2990     REPORTER_ASSERT(reporter, v == SkPath::kLine_Verb);
2991     REPORTER_ASSERT(reporter, pts[1].fX == x1);
2992     REPORTER_ASSERT(reporter, pts[1].fY == y1);
2993 }
2994
2995 static void check_quad(skiatest::Reporter* reporter, SkPath::RawIter* iter,
2996                        SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
2997     SkPoint pts[4];
2998     SkPath::Verb v = iter->next(pts);
2999     REPORTER_ASSERT(reporter, v == SkPath::kQuad_Verb);
3000     REPORTER_ASSERT(reporter, pts[1].fX == x1);
3001     REPORTER_ASSERT(reporter, pts[1].fY == y1);
3002     REPORTER_ASSERT(reporter, pts[2].fX == x2);
3003     REPORTER_ASSERT(reporter, pts[2].fY == y2);
3004 }
3005
3006 static void check_done(skiatest::Reporter* reporter, SkPath* p, SkPath::RawIter* iter) {
3007     SkPoint pts[4];
3008     SkPath::Verb v = iter->next(pts);
3009     REPORTER_ASSERT(reporter, v == SkPath::kDone_Verb);
3010 }
3011
3012 static void check_done_and_reset(skiatest::Reporter* reporter, SkPath* p, SkPath::RawIter* iter) {
3013     check_done(reporter, p, iter);
3014     p->reset();
3015 }
3016
3017 static void check_path_is_move_and_reset(skiatest::Reporter* reporter, SkPath* p,
3018                                          SkScalar x0, SkScalar y0) {
3019     SkPath::RawIter iter(*p);
3020     check_move(reporter, &iter, x0, y0);
3021     check_done_and_reset(reporter, p, &iter);
3022 }
3023
3024 static void check_path_is_line_and_reset(skiatest::Reporter* reporter, SkPath* p,
3025                                          SkScalar x1, SkScalar y1) {
3026     SkPath::RawIter iter(*p);
3027     check_move(reporter, &iter, 0, 0);
3028     check_line(reporter, &iter, x1, y1);
3029     check_done_and_reset(reporter, p, &iter);
3030 }
3031
3032 static void check_path_is_line(skiatest::Reporter* reporter, SkPath* p,
3033                                          SkScalar x1, SkScalar y1) {
3034     SkPath::RawIter iter(*p);
3035     check_move(reporter, &iter, 0, 0);
3036     check_line(reporter, &iter, x1, y1);
3037     check_done(reporter, p, &iter);
3038 }
3039
3040 static void check_path_is_line_pair_and_reset(skiatest::Reporter* reporter, SkPath* p,
3041                                     SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
3042     SkPath::RawIter iter(*p);
3043     check_move(reporter, &iter, 0, 0);
3044     check_line(reporter, &iter, x1, y1);
3045     check_line(reporter, &iter, x2, y2);
3046     check_done_and_reset(reporter, p, &iter);
3047 }
3048
3049 static void check_path_is_quad_and_reset(skiatest::Reporter* reporter, SkPath* p,
3050                                     SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
3051     SkPath::RawIter iter(*p);
3052     check_move(reporter, &iter, 0, 0);
3053     check_quad(reporter, &iter, x1, y1, x2, y2);
3054     check_done_and_reset(reporter, p, &iter);
3055 }
3056
3057 static void test_arcTo(skiatest::Reporter* reporter) {
3058     SkPath p;
3059     p.arcTo(0, 0, 1, 2, 1);
3060     check_path_is_line_and_reset(reporter, &p, 0, 0);
3061     p.arcTo(1, 2, 1, 2, 1);
3062     check_path_is_line_and_reset(reporter, &p, 1, 2);
3063     p.arcTo(1, 2, 3, 4, 0);
3064     check_path_is_line_and_reset(reporter, &p, 1, 2);
3065     p.arcTo(1, 2, 0, 0, 1);
3066     check_path_is_line_and_reset(reporter, &p, 1, 2);
3067     p.arcTo(1, 0, 1, 1, 1);
3068     SkPoint pt;
3069     REPORTER_ASSERT(reporter, p.getLastPt(&pt) && pt.fX == 1 && pt.fY == 1);
3070     p.reset();
3071     p.arcTo(1, 0, 1, -1, 1);
3072     REPORTER_ASSERT(reporter, p.getLastPt(&pt) && pt.fX == 1 && pt.fY == -1);
3073     p.reset();
3074     SkRect oval = {1, 2, 3, 4};
3075     p.arcTo(oval, 0, 0, true);
3076     check_path_is_move_and_reset(reporter, &p, oval.fRight, oval.centerY());
3077     p.arcTo(oval, 0, 0, false);
3078     check_path_is_move_and_reset(reporter, &p, oval.fRight, oval.centerY());
3079     p.arcTo(oval, 360, 0, true);
3080     check_path_is_move_and_reset(reporter, &p, oval.fRight, oval.centerY());
3081     p.arcTo(oval, 360, 0, false);
3082     check_path_is_move_and_reset(reporter, &p, oval.fRight, oval.centerY());
3083     for (float sweep = 359, delta = 0.5f; sweep != (float) (sweep + delta); ) {
3084         p.arcTo(oval, 0, sweep, false);
3085         REPORTER_ASSERT(reporter, p.getBounds() == oval);
3086         sweep += delta;
3087         delta /= 2;
3088     }
3089     for (float sweep = 361, delta = 0.5f; sweep != (float) (sweep - delta);) {
3090         p.arcTo(oval, 0, sweep, false);
3091         REPORTER_ASSERT(reporter, p.getBounds() == oval);
3092         sweep -= delta;
3093         delta /= 2;
3094     }
3095     SkRect noOvalWidth = {1, 2, 0, 3};
3096     p.reset();
3097     p.arcTo(noOvalWidth, 0, 360, false);
3098     REPORTER_ASSERT(reporter, p.isEmpty());
3099
3100     SkRect noOvalHeight = {1, 2, 3, 1};
3101     p.reset();
3102     p.arcTo(noOvalHeight, 0, 360, false);
3103     REPORTER_ASSERT(reporter, p.isEmpty());
3104 }
3105
3106 static void test_addPath(skiatest::Reporter* reporter) {
3107     SkPath p, q;
3108     p.lineTo(1, 2);
3109     q.moveTo(4, 4);
3110     q.lineTo(7, 8);
3111     q.conicTo(8, 7, 6, 5, 0.5f);
3112     q.quadTo(6, 7, 8, 6);
3113     q.cubicTo(5, 6, 7, 8, 7, 5);
3114     q.close();
3115     p.addPath(q, -4, -4);
3116     SkRect expected = {0, 0, 4, 4};
3117     REPORTER_ASSERT(reporter, p.getBounds() == expected);
3118     p.reset();
3119     p.reverseAddPath(q);
3120     SkRect reverseExpected = {4, 4, 8, 8};
3121     REPORTER_ASSERT(reporter, p.getBounds() == reverseExpected);
3122 }
3123
3124 static void test_addPathMode(skiatest::Reporter* reporter, bool explicitMoveTo, bool extend) {
3125     SkPath p, q;
3126     if (explicitMoveTo) {
3127         p.moveTo(1, 1);
3128     }
3129     p.lineTo(1, 2);
3130     if (explicitMoveTo) {
3131         q.moveTo(2, 1);
3132     }
3133     q.lineTo(2, 2);
3134     p.addPath(q, extend ? SkPath::kExtend_AddPathMode : SkPath::kAppend_AddPathMode);
3135     uint8_t verbs[4];
3136     int verbcount = p.getVerbs(verbs, 4);
3137     REPORTER_ASSERT(reporter, verbcount == 4);
3138     REPORTER_ASSERT(reporter, verbs[0] == SkPath::kMove_Verb);
3139     REPORTER_ASSERT(reporter, verbs[1] == SkPath::kLine_Verb);
3140     REPORTER_ASSERT(reporter, verbs[2] == (extend ? SkPath::kLine_Verb : SkPath::kMove_Verb));
3141     REPORTER_ASSERT(reporter, verbs[3] == SkPath::kLine_Verb);
3142 }
3143
3144 static void test_extendClosedPath(skiatest::Reporter* reporter) {
3145     SkPath p, q;
3146     p.moveTo(1, 1);
3147     p.lineTo(1, 2);
3148     p.lineTo(2, 2);
3149     p.close();
3150     q.moveTo(2, 1);
3151     q.lineTo(2, 3);
3152     p.addPath(q, SkPath::kExtend_AddPathMode);
3153     uint8_t verbs[7];
3154     int verbcount = p.getVerbs(verbs, 7);
3155     REPORTER_ASSERT(reporter, verbcount == 7);
3156     REPORTER_ASSERT(reporter, verbs[0] == SkPath::kMove_Verb);
3157     REPORTER_ASSERT(reporter, verbs[1] == SkPath::kLine_Verb);
3158     REPORTER_ASSERT(reporter, verbs[2] == SkPath::kLine_Verb);
3159     REPORTER_ASSERT(reporter, verbs[3] == SkPath::kClose_Verb);
3160     REPORTER_ASSERT(reporter, verbs[4] == SkPath::kMove_Verb);
3161     REPORTER_ASSERT(reporter, verbs[5] == SkPath::kLine_Verb);
3162     REPORTER_ASSERT(reporter, verbs[6] == SkPath::kLine_Verb);
3163
3164     SkPoint pt;
3165     REPORTER_ASSERT(reporter, p.getLastPt(&pt));
3166     REPORTER_ASSERT(reporter, pt == SkPoint::Make(2, 3));
3167     REPORTER_ASSERT(reporter, p.getPoint(3) == SkPoint::Make(1, 1));
3168 }
3169
3170 static void test_addEmptyPath(skiatest::Reporter* reporter, SkPath::AddPathMode mode) {
3171     SkPath p, q, r;
3172     // case 1: dst is empty
3173     p.moveTo(2, 1);
3174     p.lineTo(2, 3);
3175     q.addPath(p, mode);
3176     REPORTER_ASSERT(reporter, q == p);
3177     // case 2: src is empty
3178     p.addPath(r, mode);
3179     REPORTER_ASSERT(reporter, q == p);
3180     // case 3: src and dst are empty
3181     q.reset();
3182     q.addPath(r, mode);
3183     REPORTER_ASSERT(reporter, q.isEmpty());
3184 }
3185
3186 static void test_conicTo_special_case(skiatest::Reporter* reporter) {
3187     SkPath p;
3188     p.conicTo(1, 2, 3, 4, -1);
3189     check_path_is_line_and_reset(reporter, &p, 3, 4);
3190     p.conicTo(1, 2, 3, 4, SK_ScalarInfinity);
3191     check_path_is_line_pair_and_reset(reporter, &p, 1, 2, 3, 4);
3192     p.conicTo(1, 2, 3, 4, 1);
3193     check_path_is_quad_and_reset(reporter, &p, 1, 2, 3, 4);
3194 }
3195
3196 static void test_get_point(skiatest::Reporter* reporter) {
3197     SkPath p;
3198     SkPoint pt = p.getPoint(0);
3199     REPORTER_ASSERT(reporter, pt == SkPoint::Make(0, 0));
3200     REPORTER_ASSERT(reporter, !p.getLastPt(NULL));
3201     REPORTER_ASSERT(reporter, !p.getLastPt(&pt) && pt == SkPoint::Make(0, 0));
3202     p.setLastPt(10, 10);
3203     pt = p.getPoint(0);
3204     REPORTER_ASSERT(reporter, pt == SkPoint::Make(10, 10));
3205     REPORTER_ASSERT(reporter, p.getLastPt(NULL));
3206     p.rMoveTo(10, 10);
3207     REPORTER_ASSERT(reporter, p.getLastPt(&pt) && pt == SkPoint::Make(20, 20));
3208 }
3209
3210 static void test_contains(skiatest::Reporter* reporter) {
3211     SkPath p;
3212     p.setFillType(SkPath::kInverseWinding_FillType);
3213     REPORTER_ASSERT(reporter, p.contains(0, 0));
3214     p.setFillType(SkPath::kWinding_FillType);
3215     REPORTER_ASSERT(reporter, !p.contains(0, 0));
3216     p.moveTo(4, 4);
3217     p.lineTo(6, 8);
3218     p.lineTo(8, 4);
3219     // test quick reject
3220     REPORTER_ASSERT(reporter, !p.contains(4, 0));
3221     REPORTER_ASSERT(reporter, !p.contains(0, 4));
3222     REPORTER_ASSERT(reporter, !p.contains(4, 10));
3223     REPORTER_ASSERT(reporter, !p.contains(10, 4));
3224     // test various crossings in x
3225     REPORTER_ASSERT(reporter, !p.contains(5, 7));
3226     REPORTER_ASSERT(reporter, p.contains(6, 7));
3227     REPORTER_ASSERT(reporter, !p.contains(7, 7));
3228     p.reset();
3229     p.moveTo(4, 4);
3230     p.lineTo(8, 6);
3231     p.lineTo(4, 8);
3232     // test various crossings in y
3233     REPORTER_ASSERT(reporter, !p.contains(7, 5));
3234     REPORTER_ASSERT(reporter, p.contains(7, 6));
3235     REPORTER_ASSERT(reporter, !p.contains(7, 7));
3236     // test quads
3237     p.reset();
3238     p.moveTo(4, 4);
3239     p.quadTo(6, 6, 8, 8);
3240     p.quadTo(6, 8, 4, 8);
3241     p.quadTo(4, 6, 4, 4);
3242     REPORTER_ASSERT(reporter, p.contains(5, 6));
3243     REPORTER_ASSERT(reporter, !p.contains(6, 5));
3244
3245     p.reset();
3246     p.moveTo(6, 6);
3247     p.quadTo(8, 8, 6, 8);
3248     p.quadTo(4, 8, 4, 6);
3249     p.quadTo(4, 4, 6, 6);
3250     REPORTER_ASSERT(reporter, p.contains(5, 6));
3251     REPORTER_ASSERT(reporter, !p.contains(6, 5));
3252
3253 #define CONIC_CONTAINS_BUG_FIXED 0
3254 #if CONIC_CONTAINS_BUG_FIXED
3255     p.reset();
3256     p.moveTo(4, 4);
3257     p.conicTo(6, 6, 8, 8, 0.5f);
3258     p.conicTo(6, 8, 4, 8, 0.5f);
3259     p.conicTo(4, 6, 4, 4, 0.5f);
3260     REPORTER_ASSERT(reporter, p.contains(5, 6));
3261     REPORTER_ASSERT(reporter, !p.contains(6, 5));
3262 #endif
3263
3264     // test cubics
3265     SkPoint pts[] = {{5, 4}, {6, 5}, {7, 6}, {6, 6}, {4, 6}, {5, 7}, {5, 5}, {5, 4}, {6, 5}, {7, 6}};
3266     for (int i = 0; i < 3; ++i) {
3267         p.reset();
3268         p.setFillType(SkPath::kEvenOdd_FillType);
3269         p.moveTo(pts[i].fX, pts[i].fY);
3270         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);
3271         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);
3272         p.close();
3273         REPORTER_ASSERT(reporter, p.contains(5.5f, 5.5f));
3274         REPORTER_ASSERT(reporter, !p.contains(4.5f, 5.5f));
3275     }
3276 }
3277
3278 class PathRefTest_Private {
3279 public:
3280     static void TestPathRef(skiatest::Reporter* reporter) {
3281         static const int kRepeatCnt = 10;
3282
3283         SkAutoTUnref<SkPathRef> pathRef(SkNEW(SkPathRef));
3284
3285         SkPathRef::Editor ed(&pathRef);
3286
3287         {
3288             ed.growForRepeatedVerb(SkPath::kMove_Verb, kRepeatCnt);
3289             REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countVerbs());
3290             REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countPoints());
3291             REPORTER_ASSERT(reporter, 0 == pathRef->getSegmentMasks());
3292             for (int i = 0; i < kRepeatCnt; ++i) {
3293                 REPORTER_ASSERT(reporter, SkPath::kMove_Verb == pathRef->atVerb(i));
3294             }
3295             ed.resetToSize(0, 0, 0);
3296         }
3297
3298         {
3299             ed.growForRepeatedVerb(SkPath::kLine_Verb, kRepeatCnt);
3300             REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countVerbs());
3301             REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countPoints());
3302             REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == pathRef->getSegmentMasks());
3303             for (int i = 0; i < kRepeatCnt; ++i) {
3304                 REPORTER_ASSERT(reporter, SkPath::kLine_Verb == pathRef->atVerb(i));
3305             }
3306             ed.resetToSize(0, 0, 0);
3307         }
3308
3309         {
3310             ed.growForRepeatedVerb(SkPath::kQuad_Verb, kRepeatCnt);
3311             REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countVerbs());
3312             REPORTER_ASSERT(reporter, 2*kRepeatCnt == pathRef->countPoints());
3313             REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == pathRef->getSegmentMasks());
3314             for (int i = 0; i < kRepeatCnt; ++i) {
3315                 REPORTER_ASSERT(reporter, SkPath::kQuad_Verb == pathRef->atVerb(i));
3316             }
3317             ed.resetToSize(0, 0, 0);
3318         }
3319
3320         {
3321             SkScalar* weights = NULL;
3322             ed.growForRepeatedVerb(SkPath::kConic_Verb, kRepeatCnt, &weights);
3323             REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countVerbs());
3324             REPORTER_ASSERT(reporter, 2*kRepeatCnt == pathRef->countPoints());
3325             REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countWeights());
3326             REPORTER_ASSERT(reporter, SkPath::kConic_SegmentMask == pathRef->getSegmentMasks());
3327             REPORTER_ASSERT(reporter, NULL != weights);
3328             for (int i = 0; i < kRepeatCnt; ++i) {
3329                 REPORTER_ASSERT(reporter, SkPath::kConic_Verb == pathRef->atVerb(i));
3330             }
3331             ed.resetToSize(0, 0, 0);
3332         }
3333
3334         {
3335             ed.growForRepeatedVerb(SkPath::kCubic_Verb, kRepeatCnt);
3336             REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countVerbs());
3337             REPORTER_ASSERT(reporter, 3*kRepeatCnt == pathRef->countPoints());
3338             REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == pathRef->getSegmentMasks());
3339             for (int i = 0; i < kRepeatCnt; ++i) {
3340                 REPORTER_ASSERT(reporter, SkPath::kCubic_Verb == pathRef->atVerb(i));
3341             }
3342             ed.resetToSize(0, 0, 0);
3343         }
3344     }
3345 };
3346
3347 static void test_operatorEqual(skiatest::Reporter* reporter) {
3348     SkPath a;
3349     SkPath b;
3350     REPORTER_ASSERT(reporter, a == a);
3351     REPORTER_ASSERT(reporter, a == b);
3352     a.setFillType(SkPath::kInverseWinding_FillType);
3353     REPORTER_ASSERT(reporter, a != b);
3354     a.reset();
3355     REPORTER_ASSERT(reporter, a == b);
3356     a.lineTo(1, 1);
3357     REPORTER_ASSERT(reporter, a != b);
3358     a.reset();
3359     REPORTER_ASSERT(reporter, a == b);
3360     a.lineTo(1, 1);
3361     b.lineTo(1, 2);
3362     REPORTER_ASSERT(reporter, a != b);
3363     a.reset();
3364     a.lineTo(1, 2);
3365     REPORTER_ASSERT(reporter, a == b);
3366 }
3367
3368 static void compare_dump(skiatest::Reporter* reporter, const SkPath& path, bool force,
3369         const char* str) {
3370     SkDynamicMemoryWStream wStream;
3371     path.dump(&wStream, force);
3372     SkAutoDataUnref data(wStream.copyToData());
3373     REPORTER_ASSERT(reporter, data->size() == strlen(str));
3374     REPORTER_ASSERT(reporter, !memcmp(data->data(), str, strlen(str)));
3375 }
3376
3377 static void test_dump(skiatest::Reporter* reporter) {
3378     SkPath p;
3379     compare_dump(reporter, p, false, "");
3380     compare_dump(reporter, p, true, "");
3381     p.moveTo(1, 2);
3382     p.lineTo(3, 4);
3383     compare_dump(reporter, p, false, "path.moveTo(1, 2);\n"
3384                                      "path.lineTo(3, 4);\n");
3385     compare_dump(reporter, p, true,  "path.moveTo(1, 2);\n"
3386                                      "path.lineTo(3, 4);\n"
3387                                      "path.lineTo(1, 2);\n"
3388                                      "path.close();\n");
3389     p.reset();
3390     p.moveTo(1, 2);
3391     p.quadTo(3, 4, 5, 6);
3392     compare_dump(reporter, p, false, "path.moveTo(1, 2);\n"
3393                                      "path.quadTo(3, 4, 5, 6);\n");
3394     p.reset();
3395     p.moveTo(1, 2);
3396     p.conicTo(3, 4, 5, 6, 0.5f);
3397     compare_dump(reporter, p, false, "path.moveTo(1, 2);\n"
3398                                      "path.conicTo(3, 4, 5, 6, 0.5f);\n");
3399     p.reset();
3400     p.moveTo(1, 2);
3401     p.cubicTo(3, 4, 5, 6, 7, 8);
3402     compare_dump(reporter, p, false, "path.moveTo(1, 2);\n"
3403                                      "path.cubicTo(3, 4, 5, 6, 7, 8);\n");
3404 }
3405
3406 class PathTest_Private {
3407 public:
3408     static void TestPathTo(skiatest::Reporter* reporter) {
3409         SkPath p, q;
3410         p.lineTo(4, 4);
3411         p.reversePathTo(q);
3412         check_path_is_line(reporter, &p, 4, 4);
3413         q.moveTo(-4, -4);
3414         p.reversePathTo(q);
3415         check_path_is_line(reporter, &p, 4, 4);
3416         q.lineTo(7, 8);
3417         q.conicTo(8, 7, 6, 5, 0.5f);
3418         q.quadTo(6, 7, 8, 6);
3419         q.cubicTo(5, 6, 7, 8, 7, 5);
3420         q.close();
3421         p.reversePathTo(q);
3422         SkRect reverseExpected = {-4, -4, 8, 8};
3423         REPORTER_ASSERT(reporter, p.getBounds() == reverseExpected);
3424     }
3425 };
3426
3427 DEF_TEST(Paths, reporter) {
3428     test_path_crbug364224();
3429
3430     SkTSize<SkScalar>::Make(3,4);
3431
3432     SkPath  p, empty;
3433     SkRect  bounds, bounds2;
3434     test_empty(reporter, p);
3435
3436     REPORTER_ASSERT(reporter, p.getBounds().isEmpty());
3437
3438     // this triggers a code path in SkPath::operator= which is otherwise unexercised
3439     SkPath& self = p;
3440     p = self;
3441
3442     // this triggers a code path in SkPath::swap which is otherwise unexercised
3443     p.swap(self);
3444
3445     bounds.set(0, 0, SK_Scalar1, SK_Scalar1);
3446
3447     p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1);
3448     check_convex_bounds(reporter, p, bounds);
3449     // we have quads or cubics
3450     REPORTER_ASSERT(reporter, p.getSegmentMasks() & kCurveSegmentMask);
3451     REPORTER_ASSERT(reporter, !p.isEmpty());
3452
3453     p.reset();
3454     test_empty(reporter, p);
3455
3456     p.addOval(bounds);
3457     check_convex_bounds(reporter, p, bounds);
3458     REPORTER_ASSERT(reporter, !p.isEmpty());
3459
3460     p.rewind();
3461     test_empty(reporter, p);
3462
3463     p.addRect(bounds);
3464     check_convex_bounds(reporter, p, bounds);
3465     // we have only lines
3466     REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == p.getSegmentMasks());
3467     REPORTER_ASSERT(reporter, !p.isEmpty());
3468
3469     REPORTER_ASSERT(reporter, p != empty);
3470     REPORTER_ASSERT(reporter, !(p == empty));
3471
3472     // do getPoints and getVerbs return the right result
3473     REPORTER_ASSERT(reporter, p.getPoints(NULL, 0) == 4);
3474     REPORTER_ASSERT(reporter, p.getVerbs(NULL, 0) == 5);
3475     SkPoint pts[4];
3476     int count = p.getPoints(pts, 4);
3477     REPORTER_ASSERT(reporter, count == 4);
3478     uint8_t verbs[6];
3479     verbs[5] = 0xff;
3480     p.getVerbs(verbs, 5);
3481     REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
3482     REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[1]);
3483     REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[2]);
3484     REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[3]);
3485     REPORTER_ASSERT(reporter, SkPath::kClose_Verb == verbs[4]);
3486     REPORTER_ASSERT(reporter, 0xff == verbs[5]);
3487     bounds2.set(pts, 4);
3488     REPORTER_ASSERT(reporter, bounds == bounds2);
3489
3490     bounds.offset(SK_Scalar1*3, SK_Scalar1*4);
3491     p.offset(SK_Scalar1*3, SK_Scalar1*4);
3492     REPORTER_ASSERT(reporter, bounds == p.getBounds());
3493
3494     REPORTER_ASSERT(reporter, p.isRect(NULL));
3495     bounds2.setEmpty();
3496     REPORTER_ASSERT(reporter, p.isRect(&bounds2));
3497     REPORTER_ASSERT(reporter, bounds == bounds2);
3498
3499     // now force p to not be a rect
3500     bounds.set(0, 0, SK_Scalar1/2, SK_Scalar1/2);
3501     p.addRect(bounds);
3502     REPORTER_ASSERT(reporter, !p.isRect(NULL));
3503
3504     test_operatorEqual(reporter);
3505     test_isLine(reporter);
3506     test_isRect(reporter);
3507     test_isNestedRects(reporter);
3508     test_zero_length_paths(reporter);
3509     test_direction(reporter);
3510     test_convexity(reporter);
3511     test_convexity2(reporter);
3512     test_conservativelyContains(reporter);
3513     test_close(reporter);
3514     test_segment_masks(reporter);
3515     test_flattening(reporter);
3516     test_transform(reporter);
3517     test_bounds(reporter);
3518     test_iter(reporter);
3519     test_raw_iter(reporter);
3520     test_circle(reporter);
3521     test_oval(reporter);
3522     test_strokerec(reporter);
3523     test_addPoly(reporter);
3524     test_isfinite(reporter);
3525     test_isfinite_after_transform(reporter);
3526     test_arb_round_rect_is_convex(reporter);
3527     test_arb_zero_rad_round_rect_is_rect(reporter);
3528     test_addrect(reporter);
3529     test_addrect_isfinite(reporter);
3530     test_tricky_cubic();
3531     test_clipped_cubic();
3532     test_crbug_170666();
3533     test_bad_cubic_crbug229478();
3534     test_bad_cubic_crbug234190();
3535     test_android_specific_behavior(reporter);
3536     test_gen_id(reporter);
3537     test_path_close_issue1474(reporter);
3538     test_path_to_region(reporter);
3539     test_rrect(reporter);
3540     test_arc(reporter);
3541     test_arcTo(reporter);
3542     test_addPath(reporter);
3543     test_addPathMode(reporter, false, false);
3544     test_addPathMode(reporter, true, false);
3545     test_addPathMode(reporter, false, true);
3546     test_addPathMode(reporter, true, true);
3547     test_extendClosedPath(reporter);
3548     test_addEmptyPath(reporter, SkPath::kExtend_AddPathMode);
3549     test_addEmptyPath(reporter, SkPath::kAppend_AddPathMode);
3550     test_conicTo_special_case(reporter);
3551     test_get_point(reporter);
3552     test_contains(reporter);
3553     PathTest_Private::TestPathTo(reporter);
3554     PathRefTest_Private::TestPathRef(reporter);
3555     test_dump(reporter);
3556 }