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