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