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