Home | History | Annotate | Download | only in tests
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "Test.h"
      9 #include "SkCanvas.h"
     10 #include "SkPaint.h"
     11 #include "SkPath.h"
     12 #include "SkParse.h"
     13 #include "SkParsePath.h"
     14 #include "SkPathEffect.h"
     15 #include "SkRandom.h"
     16 #include "SkReader32.h"
     17 #include "SkSize.h"
     18 #include "SkWriter32.h"
     19 #include "SkSurface.h"
     20 
     21 #if defined(WIN32)
     22     #define SUPPRESS_VISIBILITY_WARNING
     23 #else
     24     #define SUPPRESS_VISIBILITY_WARNING __attribute__((visibility("hidden")))
     25 #endif
     26 
     27 static SkSurface* new_surface(int w, int h) {
     28     SkImage::Info info = {
     29         w, h, SkImage::kPMColor_ColorType, SkImage::kPremul_AlphaType
     30     };
     31     return SkSurface::NewRaster(info);
     32 }
     33 
     34 static void build_path_170666(SkPath& path) {
     35     path.moveTo(17.9459f, 21.6344f);
     36     path.lineTo(139.545f, -47.8105f);
     37     path.lineTo(139.545f, -47.8105f);
     38     path.lineTo(131.07f, -47.3888f);
     39     path.lineTo(131.07f, -47.3888f);
     40     path.lineTo(122.586f, -46.9532f);
     41     path.lineTo(122.586f, -46.9532f);
     42     path.lineTo(18076.6f, 31390.9f);
     43     path.lineTo(18076.6f, 31390.9f);
     44     path.lineTo(18085.1f, 31390.5f);
     45     path.lineTo(18085.1f, 31390.5f);
     46     path.lineTo(18076.6f, 31390.9f);
     47     path.lineTo(18076.6f, 31390.9f);
     48     path.lineTo(17955, 31460.3f);
     49     path.lineTo(17955, 31460.3f);
     50     path.lineTo(17963.5f, 31459.9f);
     51     path.lineTo(17963.5f, 31459.9f);
     52     path.lineTo(17971.9f, 31459.5f);
     53     path.lineTo(17971.9f, 31459.5f);
     54     path.lineTo(17.9551f, 21.6205f);
     55     path.lineTo(17.9551f, 21.6205f);
     56     path.lineTo(9.47091f, 22.0561f);
     57     path.lineTo(9.47091f, 22.0561f);
     58     path.lineTo(17.9459f, 21.6344f);
     59     path.lineTo(17.9459f, 21.6344f);
     60     path.close();path.moveTo(0.995934f, 22.4779f);
     61     path.lineTo(0.986725f, 22.4918f);
     62     path.lineTo(0.986725f, 22.4918f);
     63     path.lineTo(17955, 31460.4f);
     64     path.lineTo(17955, 31460.4f);
     65     path.lineTo(17971.9f, 31459.5f);
     66     path.lineTo(17971.9f, 31459.5f);
     67     path.lineTo(18093.6f, 31390.1f);
     68     path.lineTo(18093.6f, 31390.1f);
     69     path.lineTo(18093.6f, 31390);
     70     path.lineTo(18093.6f, 31390);
     71     path.lineTo(139.555f, -47.8244f);
     72     path.lineTo(139.555f, -47.8244f);
     73     path.lineTo(122.595f, -46.9671f);
     74     path.lineTo(122.595f, -46.9671f);
     75     path.lineTo(0.995934f, 22.4779f);
     76     path.lineTo(0.995934f, 22.4779f);
     77     path.close();
     78     path.moveTo(5.43941f, 25.5223f);
     79     path.lineTo(798267, -28871.1f);
     80     path.lineTo(798267, -28871.1f);
     81     path.lineTo(3.12512e+06f, -113102);
     82     path.lineTo(3.12512e+06f, -113102);
     83     path.cubicTo(5.16324e+06f, -186882, 8.15247e+06f, -295092, 1.1957e+07f, -432813);
     84     path.cubicTo(1.95659e+07f, -708257, 3.04359e+07f, -1.10175e+06f, 4.34798e+07f, -1.57394e+06f);
     85     path.cubicTo(6.95677e+07f, -2.51831e+06f, 1.04352e+08f, -3.77748e+06f, 1.39135e+08f, -5.03666e+06f);
     86     path.cubicTo(1.73919e+08f, -6.29583e+06f, 2.08703e+08f, -7.555e+06f, 2.34791e+08f, -8.49938e+06f);
     87     path.cubicTo(2.47835e+08f, -8.97157e+06f, 2.58705e+08f, -9.36506e+06f, 2.66314e+08f, -9.6405e+06f);
     88     path.cubicTo(2.70118e+08f, -9.77823e+06f, 2.73108e+08f, -9.88644e+06f, 2.75146e+08f, -9.96022e+06f);
     89     path.cubicTo(2.76165e+08f, -9.99711e+06f, 2.76946e+08f, -1.00254e+07f, 2.77473e+08f, -1.00444e+07f);
     90     path.lineTo(2.78271e+08f, -1.00733e+07f);
     91     path.lineTo(2.78271e+08f, -1.00733e+07f);
     92     path.cubicTo(2.78271e+08f, -1.00733e+07f, 2.08703e+08f, -7.555e+06f, 135.238f, 23.3517f);
     93     path.cubicTo(131.191f, 23.4981f, 125.995f, 23.7976f, 123.631f, 24.0206f);
     94     path.cubicTo(121.267f, 24.2436f, 122.631f, 24.3056f, 126.677f, 24.1591f);
     95     path.cubicTo(2.08703e+08f, -7.555e+06f, 2.78271e+08f, -1.00733e+07f, 2.78271e+08f, -1.00733e+07f);
     96     path.lineTo(2.77473e+08f, -1.00444e+07f);
     97     path.lineTo(2.77473e+08f, -1.00444e+07f);
     98     path.cubicTo(2.76946e+08f, -1.00254e+07f, 2.76165e+08f, -9.99711e+06f, 2.75146e+08f, -9.96022e+06f);
     99     path.cubicTo(2.73108e+08f, -9.88644e+06f, 2.70118e+08f, -9.77823e+06f, 2.66314e+08f, -9.6405e+06f);
    100     path.cubicTo(2.58705e+08f, -9.36506e+06f, 2.47835e+08f, -8.97157e+06f, 2.34791e+08f, -8.49938e+06f);
    101     path.cubicTo(2.08703e+08f, -7.555e+06f, 1.73919e+08f, -6.29583e+06f, 1.39135e+08f, -5.03666e+06f);
    102     path.cubicTo(1.04352e+08f, -3.77749e+06f, 6.95677e+07f, -2.51831e+06f, 4.34798e+07f, -1.57394e+06f);
    103     path.cubicTo(3.04359e+07f, -1.10175e+06f, 1.95659e+07f, -708258, 1.1957e+07f, -432814);
    104     path.cubicTo(8.15248e+06f, -295092, 5.16324e+06f, -186883, 3.12513e+06f, -113103);
    105     path.lineTo(798284, -28872);
    106     path.lineTo(798284, -28872);
    107     path.lineTo(22.4044f, 24.6677f);
    108     path.lineTo(22.4044f, 24.6677f);
    109     path.cubicTo(22.5186f, 24.5432f, 18.8134f, 24.6337f, 14.1287f, 24.8697f);
    110     path.cubicTo(9.4439f, 25.1057f, 5.55359f, 25.3978f, 5.43941f, 25.5223f);
    111     path.close();
    112 }
    113 
    114 static void build_path_simple_170666(SkPath& path) {
    115     path.moveTo(126.677f, 24.1591f);
    116     path.cubicTo(2.08703e+08f, -7.555e+06f, 2.78271e+08f, -1.00733e+07f, 2.78271e+08f, -1.00733e+07f);
    117 }
    118 
    119 // This used to assert in the SK_DEBUG build, as the clip step would fail with
    120 // too-few interations in our cubic-line intersection code. That code now runs
    121 // 24 interations (instead of 16).
    122 static void test_crbug_170666(skiatest::Reporter* reporter) {
    123     SkPath path;
    124     SkPaint paint;
    125     paint.setAntiAlias(true);
    126 
    127     SkAutoTUnref<SkSurface> surface(new_surface(1000, 1000));
    128 
    129     build_path_simple_170666(path);
    130     surface->getCanvas()->drawPath(path, paint);
    131 
    132     build_path_170666(path);
    133     surface->getCanvas()->drawPath(path, paint);
    134 }
    135 
    136 // Make sure we stay non-finite once we get there (unless we reset or rewind).
    137 static void test_addrect_isfinite(skiatest::Reporter* reporter) {
    138     SkPath path;
    139 
    140     path.addRect(SkRect::MakeWH(50, 100));
    141     REPORTER_ASSERT(reporter, path.isFinite());
    142 
    143     path.moveTo(0, 0);
    144     path.lineTo(SK_ScalarInfinity, 42);
    145     REPORTER_ASSERT(reporter, !path.isFinite());
    146 
    147     path.addRect(SkRect::MakeWH(50, 100));
    148     REPORTER_ASSERT(reporter, !path.isFinite());
    149 
    150     path.reset();
    151     REPORTER_ASSERT(reporter, path.isFinite());
    152 
    153     path.addRect(SkRect::MakeWH(50, 100));
    154     REPORTER_ASSERT(reporter, path.isFinite());
    155 }
    156 
    157 static void build_big_path(SkPath* path, bool reducedCase) {
    158     if (reducedCase) {
    159         path->moveTo(577330, 1971.72f);
    160         path->cubicTo(10.7082f, -116.596f, 262.057f, 45.6468f, 294.694f, 1.96237f);
    161     } else {
    162         path->moveTo(60.1631f, 7.70567f);
    163         path->quadTo(60.1631f, 7.70567f, 0.99474f, 0.901199f);
    164         path->lineTo(577379, 1977.77f);
    165         path->quadTo(577364, 1979.57f, 577325, 1980.26f);
    166         path->quadTo(577286, 1980.95f, 577245, 1980.13f);
    167         path->quadTo(577205, 1979.3f, 577187, 1977.45f);
    168         path->quadTo(577168, 1975.6f, 577183, 1973.8f);
    169         path->quadTo(577198, 1972, 577238, 1971.31f);
    170         path->quadTo(577277, 1970.62f, 577317, 1971.45f);
    171         path->quadTo(577330, 1971.72f, 577341, 1972.11f);
    172         path->cubicTo(10.7082f, -116.596f, 262.057f, 45.6468f, 294.694f, 1.96237f);
    173         path->moveTo(306.718f, -32.912f);
    174         path->cubicTo(30.531f, 10.0005f, 1502.47f, 13.2804f, 84.3088f, 9.99601f);
    175     }
    176 }
    177 
    178 static void test_clipped_cubic(skiatest::Reporter* reporter) {
    179     SkAutoTUnref<SkSurface> surface(new_surface(640, 480));
    180 
    181     // This path used to assert, because our cubic-chopping code incorrectly
    182     // moved control points after the chop. This test should be run in SK_DEBUG
    183     // mode to ensure that we no long assert.
    184     SkPath path;
    185     for (int doReducedCase = 0; doReducedCase <= 1; ++doReducedCase) {
    186         build_big_path(&path, SkToBool(doReducedCase));
    187 
    188         SkPaint paint;
    189         for (int doAA = 0; doAA <= 1; ++doAA) {
    190             paint.setAntiAlias(SkToBool(doAA));
    191             surface->getCanvas()->drawPath(path, paint);
    192         }
    193     }
    194 }
    195 
    196 // Inspired by http://ie.microsoft.com/testdrive/Performance/Chalkboard/
    197 // which triggered an assert, from a tricky cubic. This test replicates that
    198 // example, so we can ensure that we handle it (in SkEdge.cpp), and don't
    199 // assert in the SK_DEBUG build.
    200 static void test_tricky_cubic(skiatest::Reporter* reporter) {
    201     const SkPoint pts[] = {
    202         { SkDoubleToScalar(18.8943768),    SkDoubleToScalar(129.121277) },
    203         { SkDoubleToScalar(18.8937435),    SkDoubleToScalar(129.121689) },
    204         { SkDoubleToScalar(18.8950119),    SkDoubleToScalar(129.120422) },
    205         { SkDoubleToScalar(18.5030727),    SkDoubleToScalar(129.13121)  },
    206     };
    207 
    208     SkPath path;
    209     path.moveTo(pts[0]);
    210     path.cubicTo(pts[1], pts[2], pts[3]);
    211 
    212     SkPaint paint;
    213     paint.setAntiAlias(true);
    214 
    215     SkSurface* surface = new_surface(19, 130);
    216     surface->getCanvas()->drawPath(path, paint);
    217     surface->unref();
    218 }
    219 
    220 // Inspired by http://code.google.com/p/chromium/issues/detail?id=141651
    221 //
    222 static void test_isfinite_after_transform(skiatest::Reporter* reporter) {
    223     SkPath path;
    224     path.quadTo(157, 366, 286, 208);
    225     path.arcTo(37, 442, 315, 163, 957494590897113.0f);
    226 
    227     SkMatrix matrix;
    228     matrix.setScale(1000*1000, 1000*1000);
    229 
    230     // Be sure that path::transform correctly updates isFinite and the bounds
    231     // if the transformation overflows. The previous bug was that isFinite was
    232     // set to true in this case, but the bounds were not set to empty (which
    233     // they should be).
    234     while (path.isFinite()) {
    235         REPORTER_ASSERT(reporter, path.getBounds().isFinite());
    236         REPORTER_ASSERT(reporter, !path.getBounds().isEmpty());
    237         path.transform(matrix);
    238     }
    239     REPORTER_ASSERT(reporter, path.getBounds().isEmpty());
    240 
    241     matrix.setTranslate(SK_Scalar1, SK_Scalar1);
    242     path.transform(matrix);
    243     // we need to still be non-finite
    244     REPORTER_ASSERT(reporter, !path.isFinite());
    245     REPORTER_ASSERT(reporter, path.getBounds().isEmpty());
    246 }
    247 
    248 static void add_corner_arc(SkPath* path, const SkRect& rect,
    249                            SkScalar xIn, SkScalar yIn,
    250                            int startAngle)
    251 {
    252 
    253     SkScalar rx = SkMinScalar(rect.width(), xIn);
    254     SkScalar ry = SkMinScalar(rect.height(), yIn);
    255 
    256     SkRect arcRect;
    257     arcRect.set(-rx, -ry, rx, ry);
    258     switch (startAngle) {
    259     case 0:
    260         arcRect.offset(rect.fRight - arcRect.fRight, rect.fBottom - arcRect.fBottom);
    261         break;
    262     case 90:
    263         arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fBottom - arcRect.fBottom);
    264         break;
    265     case 180:
    266         arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fTop - arcRect.fTop);
    267         break;
    268     case 270:
    269         arcRect.offset(rect.fRight - arcRect.fRight, rect.fTop - arcRect.fTop);
    270         break;
    271     default:
    272         break;
    273     }
    274 
    275     path->arcTo(arcRect, SkIntToScalar(startAngle), SkIntToScalar(90), false);
    276 }
    277 
    278 static void make_arb_round_rect(SkPath* path, const SkRect& r,
    279                                 SkScalar xCorner, SkScalar yCorner) {
    280     // we are lazy here and use the same x & y for each corner
    281     add_corner_arc(path, r, xCorner, yCorner, 270);
    282     add_corner_arc(path, r, xCorner, yCorner, 0);
    283     add_corner_arc(path, r, xCorner, yCorner, 90);
    284     add_corner_arc(path, r, xCorner, yCorner, 180);
    285     path->close();
    286 }
    287 
    288 // Chrome creates its own round rects with each corner possibly being different.
    289 // Performance will suffer if they are not convex.
    290 // Note: PathBench::ArbRoundRectBench performs almost exactly
    291 // the same test (but with drawing)
    292 static void test_arb_round_rect_is_convex(skiatest::Reporter* reporter) {
    293     SkRandom rand;
    294     SkRect r;
    295 
    296     for (int i = 0; i < 5000; ++i) {
    297 
    298         SkScalar size = rand.nextUScalar1() * 30;
    299         if (size < SK_Scalar1) {
    300             continue;
    301         }
    302         r.fLeft = rand.nextUScalar1() * 300;
    303         r.fTop =  rand.nextUScalar1() * 300;
    304         r.fRight =  r.fLeft + 2 * size;
    305         r.fBottom = r.fTop + 2 * size;
    306 
    307         SkPath temp;
    308 
    309         make_arb_round_rect(&temp, r, r.width() / 10, r.height() / 15);
    310 
    311 #ifndef SK_IGNORE_CONVEX_QUAD_OPT
    312         REPORTER_ASSERT(reporter, temp.isConvex());
    313 #endif
    314     }
    315 }
    316 
    317 // Chrome will sometimes create a 0 radius round rect. The degenerate
    318 // quads prevent the path from being converted to a rect
    319 // Note: PathBench::ArbRoundRectBench performs almost exactly
    320 // the same test (but with drawing)
    321 static void test_arb_zero_rad_round_rect_is_rect(skiatest::Reporter* reporter) {
    322     SkRandom rand;
    323     SkRect r;
    324 
    325     for (int i = 0; i < 5000; ++i) {
    326 
    327         SkScalar size = rand.nextUScalar1() * 30;
    328         if (size < SK_Scalar1) {
    329             continue;
    330         }
    331         r.fLeft = rand.nextUScalar1() * 300;
    332         r.fTop =  rand.nextUScalar1() * 300;
    333         r.fRight =  r.fLeft + 2 * size;
    334         r.fBottom = r.fTop + 2 * size;
    335 
    336         SkPath temp;
    337 
    338         make_arb_round_rect(&temp, r, 0, 0);
    339 
    340 #ifndef SK_IGNORE_CONVEX_QUAD_OPT
    341         SkRect result;
    342         REPORTER_ASSERT(reporter, temp.isRect(&result));
    343         REPORTER_ASSERT(reporter, r == result);
    344 #endif
    345     }
    346 }
    347 
    348 static void test_rect_isfinite(skiatest::Reporter* reporter) {
    349     const SkScalar inf = SK_ScalarInfinity;
    350     const SkScalar nan = SK_ScalarNaN;
    351 
    352     SkRect r;
    353     r.setEmpty();
    354     REPORTER_ASSERT(reporter, r.isFinite());
    355     r.set(0, 0, inf, -inf);
    356     REPORTER_ASSERT(reporter, !r.isFinite());
    357     r.set(0, 0, nan, 0);
    358     REPORTER_ASSERT(reporter, !r.isFinite());
    359 
    360     SkPoint pts[] = {
    361         { 0, 0 },
    362         { SK_Scalar1, 0 },
    363         { 0, SK_Scalar1 },
    364     };
    365 
    366     bool isFine = r.setBoundsCheck(pts, 3);
    367     REPORTER_ASSERT(reporter, isFine);
    368     REPORTER_ASSERT(reporter, !r.isEmpty());
    369 
    370     pts[1].set(inf, 0);
    371     isFine = r.setBoundsCheck(pts, 3);
    372     REPORTER_ASSERT(reporter, !isFine);
    373     REPORTER_ASSERT(reporter, r.isEmpty());
    374 
    375     pts[1].set(nan, 0);
    376     isFine = r.setBoundsCheck(pts, 3);
    377     REPORTER_ASSERT(reporter, !isFine);
    378     REPORTER_ASSERT(reporter, r.isEmpty());
    379 }
    380 
    381 static void test_path_isfinite(skiatest::Reporter* reporter) {
    382     const SkScalar inf = SK_ScalarInfinity;
    383     const SkScalar negInf = SK_ScalarNegativeInfinity;
    384     const SkScalar nan = SK_ScalarNaN;
    385 
    386     SkPath path;
    387     REPORTER_ASSERT(reporter, path.isFinite());
    388 
    389     path.reset();
    390     REPORTER_ASSERT(reporter, path.isFinite());
    391 
    392     path.reset();
    393     path.moveTo(SK_Scalar1, 0);
    394     REPORTER_ASSERT(reporter, path.isFinite());
    395 
    396     path.reset();
    397     path.moveTo(inf, negInf);
    398     REPORTER_ASSERT(reporter, !path.isFinite());
    399 
    400     path.reset();
    401     path.moveTo(nan, 0);
    402     REPORTER_ASSERT(reporter, !path.isFinite());
    403 }
    404 
    405 static void test_isfinite(skiatest::Reporter* reporter) {
    406     test_rect_isfinite(reporter);
    407     test_path_isfinite(reporter);
    408 }
    409 
    410 // assert that we always
    411 //  start with a moveTo
    412 //  only have 1 moveTo
    413 //  only have Lines after that
    414 //  end with a single close
    415 //  only have (at most) 1 close
    416 //
    417 static void test_poly(skiatest::Reporter* reporter, const SkPath& path,
    418                       const SkPoint srcPts[], int count, bool expectClose) {
    419     SkPath::RawIter iter(path);
    420     SkPoint         pts[4];
    421 
    422     bool firstTime = true;
    423     bool foundClose = false;
    424     for (;;) {
    425         switch (iter.next(pts)) {
    426             case SkPath::kMove_Verb:
    427                 REPORTER_ASSERT(reporter, firstTime);
    428                 REPORTER_ASSERT(reporter, pts[0] == srcPts[0]);
    429                 srcPts++;
    430                 firstTime = false;
    431                 break;
    432             case SkPath::kLine_Verb:
    433                 REPORTER_ASSERT(reporter, !firstTime);
    434                 REPORTER_ASSERT(reporter, pts[1] == srcPts[0]);
    435                 srcPts++;
    436                 break;
    437             case SkPath::kQuad_Verb:
    438                 REPORTER_ASSERT(reporter, !"unexpected quad verb");
    439                 break;
    440             case SkPath::kCubic_Verb:
    441                 REPORTER_ASSERT(reporter, !"unexpected cubic verb");
    442                 break;
    443             case SkPath::kClose_Verb:
    444                 REPORTER_ASSERT(reporter, !firstTime);
    445                 REPORTER_ASSERT(reporter, !foundClose);
    446                 REPORTER_ASSERT(reporter, expectClose);
    447                 foundClose = true;
    448                 break;
    449             case SkPath::kDone_Verb:
    450                 goto DONE;
    451         }
    452     }
    453 DONE:
    454     REPORTER_ASSERT(reporter, foundClose == expectClose);
    455 }
    456 
    457 static void test_addPoly(skiatest::Reporter* reporter) {
    458     SkPoint pts[32];
    459     SkRandom rand;
    460 
    461     for (size_t i = 0; i < SK_ARRAY_COUNT(pts); ++i) {
    462         pts[i].fX = rand.nextSScalar1();
    463         pts[i].fY = rand.nextSScalar1();
    464     }
    465 
    466     for (int doClose = 0; doClose <= 1; ++doClose) {
    467         for (size_t count = 1; count <= SK_ARRAY_COUNT(pts); ++count) {
    468             SkPath path;
    469             path.addPoly(pts, count, SkToBool(doClose));
    470             test_poly(reporter, path, pts, count, SkToBool(doClose));
    471         }
    472     }
    473 }
    474 
    475 static void test_strokerec(skiatest::Reporter* reporter) {
    476     SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
    477     REPORTER_ASSERT(reporter, rec.isFillStyle());
    478 
    479     rec.setHairlineStyle();
    480     REPORTER_ASSERT(reporter, rec.isHairlineStyle());
    481 
    482     rec.setStrokeStyle(SK_Scalar1, false);
    483     REPORTER_ASSERT(reporter, SkStrokeRec::kStroke_Style == rec.getStyle());
    484 
    485     rec.setStrokeStyle(SK_Scalar1, true);
    486     REPORTER_ASSERT(reporter, SkStrokeRec::kStrokeAndFill_Style == rec.getStyle());
    487 
    488     rec.setStrokeStyle(0, false);
    489     REPORTER_ASSERT(reporter, SkStrokeRec::kHairline_Style == rec.getStyle());
    490 
    491     rec.setStrokeStyle(0, true);
    492     REPORTER_ASSERT(reporter, SkStrokeRec::kFill_Style == rec.getStyle());
    493 }
    494 
    495 // Set this for paths that don't have a consistent direction such as a bowtie.
    496 // (cheapComputeDirection is not expected to catch these.)
    497 static const SkPath::Direction kDontCheckDir = static_cast<SkPath::Direction>(-1);
    498 
    499 static void check_direction(skiatest::Reporter* reporter, const SkPath& path,
    500                             SkPath::Direction expected) {
    501     if (expected == kDontCheckDir) {
    502         return;
    503     }
    504     SkPath copy(path); // we make a copy so that we don't cache the result on the passed in path.
    505 
    506     SkPath::Direction dir;
    507     if (copy.cheapComputeDirection(&dir)) {
    508         REPORTER_ASSERT(reporter, dir == expected);
    509     } else {
    510         REPORTER_ASSERT(reporter, SkPath::kUnknown_Direction == expected);
    511     }
    512 }
    513 
    514 static void test_direction(skiatest::Reporter* reporter) {
    515     size_t i;
    516     SkPath path;
    517     REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
    518     REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCW_Direction));
    519     REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCCW_Direction));
    520     REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kUnknown_Direction));
    521 
    522     static const char* gDegen[] = {
    523         "M 10 10",
    524         "M 10 10 M 20 20",
    525         "M 10 10 L 20 20",
    526         "M 10 10 L 10 10 L 10 10",
    527         "M 10 10 Q 10 10 10 10",
    528         "M 10 10 C 10 10 10 10 10 10",
    529     };
    530     for (i = 0; i < SK_ARRAY_COUNT(gDegen); ++i) {
    531         path.reset();
    532         bool valid = SkParsePath::FromSVGString(gDegen[i], &path);
    533         REPORTER_ASSERT(reporter, valid);
    534         REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
    535     }
    536 
    537     static const char* gCW[] = {
    538         "M 10 10 L 10 10 Q 20 10 20 20",
    539         "M 10 10 C 20 10 20 20 20 20",
    540         "M 20 10 Q 20 20 30 20 L 10 20", // test double-back at y-max
    541         // rect with top two corners replaced by cubics with identical middle
    542         // control points
    543         "M 10 10 C 10 0 10 0 20 0 L 40 0 C 50 0 50 0 50 10",
    544         "M 20 10 L 0 10 Q 10 10 20 0",  // left, degenerate serif
    545     };
    546     for (i = 0; i < SK_ARRAY_COUNT(gCW); ++i) {
    547         path.reset();
    548         bool valid = SkParsePath::FromSVGString(gCW[i], &path);
    549         REPORTER_ASSERT(reporter, valid);
    550         check_direction(reporter, path, SkPath::kCW_Direction);
    551     }
    552 
    553     static const char* gCCW[] = {
    554         "M 10 10 L 10 10 Q 20 10 20 -20",
    555         "M 10 10 C 20 10 20 -20 20 -20",
    556         "M 20 10 Q 20 20 10 20 L 30 20", // test double-back at y-max
    557         // rect with top two corners replaced by cubics with identical middle
    558         // control points
    559         "M 50 10 C 50 0 50 0 40 0 L 20 0 C 10 0 10 0 10 10",
    560         "M 10 10 L 30 10 Q 20 10 10 0",  // right, degenerate serif
    561     };
    562     for (i = 0; i < SK_ARRAY_COUNT(gCCW); ++i) {
    563         path.reset();
    564         bool valid = SkParsePath::FromSVGString(gCCW[i], &path);
    565         REPORTER_ASSERT(reporter, valid);
    566         check_direction(reporter, path, SkPath::kCCW_Direction);
    567     }
    568 
    569     // Test two donuts, each wound a different direction. Only the outer contour
    570     // determines the cheap direction
    571     path.reset();
    572     path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCW_Direction);
    573     path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCCW_Direction);
    574     check_direction(reporter, path, SkPath::kCW_Direction);
    575 
    576     path.reset();
    577     path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCW_Direction);
    578     path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCCW_Direction);
    579     check_direction(reporter, path, SkPath::kCCW_Direction);
    580 
    581 #ifdef SK_SCALAR_IS_FLOAT
    582     // triangle with one point really far from the origin.
    583     path.reset();
    584     // the first point is roughly 1.05e10, 1.05e10
    585     path.moveTo(SkFloatToScalar(SkBits2Float(0x501c7652)), SkFloatToScalar(SkBits2Float(0x501c7652)));
    586     path.lineTo(110 * SK_Scalar1, -10 * SK_Scalar1);
    587     path.lineTo(-10 * SK_Scalar1, 60 * SK_Scalar1);
    588     check_direction(reporter, path, SkPath::kCCW_Direction);
    589 #endif
    590 }
    591 
    592 static void add_rect(SkPath* path, const SkRect& r) {
    593     path->moveTo(r.fLeft, r.fTop);
    594     path->lineTo(r.fRight, r.fTop);
    595     path->lineTo(r.fRight, r.fBottom);
    596     path->lineTo(r.fLeft, r.fBottom);
    597     path->close();
    598 }
    599 
    600 static void test_bounds(skiatest::Reporter* reporter) {
    601     static const SkRect rects[] = {
    602         { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(160) },
    603         { SkIntToScalar(610), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(199) },
    604         { SkIntToScalar(10), SkIntToScalar(198), SkIntToScalar(610), SkIntToScalar(199) },
    605         { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(10), SkIntToScalar(199) },
    606     };
    607 
    608     SkPath path0, path1;
    609     for (size_t i = 0; i < SK_ARRAY_COUNT(rects); ++i) {
    610         path0.addRect(rects[i]);
    611         add_rect(&path1, rects[i]);
    612     }
    613 
    614     REPORTER_ASSERT(reporter, path0.getBounds() == path1.getBounds());
    615 }
    616 
    617 static void stroke_cubic(const SkPoint pts[4]) {
    618     SkPath path;
    619     path.moveTo(pts[0]);
    620     path.cubicTo(pts[1], pts[2], pts[3]);
    621 
    622     SkPaint paint;
    623     paint.setStyle(SkPaint::kStroke_Style);
    624     paint.setStrokeWidth(SK_Scalar1 * 2);
    625 
    626     SkPath fill;
    627     paint.getFillPath(path, &fill);
    628 }
    629 
    630 // just ensure this can run w/o any SkASSERTS firing in the debug build
    631 // we used to assert due to differences in how we determine a degenerate vector
    632 // but that was fixed with the introduction of SkPoint::CanNormalize
    633 static void stroke_tiny_cubic() {
    634     SkPoint p0[] = {
    635         { 372.0f,   92.0f },
    636         { 372.0f,   92.0f },
    637         { 372.0f,   92.0f },
    638         { 372.0f,   92.0f },
    639     };
    640 
    641     stroke_cubic(p0);
    642 
    643     SkPoint p1[] = {
    644         { 372.0f,       92.0f },
    645         { 372.0007f,    92.000755f },
    646         { 371.99927f,   92.003922f },
    647         { 371.99826f,   92.003899f },
    648     };
    649 
    650     stroke_cubic(p1);
    651 }
    652 
    653 static void check_close(skiatest::Reporter* reporter, const SkPath& path) {
    654     for (int i = 0; i < 2; ++i) {
    655         SkPath::Iter iter(path, SkToBool(i));
    656         SkPoint mv;
    657         SkPoint pts[4];
    658         SkPath::Verb v;
    659         int nMT = 0;
    660         int nCL = 0;
    661         mv.set(0, 0);
    662         while (SkPath::kDone_Verb != (v = iter.next(pts))) {
    663             switch (v) {
    664                 case SkPath::kMove_Verb:
    665                     mv = pts[0];
    666                     ++nMT;
    667                     break;
    668                 case SkPath::kClose_Verb:
    669                     REPORTER_ASSERT(reporter, mv == pts[0]);
    670                     ++nCL;
    671                     break;
    672                 default:
    673                     break;
    674             }
    675         }
    676         // if we force a close on the interator we should have a close
    677         // for every moveTo
    678         REPORTER_ASSERT(reporter, !i || nMT == nCL);
    679     }
    680 }
    681 
    682 static void test_close(skiatest::Reporter* reporter) {
    683     SkPath closePt;
    684     closePt.moveTo(0, 0);
    685     closePt.close();
    686     check_close(reporter, closePt);
    687 
    688     SkPath openPt;
    689     openPt.moveTo(0, 0);
    690     check_close(reporter, openPt);
    691 
    692     SkPath empty;
    693     check_close(reporter, empty);
    694     empty.close();
    695     check_close(reporter, empty);
    696 
    697     SkPath rect;
    698     rect.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
    699     check_close(reporter, rect);
    700     rect.close();
    701     check_close(reporter, rect);
    702 
    703     SkPath quad;
    704     quad.quadTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
    705     check_close(reporter, quad);
    706     quad.close();
    707     check_close(reporter, quad);
    708 
    709     SkPath cubic;
    710     quad.cubicTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1,
    711                  10*SK_Scalar1, 20 * SK_Scalar1, 20*SK_Scalar1);
    712     check_close(reporter, cubic);
    713     cubic.close();
    714     check_close(reporter, cubic);
    715 
    716     SkPath line;
    717     line.moveTo(SK_Scalar1, SK_Scalar1);
    718     line.lineTo(10 * SK_Scalar1, 10*SK_Scalar1);
    719     check_close(reporter, line);
    720     line.close();
    721     check_close(reporter, line);
    722 
    723     SkPath rect2;
    724     rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
    725     rect2.close();
    726     rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
    727     check_close(reporter, rect2);
    728     rect2.close();
    729     check_close(reporter, rect2);
    730 
    731     SkPath oval3;
    732     oval3.addOval(SkRect::MakeWH(SK_Scalar1*100,SK_Scalar1*100));
    733     oval3.close();
    734     oval3.addOval(SkRect::MakeWH(SK_Scalar1*200,SK_Scalar1*200));
    735     check_close(reporter, oval3);
    736     oval3.close();
    737     check_close(reporter, oval3);
    738 
    739     SkPath moves;
    740     moves.moveTo(SK_Scalar1, SK_Scalar1);
    741     moves.moveTo(5 * SK_Scalar1, SK_Scalar1);
    742     moves.moveTo(SK_Scalar1, 10 * SK_Scalar1);
    743     moves.moveTo(10 *SK_Scalar1, SK_Scalar1);
    744     check_close(reporter, moves);
    745 
    746     stroke_tiny_cubic();
    747 }
    748 
    749 static void check_convexity(skiatest::Reporter* reporter, const SkPath& path,
    750                             SkPath::Convexity expected) {
    751     SkPath copy(path); // we make a copy so that we don't cache the result on the passed in path.
    752     SkPath::Convexity c = copy.getConvexity();
    753     REPORTER_ASSERT(reporter, c == expected);
    754 }
    755 
    756 static void test_convexity2(skiatest::Reporter* reporter) {
    757     SkPath pt;
    758     pt.moveTo(0, 0);
    759     pt.close();
    760     check_convexity(reporter, pt, SkPath::kConvex_Convexity);
    761     check_direction(reporter, pt, SkPath::kUnknown_Direction);
    762 
    763     SkPath line;
    764     line.moveTo(12*SK_Scalar1, 20*SK_Scalar1);
    765     line.lineTo(-12*SK_Scalar1, -20*SK_Scalar1);
    766     line.close();
    767     check_convexity(reporter, line, SkPath::kConvex_Convexity);
    768     check_direction(reporter, line, SkPath::kUnknown_Direction);
    769 
    770     SkPath triLeft;
    771     triLeft.moveTo(0, 0);
    772     triLeft.lineTo(SK_Scalar1, 0);
    773     triLeft.lineTo(SK_Scalar1, SK_Scalar1);
    774     triLeft.close();
    775     check_convexity(reporter, triLeft, SkPath::kConvex_Convexity);
    776     check_direction(reporter, triLeft, SkPath::kCW_Direction);
    777 
    778     SkPath triRight;
    779     triRight.moveTo(0, 0);
    780     triRight.lineTo(-SK_Scalar1, 0);
    781     triRight.lineTo(SK_Scalar1, SK_Scalar1);
    782     triRight.close();
    783     check_convexity(reporter, triRight, SkPath::kConvex_Convexity);
    784     check_direction(reporter, triRight, SkPath::kCCW_Direction);
    785 
    786     SkPath square;
    787     square.moveTo(0, 0);
    788     square.lineTo(SK_Scalar1, 0);
    789     square.lineTo(SK_Scalar1, SK_Scalar1);
    790     square.lineTo(0, SK_Scalar1);
    791     square.close();
    792     check_convexity(reporter, square, SkPath::kConvex_Convexity);
    793     check_direction(reporter, square, SkPath::kCW_Direction);
    794 
    795     SkPath redundantSquare;
    796     redundantSquare.moveTo(0, 0);
    797     redundantSquare.lineTo(0, 0);
    798     redundantSquare.lineTo(0, 0);
    799     redundantSquare.lineTo(SK_Scalar1, 0);
    800     redundantSquare.lineTo(SK_Scalar1, 0);
    801     redundantSquare.lineTo(SK_Scalar1, 0);
    802     redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
    803     redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
    804     redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
    805     redundantSquare.lineTo(0, SK_Scalar1);
    806     redundantSquare.lineTo(0, SK_Scalar1);
    807     redundantSquare.lineTo(0, SK_Scalar1);
    808     redundantSquare.close();
    809     check_convexity(reporter, redundantSquare, SkPath::kConvex_Convexity);
    810     check_direction(reporter, redundantSquare, SkPath::kCW_Direction);
    811 
    812     SkPath bowTie;
    813     bowTie.moveTo(0, 0);
    814     bowTie.lineTo(0, 0);
    815     bowTie.lineTo(0, 0);
    816     bowTie.lineTo(SK_Scalar1, SK_Scalar1);
    817     bowTie.lineTo(SK_Scalar1, SK_Scalar1);
    818     bowTie.lineTo(SK_Scalar1, SK_Scalar1);
    819     bowTie.lineTo(SK_Scalar1, 0);
    820     bowTie.lineTo(SK_Scalar1, 0);
    821     bowTie.lineTo(SK_Scalar1, 0);
    822     bowTie.lineTo(0, SK_Scalar1);
    823     bowTie.lineTo(0, SK_Scalar1);
    824     bowTie.lineTo(0, SK_Scalar1);
    825     bowTie.close();
    826     check_convexity(reporter, bowTie, SkPath::kConcave_Convexity);
    827     check_direction(reporter, bowTie, kDontCheckDir);
    828 
    829     SkPath spiral;
    830     spiral.moveTo(0, 0);
    831     spiral.lineTo(100*SK_Scalar1, 0);
    832     spiral.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
    833     spiral.lineTo(0, 100*SK_Scalar1);
    834     spiral.lineTo(0, 50*SK_Scalar1);
    835     spiral.lineTo(50*SK_Scalar1, 50*SK_Scalar1);
    836     spiral.lineTo(50*SK_Scalar1, 75*SK_Scalar1);
    837     spiral.close();
    838     check_convexity(reporter, spiral, SkPath::kConcave_Convexity);
    839     check_direction(reporter, spiral, kDontCheckDir);
    840 
    841     SkPath dent;
    842     dent.moveTo(0, 0);
    843     dent.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
    844     dent.lineTo(0, 100*SK_Scalar1);
    845     dent.lineTo(-50*SK_Scalar1, 200*SK_Scalar1);
    846     dent.lineTo(-200*SK_Scalar1, 100*SK_Scalar1);
    847     dent.close();
    848     check_convexity(reporter, dent, SkPath::kConcave_Convexity);
    849     check_direction(reporter, dent, SkPath::kCW_Direction);
    850 }
    851 
    852 static void check_convex_bounds(skiatest::Reporter* reporter, const SkPath& p,
    853                                 const SkRect& bounds) {
    854     REPORTER_ASSERT(reporter, p.isConvex());
    855     REPORTER_ASSERT(reporter, p.getBounds() == bounds);
    856 
    857     SkPath p2(p);
    858     REPORTER_ASSERT(reporter, p2.isConvex());
    859     REPORTER_ASSERT(reporter, p2.getBounds() == bounds);
    860 
    861     SkPath other;
    862     other.swap(p2);
    863     REPORTER_ASSERT(reporter, other.isConvex());
    864     REPORTER_ASSERT(reporter, other.getBounds() == bounds);
    865 }
    866 
    867 static void setFromString(SkPath* path, const char str[]) {
    868     bool first = true;
    869     while (str) {
    870         SkScalar x, y;
    871         str = SkParse::FindScalar(str, &x);
    872         if (NULL == str) {
    873             break;
    874         }
    875         str = SkParse::FindScalar(str, &y);
    876         SkASSERT(str);
    877         if (first) {
    878             path->moveTo(x, y);
    879             first = false;
    880         } else {
    881             path->lineTo(x, y);
    882         }
    883     }
    884 }
    885 
    886 static void test_convexity(skiatest::Reporter* reporter) {
    887     SkPath path;
    888 
    889     check_convexity(reporter, path, SkPath::kConvex_Convexity);
    890     path.addCircle(0, 0, SkIntToScalar(10));
    891     check_convexity(reporter, path, SkPath::kConvex_Convexity);
    892     path.addCircle(0, 0, SkIntToScalar(10));   // 2nd circle
    893     check_convexity(reporter, path, SkPath::kConcave_Convexity);
    894 
    895     path.reset();
    896     path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCCW_Direction);
    897     check_convexity(reporter, path, SkPath::kConvex_Convexity);
    898     REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCCW_Direction));
    899 
    900     path.reset();
    901     path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCW_Direction);
    902     check_convexity(reporter, path, SkPath::kConvex_Convexity);
    903     REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCW_Direction));
    904 
    905     static const struct {
    906         const char*         fPathStr;
    907         SkPath::Convexity   fExpectedConvexity;
    908         SkPath::Direction   fExpectedDirection;
    909     } gRec[] = {
    910         { "", SkPath::kConvex_Convexity, SkPath::kUnknown_Direction },
    911         { "0 0", SkPath::kConvex_Convexity, SkPath::kUnknown_Direction },
    912         { "0 0 10 10", SkPath::kConvex_Convexity, SkPath::kUnknown_Direction },
    913         { "0 0 10 10 20 20 0 0 10 10", SkPath::kConcave_Convexity, SkPath::kUnknown_Direction },
    914         { "0 0 10 10 10 20", SkPath::kConvex_Convexity, SkPath::kCW_Direction },
    915         { "0 0 10 10 10 0", SkPath::kConvex_Convexity, SkPath::kCCW_Direction },
    916         { "0 0 10 10 10 0 0 10", SkPath::kConcave_Convexity, kDontCheckDir },
    917         { "0 0 10 0 0 10 -10 -10", SkPath::kConcave_Convexity, SkPath::kCW_Direction },
    918     };
    919 
    920     for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
    921         SkPath path;
    922         setFromString(&path, gRec[i].fPathStr);
    923         check_convexity(reporter, path, gRec[i].fExpectedConvexity);
    924         check_direction(reporter, path, gRec[i].fExpectedDirection);
    925     }
    926 }
    927 
    928 static void test_isLine(skiatest::Reporter* reporter) {
    929     SkPath path;
    930     SkPoint pts[2];
    931     const SkScalar value = SkIntToScalar(5);
    932 
    933     REPORTER_ASSERT(reporter, !path.isLine(NULL));
    934 
    935     // set some non-zero values
    936     pts[0].set(value, value);
    937     pts[1].set(value, value);
    938     REPORTER_ASSERT(reporter, !path.isLine(pts));
    939     // check that pts was untouched
    940     REPORTER_ASSERT(reporter, pts[0].equals(value, value));
    941     REPORTER_ASSERT(reporter, pts[1].equals(value, value));
    942 
    943     const SkScalar moveX = SkIntToScalar(1);
    944     const SkScalar moveY = SkIntToScalar(2);
    945     SkASSERT(value != moveX && value != moveY);
    946 
    947     path.moveTo(moveX, moveY);
    948     REPORTER_ASSERT(reporter, !path.isLine(NULL));
    949     REPORTER_ASSERT(reporter, !path.isLine(pts));
    950     // check that pts was untouched
    951     REPORTER_ASSERT(reporter, pts[0].equals(value, value));
    952     REPORTER_ASSERT(reporter, pts[1].equals(value, value));
    953 
    954     const SkScalar lineX = SkIntToScalar(2);
    955     const SkScalar lineY = SkIntToScalar(2);
    956     SkASSERT(value != lineX && value != lineY);
    957 
    958     path.lineTo(lineX, lineY);
    959     REPORTER_ASSERT(reporter, path.isLine(NULL));
    960 
    961     REPORTER_ASSERT(reporter, !pts[0].equals(moveX, moveY));
    962     REPORTER_ASSERT(reporter, !pts[1].equals(lineX, lineY));
    963     REPORTER_ASSERT(reporter, path.isLine(pts));
    964     REPORTER_ASSERT(reporter, pts[0].equals(moveX, moveY));
    965     REPORTER_ASSERT(reporter, pts[1].equals(lineX, lineY));
    966 
    967     path.lineTo(0, 0);  // too many points/verbs
    968     REPORTER_ASSERT(reporter, !path.isLine(NULL));
    969     REPORTER_ASSERT(reporter, !path.isLine(pts));
    970     REPORTER_ASSERT(reporter, pts[0].equals(moveX, moveY));
    971     REPORTER_ASSERT(reporter, pts[1].equals(lineX, lineY));
    972 }
    973 
    974 static void test_conservativelyContains(skiatest::Reporter* reporter) {
    975     SkPath path;
    976 
    977     // kBaseRect is used to construct most our test paths: a rect, a circle, and a round-rect.
    978     static const SkRect kBaseRect = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
    979 
    980     // A circle that bounds kBaseRect (with a significant amount of slop)
    981     SkScalar circleR = SkMaxScalar(kBaseRect.width(), kBaseRect.height());
    982     circleR = SkScalarMul(circleR, SkFloatToScalar(1.75f)) / 2;
    983     static const SkPoint kCircleC = {kBaseRect.centerX(), kBaseRect.centerY()};
    984 
    985     // round-rect radii
    986     static const SkScalar kRRRadii[] = {SkIntToScalar(5), SkIntToScalar(3)};
    987 
    988     static const struct SUPPRESS_VISIBILITY_WARNING {
    989         SkRect fQueryRect;
    990         bool   fInRect;
    991         bool   fInCircle;
    992         bool   fInRR;
    993     } kQueries[] = {
    994         {kBaseRect, true, true, false},
    995 
    996         // rect well inside of kBaseRect
    997         {SkRect::MakeLTRB(kBaseRect.fLeft + SkFloatToScalar(0.25f)*kBaseRect.width(),
    998                           kBaseRect.fTop + SkFloatToScalar(0.25f)*kBaseRect.height(),
    999                           kBaseRect.fRight - SkFloatToScalar(0.25f)*kBaseRect.width(),
   1000                           kBaseRect.fBottom - SkFloatToScalar(0.25f)*kBaseRect.height()),
   1001                           true, true, true},
   1002 
   1003         // rects with edges off by one from kBaseRect's edges
   1004         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop,
   1005                           kBaseRect.width(), kBaseRect.height() + 1),
   1006          false, true, false},
   1007         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop,
   1008                           kBaseRect.width() + 1, kBaseRect.height()),
   1009          false, true, false},
   1010         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop,
   1011                           kBaseRect.width() + 1, kBaseRect.height() + 1),
   1012          false, true, false},
   1013         {SkRect::MakeXYWH(kBaseRect.fLeft - 1, kBaseRect.fTop,
   1014                           kBaseRect.width(), kBaseRect.height()),
   1015          false, true, false},
   1016         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop - 1,
   1017                           kBaseRect.width(), kBaseRect.height()),
   1018          false, true, false},
   1019         {SkRect::MakeXYWH(kBaseRect.fLeft - 1, kBaseRect.fTop,
   1020                           kBaseRect.width() + 2, kBaseRect.height()),
   1021          false, true, false},
   1022         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop - 1,
   1023                           kBaseRect.width() + 2, kBaseRect.height()),
   1024          false, true, false},
   1025 
   1026         // zero-w/h rects at each corner of kBaseRect
   1027         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop, 0, 0), true, true, false},
   1028         {SkRect::MakeXYWH(kBaseRect.fRight, kBaseRect.fTop, 0, 0), true, true, false},
   1029         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fBottom, 0, 0), true, true, false},
   1030         {SkRect::MakeXYWH(kBaseRect.fRight, kBaseRect.fBottom, 0, 0), true, true, false},
   1031 
   1032         // far away rect
   1033         {SkRect::MakeXYWH(10 * kBaseRect.fRight, 10 * kBaseRect.fBottom,
   1034                           SkIntToScalar(10), SkIntToScalar(10)),
   1035          false, false, false},
   1036 
   1037         // very large rect containing kBaseRect
   1038         {SkRect::MakeXYWH(kBaseRect.fLeft - 5 * kBaseRect.width(),
   1039                           kBaseRect.fTop - 5 * kBaseRect.height(),
   1040                           11 * kBaseRect.width(), 11 * kBaseRect.height()),
   1041          false, false, false},
   1042 
   1043         // skinny rect that spans same y-range as kBaseRect
   1044         {SkRect::MakeXYWH(kBaseRect.centerX(), kBaseRect.fTop,
   1045                           SkIntToScalar(1), kBaseRect.height()),
   1046          true, true, true},
   1047 
   1048         // short rect that spans same x-range as kBaseRect
   1049         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.centerY(), kBaseRect.width(), SkScalar(1)),
   1050          true, true, true},
   1051 
   1052         // skinny rect that spans slightly larger y-range than kBaseRect
   1053         {SkRect::MakeXYWH(kBaseRect.centerX(), kBaseRect.fTop,
   1054                           SkIntToScalar(1), kBaseRect.height() + 1),
   1055          false, true, false},
   1056 
   1057         // short rect that spans slightly larger x-range than kBaseRect
   1058         {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.centerY(),
   1059                           kBaseRect.width() + 1, SkScalar(1)),
   1060          false, true, false},
   1061     };
   1062 
   1063     for (int inv = 0; inv < 4; ++inv) {
   1064         for (size_t q = 0; q < SK_ARRAY_COUNT(kQueries); ++q) {
   1065             SkRect qRect = kQueries[q].fQueryRect;
   1066             if (inv & 0x1) {
   1067                 SkTSwap(qRect.fLeft, qRect.fRight);
   1068             }
   1069             if (inv & 0x2) {
   1070                 SkTSwap(qRect.fTop, qRect.fBottom);
   1071             }
   1072             for (int d = 0; d < 2; ++d) {
   1073                 SkPath::Direction dir = d ? SkPath::kCCW_Direction : SkPath::kCW_Direction;
   1074                 path.reset();
   1075                 path.addRect(kBaseRect, dir);
   1076                 REPORTER_ASSERT(reporter, kQueries[q].fInRect ==
   1077                                           path.conservativelyContainsRect(qRect));
   1078 
   1079                 path.reset();
   1080                 path.addCircle(kCircleC.fX, kCircleC.fY, circleR, dir);
   1081                 REPORTER_ASSERT(reporter, kQueries[q].fInCircle ==
   1082                                           path.conservativelyContainsRect(qRect));
   1083 
   1084                 path.reset();
   1085                 path.addRoundRect(kBaseRect, kRRRadii[0], kRRRadii[1], dir);
   1086                 REPORTER_ASSERT(reporter, kQueries[q].fInRR ==
   1087                                           path.conservativelyContainsRect(qRect));
   1088             }
   1089             // Slightly non-convex shape, shouldn't contain any rects.
   1090             path.reset();
   1091             path.moveTo(0, 0);
   1092             path.lineTo(SkIntToScalar(50), SkFloatToScalar(0.05f));
   1093             path.lineTo(SkIntToScalar(100), 0);
   1094             path.lineTo(SkIntToScalar(100), SkIntToScalar(100));
   1095             path.lineTo(0, SkIntToScalar(100));
   1096             path.close();
   1097             REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(qRect));
   1098         }
   1099     }
   1100 
   1101     // make sure a minimal convex shape works, a right tri with edges along pos x and y axes.
   1102     path.reset();
   1103     path.moveTo(0, 0);
   1104     path.lineTo(SkIntToScalar(100), 0);
   1105     path.lineTo(0, SkIntToScalar(100));
   1106 
   1107     // inside, on along top edge
   1108     REPORTER_ASSERT(reporter, path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(50), 0,
   1109                                                                                SkIntToScalar(10),
   1110                                                                                SkIntToScalar(10))));
   1111     // above
   1112     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(
   1113         SkRect::MakeXYWH(SkIntToScalar(50),
   1114                          SkIntToScalar(-10),
   1115                          SkIntToScalar(10),
   1116                          SkIntToScalar(10))));
   1117     // to the left
   1118     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(-10),
   1119                                                                                 SkIntToScalar(5),
   1120                                                                                 SkIntToScalar(5),
   1121                                                                                 SkIntToScalar(5))));
   1122 
   1123     // outside the diagonal edge
   1124     REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(10),
   1125                                                                                 SkIntToScalar(200),
   1126                                                                                 SkIntToScalar(20),
   1127                                                                                 SkIntToScalar(5))));
   1128 }
   1129 
   1130 // Simple isRect test is inline TestPath, below.
   1131 // test_isRect provides more extensive testing.
   1132 static void test_isRect(skiatest::Reporter* reporter) {
   1133     // passing tests (all moveTo / lineTo...
   1134     SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
   1135     SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
   1136     SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
   1137     SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
   1138     SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
   1139     SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
   1140     SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
   1141     SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
   1142     SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
   1143     SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f},
   1144         {1, 0}, {.5f, 0}};
   1145     SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1},
   1146         {0, 1}, {0, .5f}};
   1147     SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}};
   1148     SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
   1149     SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}};
   1150     SkPoint rf[] = {{1, 0}, {8, 0}, {8, 8}, {0, 8}, {0, 0}};
   1151 
   1152     // failing tests
   1153     SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
   1154     SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
   1155     SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
   1156     SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
   1157     SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
   1158     SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
   1159     SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
   1160     SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
   1161     SkPoint f9[] = {{1, 0}, {8, 0}, {8, 8}, {0, 8}, {0, 0}, {2, 0}}; // overlaps
   1162     SkPoint fa[] = {{1, 0}, {8, 0}, {8, 8}, {0, 8}, {0, -1}, {1, -1}}; // non colinear gap
   1163     SkPoint fb[] = {{1, 0}, {8, 0}, {8, 8}, {0, 8}, {0, 1}}; // falls short
   1164 
   1165     // failing, no close
   1166     SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match
   1167     SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto
   1168 
   1169     size_t testLen[] = {
   1170         sizeof(r1), sizeof(r2), sizeof(r3), sizeof(r4), sizeof(r5), sizeof(r6),
   1171         sizeof(r7), sizeof(r8), sizeof(r9), sizeof(ra), sizeof(rb), sizeof(rc),
   1172         sizeof(rd), sizeof(re), sizeof(rf),
   1173         sizeof(f1), sizeof(f2), sizeof(f3), sizeof(f4), sizeof(f5), sizeof(f6),
   1174         sizeof(f7), sizeof(f8), sizeof(f9), sizeof(fa), sizeof(fb),
   1175         sizeof(c1), sizeof(c2)
   1176     };
   1177     SkPoint* tests[] = {
   1178         r1, r2, r3, r4, r5, r6, r7, r8, r9, ra, rb, rc, rd, re, rf,
   1179         f1, f2, f3, f4, f5, f6, f7, f8, f9, fa, fb,
   1180         c1, c2
   1181     };
   1182     SkPoint* lastPass = rf;
   1183     SkPoint* lastClose = fb;
   1184     bool fail = false;
   1185     bool close = true;
   1186     const size_t testCount = sizeof(tests) / sizeof(tests[0]);
   1187     size_t index;
   1188     for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
   1189         SkPath path;
   1190         path.moveTo(tests[testIndex][0].fX, tests[testIndex][0].fY);
   1191         for (index = 1; index < testLen[testIndex] / sizeof(SkPoint); ++index) {
   1192             path.lineTo(tests[testIndex][index].fX, tests[testIndex][index].fY);
   1193         }
   1194         if (close) {
   1195             path.close();
   1196         }
   1197         REPORTER_ASSERT(reporter, fail ^ path.isRect(0));
   1198         REPORTER_ASSERT(reporter, fail ^ path.isRect(NULL, NULL));
   1199 
   1200         if (!fail) {
   1201             SkRect computed, expected;
   1202             expected.set(tests[testIndex], testLen[testIndex] / sizeof(SkPoint));
   1203             REPORTER_ASSERT(reporter, path.isRect(&computed));
   1204             REPORTER_ASSERT(reporter, expected == computed);
   1205 
   1206             bool isClosed;
   1207             SkPath::Direction direction, cheapDirection;
   1208             REPORTER_ASSERT(reporter, path.cheapComputeDirection(&cheapDirection));
   1209             REPORTER_ASSERT(reporter, path.isRect(&isClosed, &direction));
   1210             REPORTER_ASSERT(reporter, isClosed == close);
   1211             REPORTER_ASSERT(reporter, direction == cheapDirection);
   1212         } else {
   1213             SkRect computed;
   1214             computed.set(123, 456, 789, 1011);
   1215             REPORTER_ASSERT(reporter, !path.isRect(&computed));
   1216             REPORTER_ASSERT(reporter, computed.fLeft == 123 && computed.fTop == 456);
   1217             REPORTER_ASSERT(reporter, computed.fRight == 789 && computed.fBottom == 1011);
   1218 
   1219             bool isClosed = (bool) -1;
   1220             SkPath::Direction direction = (SkPath::Direction) -1;
   1221             REPORTER_ASSERT(reporter, !path.isRect(&isClosed, &direction));
   1222             REPORTER_ASSERT(reporter, isClosed == (bool) -1);
   1223             REPORTER_ASSERT(reporter, direction == (SkPath::Direction) -1);
   1224         }
   1225 
   1226         if (tests[testIndex] == lastPass) {
   1227             fail = true;
   1228         }
   1229         if (tests[testIndex] == lastClose) {
   1230             close = false;
   1231         }
   1232     }
   1233 
   1234     // fail, close then line
   1235     SkPath path1;
   1236     path1.moveTo(r1[0].fX, r1[0].fY);
   1237     for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
   1238         path1.lineTo(r1[index].fX, r1[index].fY);
   1239     }
   1240     path1.close();
   1241     path1.lineTo(1, 0);
   1242     REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
   1243 
   1244     // fail, move in the middle
   1245     path1.reset();
   1246     path1.moveTo(r1[0].fX, r1[0].fY);
   1247     for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
   1248         if (index == 2) {
   1249             path1.moveTo(1, .5f);
   1250         }
   1251         path1.lineTo(r1[index].fX, r1[index].fY);
   1252     }
   1253     path1.close();
   1254     REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
   1255 
   1256     // fail, move on the edge
   1257     path1.reset();
   1258     for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
   1259         path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
   1260         path1.lineTo(r1[index].fX, r1[index].fY);
   1261     }
   1262     path1.close();
   1263     REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
   1264 
   1265     // fail, quad
   1266     path1.reset();
   1267     path1.moveTo(r1[0].fX, r1[0].fY);
   1268     for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
   1269         if (index == 2) {
   1270             path1.quadTo(1, .5f, 1, .5f);
   1271         }
   1272         path1.lineTo(r1[index].fX, r1[index].fY);
   1273     }
   1274     path1.close();
   1275     REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
   1276 
   1277     // fail, cubic
   1278     path1.reset();
   1279     path1.moveTo(r1[0].fX, r1[0].fY);
   1280     for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
   1281         if (index == 2) {
   1282             path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
   1283         }
   1284         path1.lineTo(r1[index].fX, r1[index].fY);
   1285     }
   1286     path1.close();
   1287     REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
   1288 }
   1289 
   1290 static void test_isNestedRects(skiatest::Reporter* reporter) {
   1291     // passing tests (all moveTo / lineTo...
   1292     SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
   1293     SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
   1294     SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
   1295     SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
   1296     SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
   1297     SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
   1298     SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
   1299     SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
   1300     SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
   1301     SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f},
   1302         {1, 0}, {.5f, 0}};
   1303     SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1},
   1304         {0, 1}, {0, .5f}};
   1305     SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}};
   1306     SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
   1307     SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}};
   1308 
   1309     // failing tests
   1310     SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
   1311     SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
   1312     SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
   1313     SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
   1314     SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
   1315     SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
   1316     SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
   1317     SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
   1318 
   1319     // failing, no close
   1320     SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match
   1321     SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto
   1322 
   1323     size_t testLen[] = {
   1324         sizeof(r1), sizeof(r2), sizeof(r3), sizeof(r4), sizeof(r5), sizeof(r6),
   1325         sizeof(r7), sizeof(r8), sizeof(r9), sizeof(ra), sizeof(rb), sizeof(rc),
   1326         sizeof(rd), sizeof(re),
   1327         sizeof(f1), sizeof(f2), sizeof(f3), sizeof(f4), sizeof(f5), sizeof(f6),
   1328         sizeof(f7), sizeof(f8),
   1329         sizeof(c1), sizeof(c2)
   1330     };
   1331     SkPoint* tests[] = {
   1332         r1, r2, r3, r4, r5, r6, r7, r8, r9, ra, rb, rc, rd, re,
   1333         f1, f2, f3, f4, f5, f6, f7, f8,
   1334         c1, c2
   1335     };
   1336     const SkPoint* lastPass = re;
   1337     const SkPoint* lastClose = f8;
   1338     const size_t testCount = sizeof(tests) / sizeof(tests[0]);
   1339     size_t index;
   1340     for (int rectFirst = 0; rectFirst <= 1; ++rectFirst) {
   1341         bool fail = false;
   1342         bool close = true;
   1343         for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
   1344             SkPath path;
   1345             if (rectFirst) {
   1346                 path.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
   1347             }
   1348             path.moveTo(tests[testIndex][0].fX, tests[testIndex][0].fY);
   1349             for (index = 1; index < testLen[testIndex] / sizeof(SkPoint); ++index) {
   1350                 path.lineTo(tests[testIndex][index].fX, tests[testIndex][index].fY);
   1351             }
   1352             if (close) {
   1353                 path.close();
   1354             }
   1355             if (!rectFirst) {
   1356                 path.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
   1357             }
   1358             REPORTER_ASSERT(reporter, fail ^ path.isNestedRects(0));
   1359             if (!fail) {
   1360                 SkRect expected[2], computed[2];
   1361                 SkRect testBounds;
   1362                 testBounds.set(tests[testIndex], testLen[testIndex] / sizeof(SkPoint));
   1363                 expected[0] = SkRect::MakeLTRB(-1, -1, 2, 2);
   1364                 expected[1] = testBounds;
   1365                 REPORTER_ASSERT(reporter, path.isNestedRects(computed));
   1366                 REPORTER_ASSERT(reporter, expected[0] == computed[0]);
   1367                 REPORTER_ASSERT(reporter, expected[1] == computed[1]);
   1368             }
   1369             if (tests[testIndex] == lastPass) {
   1370                 fail = true;
   1371             }
   1372             if (tests[testIndex] == lastClose) {
   1373                 close = false;
   1374             }
   1375         }
   1376 
   1377         // fail, close then line
   1378         SkPath path1;
   1379         if (rectFirst) {
   1380             path1.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
   1381         }
   1382         path1.moveTo(r1[0].fX, r1[0].fY);
   1383         for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
   1384             path1.lineTo(r1[index].fX, r1[index].fY);
   1385         }
   1386         path1.close();
   1387         path1.lineTo(1, 0);
   1388         if (!rectFirst) {
   1389             path1.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
   1390         }
   1391         REPORTER_ASSERT(reporter, fail ^ path1.isNestedRects(0));
   1392 
   1393         // fail, move in the middle
   1394         path1.reset();
   1395         if (rectFirst) {
   1396             path1.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
   1397         }
   1398         path1.moveTo(r1[0].fX, r1[0].fY);
   1399         for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
   1400             if (index == 2) {
   1401                 path1.moveTo(1, .5f);
   1402             }
   1403             path1.lineTo(r1[index].fX, r1[index].fY);
   1404         }
   1405         path1.close();
   1406         if (!rectFirst) {
   1407             path1.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
   1408         }
   1409         REPORTER_ASSERT(reporter, fail ^ path1.isNestedRects(0));
   1410 
   1411         // fail, move on the edge
   1412         path1.reset();
   1413         if (rectFirst) {
   1414             path1.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
   1415         }
   1416         for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
   1417             path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
   1418             path1.lineTo(r1[index].fX, r1[index].fY);
   1419         }
   1420         path1.close();
   1421         if (!rectFirst) {
   1422             path1.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
   1423         }
   1424         REPORTER_ASSERT(reporter, fail ^ path1.isNestedRects(0));
   1425 
   1426         // fail, quad
   1427         path1.reset();
   1428         if (rectFirst) {
   1429             path1.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
   1430         }
   1431         path1.moveTo(r1[0].fX, r1[0].fY);
   1432         for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
   1433             if (index == 2) {
   1434                 path1.quadTo(1, .5f, 1, .5f);
   1435             }
   1436             path1.lineTo(r1[index].fX, r1[index].fY);
   1437         }
   1438         path1.close();
   1439         if (!rectFirst) {
   1440             path1.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
   1441         }
   1442         REPORTER_ASSERT(reporter, fail ^ path1.isNestedRects(0));
   1443 
   1444         // fail, cubic
   1445         path1.reset();
   1446         if (rectFirst) {
   1447             path1.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
   1448         }
   1449         path1.moveTo(r1[0].fX, r1[0].fY);
   1450         for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
   1451             if (index == 2) {
   1452                 path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
   1453             }
   1454             path1.lineTo(r1[index].fX, r1[index].fY);
   1455         }
   1456         path1.close();
   1457         if (!rectFirst) {
   1458             path1.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
   1459         }
   1460         REPORTER_ASSERT(reporter, fail ^ path1.isNestedRects(0));
   1461 
   1462         // fail,  not nested
   1463         path1.reset();
   1464         path1.addRect(1, 1, 3, 3, SkPath::kCW_Direction);
   1465         path1.addRect(2, 2, 4, 4, SkPath::kCW_Direction);
   1466         REPORTER_ASSERT(reporter, fail ^ path1.isNestedRects(0));
   1467     }
   1468 
   1469     // pass, stroke rect
   1470     SkPath src, dst;
   1471     src.addRect(1, 1, 7, 7, SkPath::kCW_Direction);
   1472     SkPaint strokePaint;
   1473     strokePaint.setStyle(SkPaint::kStroke_Style);
   1474     strokePaint.setStrokeWidth(2);
   1475     strokePaint.getFillPath(src, &dst);
   1476     REPORTER_ASSERT(reporter, dst.isNestedRects(0));
   1477 }
   1478 
   1479 static void write_and_read_back(skiatest::Reporter* reporter,
   1480                                 const SkPath& p) {
   1481     SkWriter32 writer(100);
   1482     writer.writePath(p);
   1483     size_t size = writer.size();
   1484     SkAutoMalloc storage(size);
   1485     writer.flatten(storage.get());
   1486     SkReader32 reader(storage.get(), size);
   1487 
   1488     SkPath readBack;
   1489     REPORTER_ASSERT(reporter, readBack != p);
   1490     reader.readPath(&readBack);
   1491     REPORTER_ASSERT(reporter, readBack == p);
   1492 
   1493     REPORTER_ASSERT(reporter, readBack.getConvexityOrUnknown() ==
   1494                               p.getConvexityOrUnknown());
   1495 
   1496     REPORTER_ASSERT(reporter, readBack.isOval(NULL) == p.isOval(NULL));
   1497 
   1498     const SkRect& origBounds = p.getBounds();
   1499     const SkRect& readBackBounds = readBack.getBounds();
   1500 
   1501     REPORTER_ASSERT(reporter, origBounds == readBackBounds);
   1502 }
   1503 
   1504 static void test_flattening(skiatest::Reporter* reporter) {
   1505     SkPath p;
   1506 
   1507     static const SkPoint pts[] = {
   1508         { 0, 0 },
   1509         { SkIntToScalar(10), SkIntToScalar(10) },
   1510         { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
   1511         { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
   1512     };
   1513     p.moveTo(pts[0]);
   1514     p.lineTo(pts[1]);
   1515     p.quadTo(pts[2], pts[3]);
   1516     p.cubicTo(pts[4], pts[5], pts[6]);
   1517 
   1518     write_and_read_back(reporter, p);
   1519 
   1520     // create a buffer that should be much larger than the path so we don't
   1521     // kill our stack if writer goes too far.
   1522     char buffer[1024];
   1523     uint32_t size1 = p.writeToMemory(NULL);
   1524     uint32_t size2 = p.writeToMemory(buffer);
   1525     REPORTER_ASSERT(reporter, size1 == size2);
   1526 
   1527     SkPath p2;
   1528     uint32_t size3 = p2.readFromMemory(buffer);
   1529     REPORTER_ASSERT(reporter, size1 == size3);
   1530     REPORTER_ASSERT(reporter, p == p2);
   1531 
   1532     char buffer2[1024];
   1533     size3 = p2.writeToMemory(buffer2);
   1534     REPORTER_ASSERT(reporter, size1 == size3);
   1535     REPORTER_ASSERT(reporter, memcmp(buffer, buffer2, size1) == 0);
   1536 
   1537     // test persistence of the oval flag & convexity
   1538     {
   1539         SkPath oval;
   1540         SkRect rect = SkRect::MakeWH(10, 10);
   1541         oval.addOval(rect);
   1542 
   1543         write_and_read_back(reporter, oval);
   1544     }
   1545 }
   1546 
   1547 static void test_transform(skiatest::Reporter* reporter) {
   1548     SkPath p, p1;
   1549 
   1550     static const SkPoint pts[] = {
   1551         { 0, 0 },
   1552         { SkIntToScalar(10), SkIntToScalar(10) },
   1553         { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
   1554         { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
   1555     };
   1556     p.moveTo(pts[0]);
   1557     p.lineTo(pts[1]);
   1558     p.quadTo(pts[2], pts[3]);
   1559     p.cubicTo(pts[4], pts[5], pts[6]);
   1560 
   1561     SkMatrix matrix;
   1562     matrix.reset();
   1563     p.transform(matrix, &p1);
   1564     REPORTER_ASSERT(reporter, p == p1);
   1565 
   1566     matrix.setScale(SK_Scalar1 * 2, SK_Scalar1 * 3);
   1567     p.transform(matrix, &p1);
   1568     SkPoint pts1[7];
   1569     int count = p1.getPoints(pts1, 7);
   1570     REPORTER_ASSERT(reporter, 7 == count);
   1571     for (int i = 0; i < count; ++i) {
   1572         SkPoint newPt = SkPoint::Make(pts[i].fX * 2, pts[i].fY * 3);
   1573         REPORTER_ASSERT(reporter, newPt == pts1[i]);
   1574     }
   1575 }
   1576 
   1577 static void test_zero_length_paths(skiatest::Reporter* reporter) {
   1578     SkPath  p;
   1579     uint8_t verbs[32];
   1580 
   1581     struct SUPPRESS_VISIBILITY_WARNING zeroPathTestData {
   1582         const char* testPath;
   1583         const size_t numResultPts;
   1584         const SkRect resultBound;
   1585         const SkPath::Verb* resultVerbs;
   1586         const size_t numResultVerbs;
   1587     };
   1588 
   1589     static const SkPath::Verb resultVerbs1[] = { SkPath::kMove_Verb };
   1590     static const SkPath::Verb resultVerbs2[] = { SkPath::kMove_Verb, SkPath::kMove_Verb };
   1591     static const SkPath::Verb resultVerbs3[] = { SkPath::kMove_Verb, SkPath::kClose_Verb };
   1592     static const SkPath::Verb resultVerbs4[] = { SkPath::kMove_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kClose_Verb };
   1593     static const SkPath::Verb resultVerbs5[] = { SkPath::kMove_Verb, SkPath::kLine_Verb };
   1594     static const SkPath::Verb resultVerbs6[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kMove_Verb, SkPath::kLine_Verb };
   1595     static const SkPath::Verb resultVerbs7[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb };
   1596     static const SkPath::Verb resultVerbs8[] = {
   1597         SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb
   1598     };
   1599     static const SkPath::Verb resultVerbs9[] = { SkPath::kMove_Verb, SkPath::kQuad_Verb };
   1600     static const SkPath::Verb resultVerbs10[] = { SkPath::kMove_Verb, SkPath::kQuad_Verb, SkPath::kMove_Verb, SkPath::kQuad_Verb };
   1601     static const SkPath::Verb resultVerbs11[] = { SkPath::kMove_Verb, SkPath::kQuad_Verb, SkPath::kClose_Verb };
   1602     static const SkPath::Verb resultVerbs12[] = {
   1603         SkPath::kMove_Verb, SkPath::kQuad_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kQuad_Verb, SkPath::kClose_Verb
   1604     };
   1605     static const SkPath::Verb resultVerbs13[] = { SkPath::kMove_Verb, SkPath::kCubic_Verb };
   1606     static const SkPath::Verb resultVerbs14[] = { SkPath::kMove_Verb, SkPath::kCubic_Verb, SkPath::kMove_Verb, SkPath::kCubic_Verb };
   1607     static const SkPath::Verb resultVerbs15[] = { SkPath::kMove_Verb, SkPath::kCubic_Verb, SkPath::kClose_Verb };
   1608     static const SkPath::Verb resultVerbs16[] = {
   1609         SkPath::kMove_Verb, SkPath::kCubic_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kCubic_Verb, SkPath::kClose_Verb
   1610     };
   1611     static const struct zeroPathTestData gZeroLengthTests[] = {
   1612         { "M 1 1", 1, {0, 0, 0, 0}, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
   1613         { "M 1 1 M 2 1", 2, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs2, SK_ARRAY_COUNT(resultVerbs2) },
   1614         { "M 1 1 z", 1, {0, 0, 0, 0}, resultVerbs3, SK_ARRAY_COUNT(resultVerbs3) },
   1615         { "M 1 1 z M 2 1 z", 2, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs4, SK_ARRAY_COUNT(resultVerbs4) },
   1616         { "M 1 1 L 1 1", 2, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs5, SK_ARRAY_COUNT(resultVerbs5) },
   1617         { "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) },
   1618         { "M 1 1 L 1 1 z", 2, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs7, SK_ARRAY_COUNT(resultVerbs7) },
   1619         { "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) },
   1620         { "M 1 1 Q 1 1 1 1", 3, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs9, SK_ARRAY_COUNT(resultVerbs9) },
   1621         { "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) },
   1622         { "M 1 1 Q 1 1 1 1 z", 3, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs11, SK_ARRAY_COUNT(resultVerbs11) },
   1623         { "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) },
   1624         { "M 1 1 C 1 1 1 1 1 1", 4, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs13, SK_ARRAY_COUNT(resultVerbs13) },
   1625         { "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,
   1626             SK_ARRAY_COUNT(resultVerbs14)
   1627         },
   1628         { "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) },
   1629         { "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,
   1630             SK_ARRAY_COUNT(resultVerbs16)
   1631         }
   1632     };
   1633 
   1634     for (size_t i = 0; i < SK_ARRAY_COUNT(gZeroLengthTests); ++i) {
   1635         p.reset();
   1636         bool valid = SkParsePath::FromSVGString(gZeroLengthTests[i].testPath, &p);
   1637         REPORTER_ASSERT(reporter, valid);
   1638         REPORTER_ASSERT(reporter, !p.isEmpty());
   1639         REPORTER_ASSERT(reporter, gZeroLengthTests[i].numResultPts == (size_t)p.countPoints());
   1640         REPORTER_ASSERT(reporter, gZeroLengthTests[i].resultBound == p.getBounds());
   1641         REPORTER_ASSERT(reporter, gZeroLengthTests[i].numResultVerbs == (size_t)p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
   1642         for (size_t j = 0; j < gZeroLengthTests[i].numResultVerbs; ++j) {
   1643             REPORTER_ASSERT(reporter, gZeroLengthTests[i].resultVerbs[j] == verbs[j]);
   1644         }
   1645     }
   1646 }
   1647 
   1648 struct SegmentInfo {
   1649     SkPath fPath;
   1650     int    fPointCount;
   1651 };
   1652 
   1653 #define kCurveSegmentMask   (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)
   1654 
   1655 static void test_segment_masks(skiatest::Reporter* reporter) {
   1656     SkPath p, p2;
   1657 
   1658     p.moveTo(0, 0);
   1659     p.quadTo(100, 100, 200, 200);
   1660     REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == p.getSegmentMasks());
   1661     REPORTER_ASSERT(reporter, !p.isEmpty());
   1662     p2 = p;
   1663     REPORTER_ASSERT(reporter, p2.getSegmentMasks() == p.getSegmentMasks());
   1664     p.cubicTo(100, 100, 200, 200, 300, 300);
   1665     REPORTER_ASSERT(reporter, kCurveSegmentMask == p.getSegmentMasks());
   1666     REPORTER_ASSERT(reporter, !p.isEmpty());
   1667     p2 = p;
   1668     REPORTER_ASSERT(reporter, p2.getSegmentMasks() == p.getSegmentMasks());
   1669 
   1670     p.reset();
   1671     p.moveTo(0, 0);
   1672     p.cubicTo(100, 100, 200, 200, 300, 300);
   1673     REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == p.getSegmentMasks());
   1674     p2 = p;
   1675     REPORTER_ASSERT(reporter, p2.getSegmentMasks() == p.getSegmentMasks());
   1676 
   1677     REPORTER_ASSERT(reporter, !p.isEmpty());
   1678 }
   1679 
   1680 static void test_iter(skiatest::Reporter* reporter) {
   1681     SkPath  p;
   1682     SkPoint pts[4];
   1683 
   1684     // Test an iterator with no path
   1685     SkPath::Iter noPathIter;
   1686     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
   1687 
   1688     // Test that setting an empty path works
   1689     noPathIter.setPath(p, false);
   1690     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
   1691 
   1692     // Test that close path makes no difference for an empty path
   1693     noPathIter.setPath(p, true);
   1694     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
   1695 
   1696     // Test an iterator with an initial empty path
   1697     SkPath::Iter iter(p, false);
   1698     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
   1699 
   1700     // Test that close path makes no difference
   1701     iter.setPath(p, true);
   1702     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
   1703 
   1704 
   1705     struct iterTestData {
   1706         const char* testPath;
   1707         const bool forceClose;
   1708         const bool consumeDegenerates;
   1709         const size_t* numResultPtsPerVerb;
   1710         const SkPoint* resultPts;
   1711         const SkPath::Verb* resultVerbs;
   1712         const size_t numResultVerbs;
   1713     };
   1714 
   1715     static const SkPath::Verb resultVerbs1[] = { SkPath::kDone_Verb };
   1716     static const SkPath::Verb resultVerbs2[] = {
   1717         SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kDone_Verb
   1718     };
   1719     static const SkPath::Verb resultVerbs3[] = {
   1720         SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb, SkPath::kDone_Verb
   1721     };
   1722     static const SkPath::Verb resultVerbs4[] = {
   1723         SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kMove_Verb, SkPath::kClose_Verb, SkPath::kDone_Verb
   1724     };
   1725     static const SkPath::Verb resultVerbs5[] = {
   1726         SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kClose_Verb, SkPath::kDone_Verb
   1727     };
   1728     static const size_t resultPtsSizes1[] = { 0 };
   1729     static const size_t resultPtsSizes2[] = { 1, 2, 2, 0 };
   1730     static const size_t resultPtsSizes3[] = { 1, 2, 2, 2, 1, 0 };
   1731     static const size_t resultPtsSizes4[] = { 1, 2, 1, 1, 0 };
   1732     static const size_t resultPtsSizes5[] = { 1, 2, 1, 1, 1, 0 };
   1733     static const SkPoint* resultPts1 = 0;
   1734     static const SkPoint resultPts2[] = {
   1735         { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, SK_Scalar1 }, { SK_Scalar1, SK_Scalar1 }, { 0, SK_Scalar1 }
   1736     };
   1737     static const SkPoint resultPts3[] = {
   1738         { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, SK_Scalar1 }, { SK_Scalar1, SK_Scalar1 }, { 0, SK_Scalar1 },
   1739         { 0, SK_Scalar1 }, { SK_Scalar1, 0 }, { SK_Scalar1, 0 }
   1740     };
   1741     static const SkPoint resultPts4[] = {
   1742         { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { 0, 0 }, { 0, 0 }
   1743     };
   1744     static const SkPoint resultPts5[] = {
   1745         { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { 0, 0 }, { 0, 0 }
   1746     };
   1747     static const struct iterTestData gIterTests[] = {
   1748         { "M 1 0", false, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
   1749         { "M 1 0 M 2 0 M 3 0 M 4 0 M 5 0", false, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
   1750         { "M 1 0 M 1 0 M 3 0 M 4 0 M 5 0", true, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
   1751         { "z", false, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
   1752         { "z", true, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
   1753         { "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) },
   1754         { "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) },
   1755         { "M 1 0 L 1 1 L 0 1 M 0 0 z", false, true, resultPtsSizes2, resultPts2, resultVerbs2, SK_ARRAY_COUNT(resultVerbs2) },
   1756         { "M 1 0 L 1 1 L 0 1 M 0 0 z", true, true, resultPtsSizes3, resultPts3, resultVerbs3, SK_ARRAY_COUNT(resultVerbs3) },
   1757         { "M 1 0 L 1 0 M 0 0 z", false, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
   1758         { "M 1 0 L 1 0 M 0 0 z", true, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
   1759         { "M 1 0 L 1 0 M 0 0 z", false, false, resultPtsSizes4, resultPts4, resultVerbs4, SK_ARRAY_COUNT(resultVerbs4) },
   1760         { "M 1 0 L 1 0 M 0 0 z", true, false, resultPtsSizes5, resultPts5, resultVerbs5, SK_ARRAY_COUNT(resultVerbs5) }
   1761     };
   1762 
   1763     for (size_t i = 0; i < SK_ARRAY_COUNT(gIterTests); ++i) {
   1764         p.reset();
   1765         bool valid = SkParsePath::FromSVGString(gIterTests[i].testPath, &p);
   1766         REPORTER_ASSERT(reporter, valid);
   1767         iter.setPath(p, gIterTests[i].forceClose);
   1768         int j = 0, l = 0;
   1769         do {
   1770             REPORTER_ASSERT(reporter, iter.next(pts, gIterTests[i].consumeDegenerates) == gIterTests[i].resultVerbs[j]);
   1771             for (int k = 0; k < (int)gIterTests[i].numResultPtsPerVerb[j]; ++k) {
   1772                 REPORTER_ASSERT(reporter, pts[k] == gIterTests[i].resultPts[l++]);
   1773             }
   1774         } while (gIterTests[i].resultVerbs[j++] != SkPath::kDone_Verb);
   1775         REPORTER_ASSERT(reporter, j == (int)gIterTests[i].numResultVerbs);
   1776     }
   1777 
   1778     // The GM degeneratesegments.cpp test is more extensive
   1779 }
   1780 
   1781 static void test_raw_iter(skiatest::Reporter* reporter) {
   1782     SkPath p;
   1783     SkPoint pts[4];
   1784 
   1785     // Test an iterator with no path
   1786     SkPath::RawIter noPathIter;
   1787     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
   1788     // Test that setting an empty path works
   1789     noPathIter.setPath(p);
   1790     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
   1791 
   1792     // Test an iterator with an initial empty path
   1793     SkPath::RawIter iter(p);
   1794     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
   1795 
   1796     // Test that a move-only path returns the move.
   1797     p.moveTo(SK_Scalar1, 0);
   1798     iter.setPath(p);
   1799     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
   1800     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
   1801     REPORTER_ASSERT(reporter, pts[0].fY == 0);
   1802     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
   1803 
   1804     // No matter how many moves we add, we should get them all back
   1805     p.moveTo(SK_Scalar1*2, SK_Scalar1);
   1806     p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
   1807     iter.setPath(p);
   1808     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
   1809     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
   1810     REPORTER_ASSERT(reporter, pts[0].fY == 0);
   1811     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
   1812     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
   1813     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
   1814     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
   1815     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
   1816     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
   1817     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
   1818 
   1819     // Initial close is never ever stored
   1820     p.reset();
   1821     p.close();
   1822     iter.setPath(p);
   1823     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
   1824 
   1825     // Move/close sequences
   1826     p.reset();
   1827     p.close(); // Not stored, no purpose
   1828     p.moveTo(SK_Scalar1, 0);
   1829     p.close();
   1830     p.close(); // Not stored, no purpose
   1831     p.moveTo(SK_Scalar1*2, SK_Scalar1);
   1832     p.close();
   1833     p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
   1834     p.moveTo(SK_Scalar1*4, SK_Scalar1*3);
   1835     p.close();
   1836     iter.setPath(p);
   1837     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
   1838     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
   1839     REPORTER_ASSERT(reporter, pts[0].fY == 0);
   1840     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
   1841     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
   1842     REPORTER_ASSERT(reporter, pts[0].fY == 0);
   1843     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
   1844     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
   1845     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
   1846     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
   1847     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
   1848     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
   1849     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
   1850     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
   1851     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
   1852     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
   1853     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
   1854     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
   1855     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
   1856     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
   1857     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
   1858     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
   1859 
   1860     // Generate random paths and verify
   1861     SkPoint randomPts[25];
   1862     for (int i = 0; i < 5; ++i) {
   1863         for (int j = 0; j < 5; ++j) {
   1864             randomPts[i*5+j].set(SK_Scalar1*i, SK_Scalar1*j);
   1865         }
   1866     }
   1867 
   1868     // Max of 10 segments, max 3 points per segment
   1869     SkRandom rand(9876543);
   1870     SkPoint          expectedPts[31]; // May have leading moveTo
   1871     SkPath::Verb     expectedVerbs[22]; // May have leading moveTo
   1872     SkPath::Verb     nextVerb;
   1873 
   1874     for (int i = 0; i < 500; ++i) {
   1875         p.reset();
   1876         bool lastWasClose = true;
   1877         bool haveMoveTo = false;
   1878         SkPoint lastMoveToPt = { 0, 0 };
   1879         int numPoints = 0;
   1880         int numVerbs = (rand.nextU() >> 16) % 10;
   1881         int numIterVerbs = 0;
   1882         for (int j = 0; j < numVerbs; ++j) {
   1883             do {
   1884                 nextVerb = static_cast<SkPath::Verb>((rand.nextU() >> 16) % SkPath::kDone_Verb);
   1885             } while (lastWasClose && nextVerb == SkPath::kClose_Verb);
   1886             switch (nextVerb) {
   1887                 case SkPath::kMove_Verb:
   1888                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
   1889                     p.moveTo(expectedPts[numPoints]);
   1890                     lastMoveToPt = expectedPts[numPoints];
   1891                     numPoints += 1;
   1892                     lastWasClose = false;
   1893                     haveMoveTo = true;
   1894                     break;
   1895                 case SkPath::kLine_Verb:
   1896                     if (!haveMoveTo) {
   1897                         expectedPts[numPoints++] = lastMoveToPt;
   1898                         expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
   1899                         haveMoveTo = true;
   1900                     }
   1901                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
   1902                     p.lineTo(expectedPts[numPoints]);
   1903                     numPoints += 1;
   1904                     lastWasClose = false;
   1905                     break;
   1906                 case SkPath::kQuad_Verb:
   1907                     if (!haveMoveTo) {
   1908                         expectedPts[numPoints++] = lastMoveToPt;
   1909                         expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
   1910                         haveMoveTo = true;
   1911                     }
   1912                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
   1913                     expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
   1914                     p.quadTo(expectedPts[numPoints], expectedPts[numPoints + 1]);
   1915                     numPoints += 2;
   1916                     lastWasClose = false;
   1917                     break;
   1918                 case SkPath::kCubic_Verb:
   1919                     if (!haveMoveTo) {
   1920                         expectedPts[numPoints++] = lastMoveToPt;
   1921                         expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
   1922                         haveMoveTo = true;
   1923                     }
   1924                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
   1925                     expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
   1926                     expectedPts[numPoints + 2] = randomPts[(rand.nextU() >> 16) % 25];
   1927                     p.cubicTo(expectedPts[numPoints], expectedPts[numPoints + 1],
   1928                               expectedPts[numPoints + 2]);
   1929                     numPoints += 3;
   1930                     lastWasClose = false;
   1931                     break;
   1932                 case SkPath::kClose_Verb:
   1933                     p.close();
   1934                     haveMoveTo = false;
   1935                     lastWasClose = true;
   1936                     break;
   1937                 default:;
   1938             }
   1939             expectedVerbs[numIterVerbs++] = nextVerb;
   1940         }
   1941 
   1942         iter.setPath(p);
   1943         numVerbs = numIterVerbs;
   1944         numIterVerbs = 0;
   1945         int numIterPts = 0;
   1946         SkPoint lastMoveTo;
   1947         SkPoint lastPt;
   1948         lastMoveTo.set(0, 0);
   1949         lastPt.set(0, 0);
   1950         while ((nextVerb = iter.next(pts)) != SkPath::kDone_Verb) {
   1951             REPORTER_ASSERT(reporter, nextVerb == expectedVerbs[numIterVerbs]);
   1952             numIterVerbs++;
   1953             switch (nextVerb) {
   1954                 case SkPath::kMove_Verb:
   1955                     REPORTER_ASSERT(reporter, numIterPts < numPoints);
   1956                     REPORTER_ASSERT(reporter, pts[0] == expectedPts[numIterPts]);
   1957                     lastPt = lastMoveTo = pts[0];
   1958                     numIterPts += 1;
   1959                     break;
   1960                 case SkPath::kLine_Verb:
   1961                     REPORTER_ASSERT(reporter, numIterPts < numPoints + 1);
   1962                     REPORTER_ASSERT(reporter, pts[0] == lastPt);
   1963                     REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
   1964                     lastPt = pts[1];
   1965                     numIterPts += 1;
   1966                     break;
   1967                 case SkPath::kQuad_Verb:
   1968                     REPORTER_ASSERT(reporter, numIterPts < numPoints + 2);
   1969                     REPORTER_ASSERT(reporter, pts[0] == lastPt);
   1970                     REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
   1971                     REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
   1972                     lastPt = pts[2];
   1973                     numIterPts += 2;
   1974                     break;
   1975                 case SkPath::kCubic_Verb:
   1976                     REPORTER_ASSERT(reporter, numIterPts < numPoints + 3);
   1977                     REPORTER_ASSERT(reporter, pts[0] == lastPt);
   1978                     REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
   1979                     REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
   1980                     REPORTER_ASSERT(reporter, pts[3] == expectedPts[numIterPts + 2]);
   1981                     lastPt = pts[3];
   1982                     numIterPts += 3;
   1983                     break;
   1984                 case SkPath::kClose_Verb:
   1985                     REPORTER_ASSERT(reporter, pts[0] == lastMoveTo);
   1986                     lastPt = lastMoveTo;
   1987                     break;
   1988                 default:;
   1989             }
   1990         }
   1991         REPORTER_ASSERT(reporter, numIterPts == numPoints);
   1992         REPORTER_ASSERT(reporter, numIterVerbs == numVerbs);
   1993     }
   1994 }
   1995 
   1996 static void check_for_circle(skiatest::Reporter* reporter,
   1997                              const SkPath& path,
   1998                              bool expectedCircle,
   1999                              SkPath::Direction expectedDir) {
   2000     SkRect rect;
   2001     REPORTER_ASSERT(reporter, path.isOval(&rect) == expectedCircle);
   2002     REPORTER_ASSERT(reporter, path.cheapIsDirection(expectedDir));
   2003 
   2004     if (expectedCircle) {
   2005         REPORTER_ASSERT(reporter, rect.height() == rect.width());
   2006     }
   2007 }
   2008 
   2009 static void test_circle_skew(skiatest::Reporter* reporter,
   2010                              const SkPath& path,
   2011                              SkPath::Direction dir) {
   2012     SkPath tmp;
   2013 
   2014     SkMatrix m;
   2015     m.setSkew(SkIntToScalar(3), SkIntToScalar(5));
   2016     path.transform(m, &tmp);
   2017     // this matrix reverses the direction.
   2018     if (SkPath::kCCW_Direction == dir) {
   2019         dir = SkPath::kCW_Direction;
   2020     } else {
   2021         SkASSERT(SkPath::kCW_Direction == dir);
   2022         dir = SkPath::kCCW_Direction;
   2023     }
   2024     check_for_circle(reporter, tmp, false, dir);
   2025 }
   2026 
   2027 static void test_circle_translate(skiatest::Reporter* reporter,
   2028                                   const SkPath& path,
   2029                                   SkPath::Direction dir) {
   2030     SkPath tmp;
   2031 
   2032     // translate at small offset
   2033     SkMatrix m;
   2034     m.setTranslate(SkIntToScalar(15), SkIntToScalar(15));
   2035     path.transform(m, &tmp);
   2036     check_for_circle(reporter, tmp, true, dir);
   2037 
   2038     tmp.reset();
   2039     m.reset();
   2040 
   2041     // translate at a relatively big offset
   2042     m.setTranslate(SkIntToScalar(1000), SkIntToScalar(1000));
   2043     path.transform(m, &tmp);
   2044     check_for_circle(reporter, tmp, true, dir);
   2045 }
   2046 
   2047 static void test_circle_rotate(skiatest::Reporter* reporter,
   2048                                const SkPath& path,
   2049                                SkPath::Direction dir) {
   2050     for (int angle = 0; angle < 360; ++angle) {
   2051         SkPath tmp;
   2052         SkMatrix m;
   2053         m.setRotate(SkIntToScalar(angle));
   2054         path.transform(m, &tmp);
   2055 
   2056         // TODO: a rotated circle whose rotated angle is not a multiple of 90
   2057         // degrees is not an oval anymore, this can be improved.  we made this
   2058         // for the simplicity of our implementation.
   2059         if (angle % 90 == 0) {
   2060             check_for_circle(reporter, tmp, true, dir);
   2061         } else {
   2062             check_for_circle(reporter, tmp, false, dir);
   2063         }
   2064     }
   2065 }
   2066 
   2067 static void test_circle_mirror_x(skiatest::Reporter* reporter,
   2068                                  const SkPath& path,
   2069                                  SkPath::Direction dir) {
   2070     SkPath tmp;
   2071     SkMatrix m;
   2072     m.reset();
   2073     m.setScaleX(-SK_Scalar1);
   2074     path.transform(m, &tmp);
   2075 
   2076     if (SkPath::kCW_Direction == dir) {
   2077         dir = SkPath::kCCW_Direction;
   2078     } else {
   2079         SkASSERT(SkPath::kCCW_Direction == dir);
   2080         dir = SkPath::kCW_Direction;
   2081     }
   2082 
   2083     check_for_circle(reporter, tmp, true, dir);
   2084 }
   2085 
   2086 static void test_circle_mirror_y(skiatest::Reporter* reporter,
   2087                                  const SkPath& path,
   2088                                  SkPath::Direction dir) {
   2089     SkPath tmp;
   2090     SkMatrix m;
   2091     m.reset();
   2092     m.setScaleY(-SK_Scalar1);
   2093     path.transform(m, &tmp);
   2094 
   2095     if (SkPath::kCW_Direction == dir) {
   2096         dir = SkPath::kCCW_Direction;
   2097     } else {
   2098         SkASSERT(SkPath::kCCW_Direction == dir);
   2099         dir = SkPath::kCW_Direction;
   2100     }
   2101 
   2102     check_for_circle(reporter, tmp, true, dir);
   2103 }
   2104 
   2105 static void test_circle_mirror_xy(skiatest::Reporter* reporter,
   2106                                  const SkPath& path,
   2107                                  SkPath::Direction dir) {
   2108     SkPath tmp;
   2109     SkMatrix m;
   2110     m.reset();
   2111     m.setScaleX(-SK_Scalar1);
   2112     m.setScaleY(-SK_Scalar1);
   2113     path.transform(m, &tmp);
   2114 
   2115     check_for_circle(reporter, tmp, true, dir);
   2116 }
   2117 
   2118 static void test_circle_with_direction(skiatest::Reporter* reporter,
   2119                                        SkPath::Direction dir) {
   2120     SkPath path;
   2121 
   2122     // circle at origin
   2123     path.addCircle(0, 0, SkIntToScalar(20), dir);
   2124     check_for_circle(reporter, path, true, dir);
   2125     test_circle_rotate(reporter, path, dir);
   2126     test_circle_translate(reporter, path, dir);
   2127     test_circle_skew(reporter, path, dir);
   2128 
   2129     // circle at an offset at (10, 10)
   2130     path.reset();
   2131     path.addCircle(SkIntToScalar(10), SkIntToScalar(10),
   2132                    SkIntToScalar(20), dir);
   2133     check_for_circle(reporter, path, true, dir);
   2134     test_circle_rotate(reporter, path, dir);
   2135     test_circle_translate(reporter, path, dir);
   2136     test_circle_skew(reporter, path, dir);
   2137     test_circle_mirror_x(reporter, path, dir);
   2138     test_circle_mirror_y(reporter, path, dir);
   2139     test_circle_mirror_xy(reporter, path, dir);
   2140 }
   2141 
   2142 static void test_circle_with_add_paths(skiatest::Reporter* reporter) {
   2143     SkPath path;
   2144     SkPath circle;
   2145     SkPath rect;
   2146     SkPath empty;
   2147 
   2148     static const SkPath::Direction kCircleDir = SkPath::kCW_Direction;
   2149     static const SkPath::Direction kCircleDirOpposite = SkPath::kCCW_Direction;
   2150 
   2151     circle.addCircle(0, 0, SkIntToScalar(10), kCircleDir);
   2152     rect.addRect(SkIntToScalar(5), SkIntToScalar(5),
   2153                  SkIntToScalar(20), SkIntToScalar(20), SkPath::kCW_Direction);
   2154 
   2155     SkMatrix translate;
   2156     translate.setTranslate(SkIntToScalar(12), SkIntToScalar(12));
   2157 
   2158     // For simplicity, all the path concatenation related operations
   2159     // would mark it non-circle, though in theory it's still a circle.
   2160 
   2161     // empty + circle (translate)
   2162     path = empty;
   2163     path.addPath(circle, translate);
   2164     check_for_circle(reporter, path, false, kCircleDir);
   2165 
   2166     // circle + empty (translate)
   2167     path = circle;
   2168     path.addPath(empty, translate);
   2169     check_for_circle(reporter, path, false, kCircleDir);
   2170 
   2171     // test reverseAddPath
   2172     path = circle;
   2173     path.reverseAddPath(rect);
   2174     check_for_circle(reporter, path, false, kCircleDirOpposite);
   2175 }
   2176 
   2177 static void test_circle(skiatest::Reporter* reporter) {
   2178     test_circle_with_direction(reporter, SkPath::kCW_Direction);
   2179     test_circle_with_direction(reporter, SkPath::kCCW_Direction);
   2180 
   2181     // multiple addCircle()
   2182     SkPath path;
   2183     path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
   2184     path.addCircle(0, 0, SkIntToScalar(20), SkPath::kCW_Direction);
   2185     check_for_circle(reporter, path, false, SkPath::kCW_Direction);
   2186 
   2187     // some extra lineTo() would make isOval() fail
   2188     path.reset();
   2189     path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
   2190     path.lineTo(0, 0);
   2191     check_for_circle(reporter, path, false, SkPath::kCW_Direction);
   2192 
   2193     // not back to the original point
   2194     path.reset();
   2195     path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
   2196     path.setLastPt(SkIntToScalar(5), SkIntToScalar(5));
   2197     check_for_circle(reporter, path, false, SkPath::kCW_Direction);
   2198 
   2199     test_circle_with_add_paths(reporter);
   2200 }
   2201 
   2202 static void test_oval(skiatest::Reporter* reporter) {
   2203     SkRect rect;
   2204     SkMatrix m;
   2205     SkPath path;
   2206 
   2207     rect = SkRect::MakeWH(SkIntToScalar(30), SkIntToScalar(50));
   2208     path.addOval(rect);
   2209 
   2210     REPORTER_ASSERT(reporter, path.isOval(NULL));
   2211 
   2212     m.setRotate(SkIntToScalar(90));
   2213     SkPath tmp;
   2214     path.transform(m, &tmp);
   2215     // an oval rotated 90 degrees is still an oval.
   2216     REPORTER_ASSERT(reporter, tmp.isOval(NULL));
   2217 
   2218     m.reset();
   2219     m.setRotate(SkIntToScalar(30));
   2220     tmp.reset();
   2221     path.transform(m, &tmp);
   2222     // an oval rotated 30 degrees is not an oval anymore.
   2223     REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
   2224 
   2225     // since empty path being transformed.
   2226     path.reset();
   2227     tmp.reset();
   2228     m.reset();
   2229     path.transform(m, &tmp);
   2230     REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
   2231 
   2232     // empty path is not an oval
   2233     tmp.reset();
   2234     REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
   2235 
   2236     // only has moveTo()s
   2237     tmp.reset();
   2238     tmp.moveTo(0, 0);
   2239     tmp.moveTo(SkIntToScalar(10), SkIntToScalar(10));
   2240     REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
   2241 
   2242     // mimic WebKit's calling convention,
   2243     // call moveTo() first and then call addOval()
   2244     path.reset();
   2245     path.moveTo(0, 0);
   2246     path.addOval(rect);
   2247     REPORTER_ASSERT(reporter, path.isOval(NULL));
   2248 
   2249     // copy path
   2250     path.reset();
   2251     tmp.reset();
   2252     tmp.addOval(rect);
   2253     path = tmp;
   2254     REPORTER_ASSERT(reporter, path.isOval(NULL));
   2255 }
   2256 
   2257 static void TestPath(skiatest::Reporter* reporter) {
   2258     SkTSize<SkScalar>::Make(3,4);
   2259 
   2260     SkPath  p, p2;
   2261     SkRect  bounds, bounds2;
   2262 
   2263     REPORTER_ASSERT(reporter, p.isEmpty());
   2264     REPORTER_ASSERT(reporter, 0 == p.countPoints());
   2265     REPORTER_ASSERT(reporter, 0 == p.countVerbs());
   2266     REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
   2267     REPORTER_ASSERT(reporter, p.isConvex());
   2268     REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType);
   2269     REPORTER_ASSERT(reporter, !p.isInverseFillType());
   2270     REPORTER_ASSERT(reporter, p == p2);
   2271     REPORTER_ASSERT(reporter, !(p != p2));
   2272 
   2273     REPORTER_ASSERT(reporter, p.getBounds().isEmpty());
   2274 
   2275     bounds.set(0, 0, SK_Scalar1, SK_Scalar1);
   2276 
   2277     p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1);
   2278     check_convex_bounds(reporter, p, bounds);
   2279     // we have quads or cubics
   2280     REPORTER_ASSERT(reporter, p.getSegmentMasks() & kCurveSegmentMask);
   2281     REPORTER_ASSERT(reporter, !p.isEmpty());
   2282 
   2283     p.reset();
   2284     REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
   2285     REPORTER_ASSERT(reporter, p.isEmpty());
   2286 
   2287     p.addOval(bounds);
   2288     check_convex_bounds(reporter, p, bounds);
   2289     REPORTER_ASSERT(reporter, !p.isEmpty());
   2290 
   2291     p.reset();
   2292     p.addRect(bounds);
   2293     check_convex_bounds(reporter, p, bounds);
   2294     // we have only lines
   2295     REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == p.getSegmentMasks());
   2296     REPORTER_ASSERT(reporter, !p.isEmpty());
   2297 
   2298     REPORTER_ASSERT(reporter, p != p2);
   2299     REPORTER_ASSERT(reporter, !(p == p2));
   2300 
   2301     // do getPoints and getVerbs return the right result
   2302     REPORTER_ASSERT(reporter, p.getPoints(NULL, 0) == 4);
   2303     REPORTER_ASSERT(reporter, p.getVerbs(NULL, 0) == 5);
   2304     SkPoint pts[4];
   2305     int count = p.getPoints(pts, 4);
   2306     REPORTER_ASSERT(reporter, count == 4);
   2307     uint8_t verbs[6];
   2308     verbs[5] = 0xff;
   2309     p.getVerbs(verbs, 5);
   2310     REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
   2311     REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[1]);
   2312     REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[2]);
   2313     REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[3]);
   2314     REPORTER_ASSERT(reporter, SkPath::kClose_Verb == verbs[4]);
   2315     REPORTER_ASSERT(reporter, 0xff == verbs[5]);
   2316     bounds2.set(pts, 4);
   2317     REPORTER_ASSERT(reporter, bounds == bounds2);
   2318 
   2319     bounds.offset(SK_Scalar1*3, SK_Scalar1*4);
   2320     p.offset(SK_Scalar1*3, SK_Scalar1*4);
   2321     REPORTER_ASSERT(reporter, bounds == p.getBounds());
   2322 
   2323     REPORTER_ASSERT(reporter, p.isRect(NULL));
   2324     bounds2.setEmpty();
   2325     REPORTER_ASSERT(reporter, p.isRect(&bounds2));
   2326     REPORTER_ASSERT(reporter, bounds == bounds2);
   2327 
   2328     // now force p to not be a rect
   2329     bounds.set(0, 0, SK_Scalar1/2, SK_Scalar1/2);
   2330     p.addRect(bounds);
   2331     REPORTER_ASSERT(reporter, !p.isRect(NULL));
   2332 
   2333     test_isLine(reporter);
   2334     test_isRect(reporter);
   2335     test_isNestedRects(reporter);
   2336     test_zero_length_paths(reporter);
   2337     test_direction(reporter);
   2338     test_convexity(reporter);
   2339     test_convexity2(reporter);
   2340     test_conservativelyContains(reporter);
   2341     test_close(reporter);
   2342     test_segment_masks(reporter);
   2343     test_flattening(reporter);
   2344     test_transform(reporter);
   2345     test_bounds(reporter);
   2346     test_iter(reporter);
   2347     test_raw_iter(reporter);
   2348     test_circle(reporter);
   2349     test_oval(reporter);
   2350     test_strokerec(reporter);
   2351     test_addPoly(reporter);
   2352     test_isfinite(reporter);
   2353     test_isfinite_after_transform(reporter);
   2354     test_tricky_cubic(reporter);
   2355     test_arb_round_rect_is_convex(reporter);
   2356     test_arb_zero_rad_round_rect_is_rect(reporter);
   2357     test_addrect_isfinite(reporter);
   2358     test_clipped_cubic(reporter);
   2359     test_crbug_170666(reporter);
   2360 }
   2361 
   2362 #include "TestClassDef.h"
   2363 DEFINE_TESTCLASS("Path", PathTestClass, TestPath)
   2364