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 "SkPaint.h"
     10 #include "SkPath.h"
     11 #include "SkParse.h"
     12 #include "SkParsePath.h"
     13 #include "SkRandom.h"
     14 #include "SkReader32.h"
     15 #include "SkSize.h"
     16 #include "SkWriter32.h"
     17 
     18 /**
     19  * cheapIsDirection can take a shortcut when a path is marked convex.
     20  * This function ensures that we always test cheapIsDirection when the path
     21  * is flagged with unknown convexity status.
     22  */
     23 static void check_direction(SkPath* path,
     24                             SkPath::Direction expectedDir,
     25                             skiatest::Reporter* reporter) {
     26     if (SkPath::kConvex_Convexity == path->getConvexity()) {
     27         REPORTER_ASSERT(reporter, path->cheapIsDirection(expectedDir));
     28         path->setConvexity(SkPath::kUnknown_Convexity);
     29     }
     30     REPORTER_ASSERT(reporter, path->cheapIsDirection(expectedDir));
     31 }
     32 
     33 static void test_direction(skiatest::Reporter* reporter) {
     34     size_t i;
     35     SkPath path;
     36     REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
     37     REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCW_Direction));
     38     REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCCW_Direction));
     39 
     40     static const char* gDegen[] = {
     41         "M 10 10",
     42         "M 10 10 M 20 20",
     43         "M 10 10 L 20 20",
     44         "M 10 10 L 10 10 L 10 10",
     45         "M 10 10 Q 10 10 10 10",
     46         "M 10 10 C 10 10 10 10 10 10",
     47     };
     48     for (i = 0; i < SK_ARRAY_COUNT(gDegen); ++i) {
     49         path.reset();
     50         bool valid = SkParsePath::FromSVGString(gDegen[i], &path);
     51         REPORTER_ASSERT(reporter, valid);
     52         REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
     53     }
     54 
     55     static const char* gCW[] = {
     56         "M 10 10 L 10 10 Q 20 10 20 20",
     57         "M 10 10 C 20 10 20 20 20 20",
     58         "M 20 10 Q 20 20 30 20 L 10 20", // test double-back at y-max
     59     };
     60     for (i = 0; i < SK_ARRAY_COUNT(gCW); ++i) {
     61         path.reset();
     62         bool valid = SkParsePath::FromSVGString(gCW[i], &path);
     63         REPORTER_ASSERT(reporter, valid);
     64         check_direction(&path, SkPath::kCW_Direction, reporter);
     65     }
     66 
     67     static const char* gCCW[] = {
     68         "M 10 10 L 10 10 Q 20 10 20 -20",
     69         "M 10 10 C 20 10 20 -20 20 -20",
     70         "M 20 10 Q 20 20 10 20 L 30 20", // test double-back at y-max
     71     };
     72     for (i = 0; i < SK_ARRAY_COUNT(gCCW); ++i) {
     73         path.reset();
     74         bool valid = SkParsePath::FromSVGString(gCCW[i], &path);
     75         REPORTER_ASSERT(reporter, valid);
     76         check_direction(&path, SkPath::kCCW_Direction, reporter);
     77     }
     78 
     79     // Test two donuts, each wound a different direction. Only the outer contour
     80     // determines the cheap direction
     81     path.reset();
     82     path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCW_Direction);
     83     path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCCW_Direction);
     84     check_direction(&path, SkPath::kCW_Direction, reporter);
     85 
     86     path.reset();
     87     path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCW_Direction);
     88     path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCCW_Direction);
     89     check_direction(&path, SkPath::kCCW_Direction, reporter);
     90 
     91 #ifdef SK_SCALAR_IS_FLOAT
     92     // triangle with one point really far from the origin.
     93     path.reset();
     94     // the first point is roughly 1.05e10, 1.05e10
     95     path.moveTo(SkFloatToScalar(SkBits2Float(0x501c7652)), SkFloatToScalar(SkBits2Float(0x501c7652)));
     96     path.lineTo(110 * SK_Scalar1, -10 * SK_Scalar1);
     97     path.lineTo(-10 * SK_Scalar1, 60 * SK_Scalar1);
     98     check_direction(&path, SkPath::kCCW_Direction, reporter);
     99 #endif
    100 }
    101 
    102 static void add_rect(SkPath* path, const SkRect& r) {
    103     path->moveTo(r.fLeft, r.fTop);
    104     path->lineTo(r.fRight, r.fTop);
    105     path->lineTo(r.fRight, r.fBottom);
    106     path->lineTo(r.fLeft, r.fBottom);
    107     path->close();
    108 }
    109 
    110 static void test_bounds(skiatest::Reporter* reporter) {
    111     static const SkRect rects[] = {
    112         { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(160) },
    113         { SkIntToScalar(610), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(199) },
    114         { SkIntToScalar(10), SkIntToScalar(198), SkIntToScalar(610), SkIntToScalar(199) },
    115         { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(10), SkIntToScalar(199) },
    116     };
    117 
    118     SkPath path0, path1;
    119     for (size_t i = 0; i < SK_ARRAY_COUNT(rects); ++i) {
    120         path0.addRect(rects[i]);
    121         add_rect(&path1, rects[i]);
    122     }
    123 
    124     REPORTER_ASSERT(reporter, path0.getBounds() == path1.getBounds());
    125 }
    126 
    127 static void stroke_cubic(const SkPoint pts[4]) {
    128     SkPath path;
    129     path.moveTo(pts[0]);
    130     path.cubicTo(pts[1], pts[2], pts[3]);
    131 
    132     SkPaint paint;
    133     paint.setStyle(SkPaint::kStroke_Style);
    134     paint.setStrokeWidth(SK_Scalar1 * 2);
    135 
    136     SkPath fill;
    137     paint.getFillPath(path, &fill);
    138 }
    139 
    140 // just ensure this can run w/o any SkASSERTS firing in the debug build
    141 // we used to assert due to differences in how we determine a degenerate vector
    142 // but that was fixed with the introduction of SkPoint::CanNormalize
    143 static void stroke_tiny_cubic() {
    144     SkPoint p0[] = {
    145         { 372.0f,   92.0f },
    146         { 372.0f,   92.0f },
    147         { 372.0f,   92.0f },
    148         { 372.0f,   92.0f },
    149     };
    150 
    151     stroke_cubic(p0);
    152 
    153     SkPoint p1[] = {
    154         { 372.0f,       92.0f },
    155         { 372.0007f,    92.000755f },
    156         { 371.99927f,   92.003922f },
    157         { 371.99826f,   92.003899f },
    158     };
    159 
    160     stroke_cubic(p1);
    161 }
    162 
    163 static void check_close(skiatest::Reporter* reporter, const SkPath& path) {
    164     for (int i = 0; i < 2; ++i) {
    165         SkPath::Iter iter(path, (bool)i);
    166         SkPoint mv;
    167         SkPoint pts[4];
    168         SkPath::Verb v;
    169         int nMT = 0;
    170         int nCL = 0;
    171         mv.set(0, 0);
    172         while (SkPath::kDone_Verb != (v = iter.next(pts))) {
    173             switch (v) {
    174                 case SkPath::kMove_Verb:
    175                     mv = pts[0];
    176                     ++nMT;
    177                     break;
    178                 case SkPath::kClose_Verb:
    179                     REPORTER_ASSERT(reporter, mv == pts[0]);
    180                     ++nCL;
    181                     break;
    182                 default:
    183                     break;
    184             }
    185         }
    186         // if we force a close on the interator we should have a close
    187         // for every moveTo
    188         REPORTER_ASSERT(reporter, !i || nMT == nCL);
    189     }
    190 }
    191 
    192 static void test_close(skiatest::Reporter* reporter) {
    193     SkPath closePt;
    194     closePt.moveTo(0, 0);
    195     closePt.close();
    196     check_close(reporter, closePt);
    197 
    198     SkPath openPt;
    199     openPt.moveTo(0, 0);
    200     check_close(reporter, openPt);
    201 
    202     SkPath empty;
    203     check_close(reporter, empty);
    204     empty.close();
    205     check_close(reporter, empty);
    206 
    207     SkPath rect;
    208     rect.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
    209     check_close(reporter, rect);
    210     rect.close();
    211     check_close(reporter, rect);
    212 
    213     SkPath quad;
    214     quad.quadTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
    215     check_close(reporter, quad);
    216     quad.close();
    217     check_close(reporter, quad);
    218 
    219     SkPath cubic;
    220     quad.cubicTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1,
    221                  10*SK_Scalar1, 20 * SK_Scalar1, 20*SK_Scalar1);
    222     check_close(reporter, cubic);
    223     cubic.close();
    224     check_close(reporter, cubic);
    225 
    226     SkPath line;
    227     line.moveTo(SK_Scalar1, SK_Scalar1);
    228     line.lineTo(10 * SK_Scalar1, 10*SK_Scalar1);
    229     check_close(reporter, line);
    230     line.close();
    231     check_close(reporter, line);
    232 
    233     SkPath rect2;
    234     rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
    235     rect2.close();
    236     rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
    237     check_close(reporter, rect2);
    238     rect2.close();
    239     check_close(reporter, rect2);
    240 
    241     SkPath oval3;
    242     oval3.addOval(SkRect::MakeWH(SK_Scalar1*100,SK_Scalar1*100));
    243     oval3.close();
    244     oval3.addOval(SkRect::MakeWH(SK_Scalar1*200,SK_Scalar1*200));
    245     check_close(reporter, oval3);
    246     oval3.close();
    247     check_close(reporter, oval3);
    248 
    249     SkPath moves;
    250     moves.moveTo(SK_Scalar1, SK_Scalar1);
    251     moves.moveTo(5 * SK_Scalar1, SK_Scalar1);
    252     moves.moveTo(SK_Scalar1, 10 * SK_Scalar1);
    253     moves.moveTo(10 *SK_Scalar1, SK_Scalar1);
    254     check_close(reporter, moves);
    255 
    256     stroke_tiny_cubic();
    257 }
    258 
    259 static void check_convexity(skiatest::Reporter* reporter, const SkPath& path,
    260                             SkPath::Convexity expected) {
    261     SkPath::Convexity c = SkPath::ComputeConvexity(path);
    262     REPORTER_ASSERT(reporter, c == expected);
    263 }
    264 
    265 static void test_convexity2(skiatest::Reporter* reporter) {
    266     SkPath pt;
    267     pt.moveTo(0, 0);
    268     pt.close();
    269     check_convexity(reporter, pt, SkPath::kConvex_Convexity);
    270 
    271     SkPath line;
    272     line.moveTo(12*SK_Scalar1, 20*SK_Scalar1);
    273     line.lineTo(-12*SK_Scalar1, -20*SK_Scalar1);
    274     line.close();
    275     check_convexity(reporter, pt, SkPath::kConvex_Convexity);
    276 
    277     SkPath triLeft;
    278     triLeft.moveTo(0, 0);
    279     triLeft.lineTo(SK_Scalar1, 0);
    280     triLeft.lineTo(SK_Scalar1, SK_Scalar1);
    281     triLeft.close();
    282     check_convexity(reporter, triLeft, SkPath::kConvex_Convexity);
    283 
    284     SkPath triRight;
    285     triRight.moveTo(0, 0);
    286     triRight.lineTo(-SK_Scalar1, 0);
    287     triRight.lineTo(SK_Scalar1, SK_Scalar1);
    288     triRight.close();
    289     check_convexity(reporter, triRight, SkPath::kConvex_Convexity);
    290 
    291     SkPath square;
    292     square.moveTo(0, 0);
    293     square.lineTo(SK_Scalar1, 0);
    294     square.lineTo(SK_Scalar1, SK_Scalar1);
    295     square.lineTo(0, SK_Scalar1);
    296     square.close();
    297     check_convexity(reporter, square, SkPath::kConvex_Convexity);
    298 
    299     SkPath redundantSquare;
    300     redundantSquare.moveTo(0, 0);
    301     redundantSquare.lineTo(0, 0);
    302     redundantSquare.lineTo(0, 0);
    303     redundantSquare.lineTo(SK_Scalar1, 0);
    304     redundantSquare.lineTo(SK_Scalar1, 0);
    305     redundantSquare.lineTo(SK_Scalar1, 0);
    306     redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
    307     redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
    308     redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
    309     redundantSquare.lineTo(0, SK_Scalar1);
    310     redundantSquare.lineTo(0, SK_Scalar1);
    311     redundantSquare.lineTo(0, SK_Scalar1);
    312     redundantSquare.close();
    313     check_convexity(reporter, redundantSquare, SkPath::kConvex_Convexity);
    314 
    315     SkPath bowTie;
    316     bowTie.moveTo(0, 0);
    317     bowTie.lineTo(0, 0);
    318     bowTie.lineTo(0, 0);
    319     bowTie.lineTo(SK_Scalar1, SK_Scalar1);
    320     bowTie.lineTo(SK_Scalar1, SK_Scalar1);
    321     bowTie.lineTo(SK_Scalar1, SK_Scalar1);
    322     bowTie.lineTo(SK_Scalar1, 0);
    323     bowTie.lineTo(SK_Scalar1, 0);
    324     bowTie.lineTo(SK_Scalar1, 0);
    325     bowTie.lineTo(0, SK_Scalar1);
    326     bowTie.lineTo(0, SK_Scalar1);
    327     bowTie.lineTo(0, SK_Scalar1);
    328     bowTie.close();
    329     check_convexity(reporter, bowTie, SkPath::kConcave_Convexity);
    330 
    331     SkPath spiral;
    332     spiral.moveTo(0, 0);
    333     spiral.lineTo(100*SK_Scalar1, 0);
    334     spiral.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
    335     spiral.lineTo(0, 100*SK_Scalar1);
    336     spiral.lineTo(0, 50*SK_Scalar1);
    337     spiral.lineTo(50*SK_Scalar1, 50*SK_Scalar1);
    338     spiral.lineTo(50*SK_Scalar1, 75*SK_Scalar1);
    339     spiral.close();
    340     check_convexity(reporter, spiral, SkPath::kConcave_Convexity);
    341 
    342     SkPath dent;
    343     dent.moveTo(0, 0);
    344     dent.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
    345     dent.lineTo(0, 100*SK_Scalar1);
    346     dent.lineTo(-50*SK_Scalar1, 200*SK_Scalar1);
    347     dent.lineTo(-200*SK_Scalar1, 100*SK_Scalar1);
    348     dent.close();
    349     check_convexity(reporter, dent, SkPath::kConcave_Convexity);
    350 }
    351 
    352 static void check_convex_bounds(skiatest::Reporter* reporter, const SkPath& p,
    353                                 const SkRect& bounds) {
    354     REPORTER_ASSERT(reporter, p.isConvex());
    355     REPORTER_ASSERT(reporter, p.getBounds() == bounds);
    356 
    357     SkPath p2(p);
    358     REPORTER_ASSERT(reporter, p2.isConvex());
    359     REPORTER_ASSERT(reporter, p2.getBounds() == bounds);
    360 
    361     SkPath other;
    362     other.swap(p2);
    363     REPORTER_ASSERT(reporter, other.isConvex());
    364     REPORTER_ASSERT(reporter, other.getBounds() == bounds);
    365 }
    366 
    367 static void setFromString(SkPath* path, const char str[]) {
    368     bool first = true;
    369     while (str) {
    370         SkScalar x, y;
    371         str = SkParse::FindScalar(str, &x);
    372         if (NULL == str) {
    373             break;
    374         }
    375         str = SkParse::FindScalar(str, &y);
    376         SkASSERT(str);
    377         if (first) {
    378             path->moveTo(x, y);
    379             first = false;
    380         } else {
    381             path->lineTo(x, y);
    382         }
    383     }
    384 }
    385 
    386 static void test_convexity(skiatest::Reporter* reporter) {
    387     static const SkPath::Convexity C = SkPath::kConcave_Convexity;
    388     static const SkPath::Convexity V = SkPath::kConvex_Convexity;
    389 
    390     SkPath path;
    391 
    392     REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
    393     path.addCircle(0, 0, SkIntToScalar(10));
    394     REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
    395     path.addCircle(0, 0, SkIntToScalar(10));   // 2nd circle
    396     REPORTER_ASSERT(reporter, C == SkPath::ComputeConvexity(path));
    397     path.reset();
    398     path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCCW_Direction);
    399     REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
    400     REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCCW_Direction));
    401     path.reset();
    402     path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCW_Direction);
    403     REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
    404     REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCW_Direction));
    405 
    406     static const struct {
    407         const char*         fPathStr;
    408         SkPath::Convexity   fExpectedConvexity;
    409     } gRec[] = {
    410         { "", SkPath::kConvex_Convexity },
    411         { "0 0", SkPath::kConvex_Convexity },
    412         { "0 0 10 10", SkPath::kConvex_Convexity },
    413         { "0 0 10 10 20 20 0 0 10 10", SkPath::kConcave_Convexity },
    414         { "0 0 10 10 10 20", SkPath::kConvex_Convexity },
    415         { "0 0 10 10 10 0", SkPath::kConvex_Convexity },
    416         { "0 0 10 10 10 0 0 10", SkPath::kConcave_Convexity },
    417         { "0 0 10 0 0 10 -10 -10", SkPath::kConcave_Convexity },
    418     };
    419 
    420     for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
    421         SkPath path;
    422         setFromString(&path, gRec[i].fPathStr);
    423         SkPath::Convexity c = SkPath::ComputeConvexity(path);
    424         REPORTER_ASSERT(reporter, c == gRec[i].fExpectedConvexity);
    425     }
    426 }
    427 
    428 // Simple isRect test is inline TestPath, below.
    429 // test_isRect provides more extensive testing.
    430 static void test_isRect(skiatest::Reporter* reporter) {
    431     // passing tests (all moveTo / lineTo...
    432     SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
    433     SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
    434     SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
    435     SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
    436     SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
    437     SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
    438     SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
    439     SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
    440     SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
    441     SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f},
    442         {1, 0}, {.5f, 0}};
    443     SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1},
    444         {0, 1}, {0, .5f}};
    445     SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}};
    446     SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
    447     SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}};
    448 
    449     // failing tests
    450     SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
    451     SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
    452     SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
    453     SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
    454     SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
    455     SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
    456     SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
    457     SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
    458 
    459     // failing, no close
    460     SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match
    461     SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto
    462 
    463     size_t testLen[] = {
    464         sizeof(r1), sizeof(r2), sizeof(r3), sizeof(r4), sizeof(r5), sizeof(r6),
    465         sizeof(r7), sizeof(r8), sizeof(r9), sizeof(ra), sizeof(rb), sizeof(rc),
    466         sizeof(rd), sizeof(re),
    467         sizeof(f1), sizeof(f2), sizeof(f3), sizeof(f4), sizeof(f5), sizeof(f6),
    468         sizeof(f7), sizeof(f8),
    469         sizeof(c1), sizeof(c2)
    470     };
    471     SkPoint* tests[] = {
    472         r1, r2, r3, r4, r5, r6, r7, r8, r9, ra, rb, rc, rd, re,
    473         f1, f2, f3, f4, f5, f6, f7, f8,
    474         c1, c2
    475     };
    476     SkPoint* lastPass = re;
    477     SkPoint* lastClose = f8;
    478     bool fail = false;
    479     bool close = true;
    480     const size_t testCount = sizeof(tests) / sizeof(tests[0]);
    481     size_t index;
    482     for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
    483         SkPath path;
    484         path.moveTo(tests[testIndex][0].fX, tests[testIndex][0].fY);
    485         for (index = 1; index < testLen[testIndex] / sizeof(SkPoint); ++index) {
    486             path.lineTo(tests[testIndex][index].fX, tests[testIndex][index].fY);
    487         }
    488         if (close) {
    489             path.close();
    490         }
    491         REPORTER_ASSERT(reporter, fail ^ path.isRect(0));
    492         if (tests[testIndex] == lastPass) {
    493             fail = true;
    494         }
    495         if (tests[testIndex] == lastClose) {
    496             close = false;
    497         }
    498     }
    499 
    500     // fail, close then line
    501     SkPath path1;
    502     path1.moveTo(r1[0].fX, r1[0].fY);
    503     for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
    504         path1.lineTo(r1[index].fX, r1[index].fY);
    505     }
    506     path1.close();
    507     path1.lineTo(1, 0);
    508     REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
    509 
    510     // fail, move in the middle
    511     path1.reset();
    512     path1.moveTo(r1[0].fX, r1[0].fY);
    513     for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
    514         if (index == 2) {
    515             path1.moveTo(1, .5f);
    516         }
    517         path1.lineTo(r1[index].fX, r1[index].fY);
    518     }
    519     path1.close();
    520     REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
    521 
    522     // fail, move on the edge
    523     path1.reset();
    524     for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
    525         path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
    526         path1.lineTo(r1[index].fX, r1[index].fY);
    527     }
    528     path1.close();
    529     REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
    530 
    531     // fail, quad
    532     path1.reset();
    533     path1.moveTo(r1[0].fX, r1[0].fY);
    534     for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
    535         if (index == 2) {
    536             path1.quadTo(1, .5f, 1, .5f);
    537         }
    538         path1.lineTo(r1[index].fX, r1[index].fY);
    539     }
    540     path1.close();
    541     REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
    542 
    543     // fail, cubic
    544     path1.reset();
    545     path1.moveTo(r1[0].fX, r1[0].fY);
    546     for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
    547         if (index == 2) {
    548             path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
    549         }
    550         path1.lineTo(r1[index].fX, r1[index].fY);
    551     }
    552     path1.close();
    553     REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
    554 }
    555 
    556 static void test_flattening(skiatest::Reporter* reporter) {
    557     SkPath p;
    558 
    559     static const SkPoint pts[] = {
    560         { 0, 0 },
    561         { SkIntToScalar(10), SkIntToScalar(10) },
    562         { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
    563         { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
    564     };
    565     p.moveTo(pts[0]);
    566     p.lineTo(pts[1]);
    567     p.quadTo(pts[2], pts[3]);
    568     p.cubicTo(pts[4], pts[5], pts[6]);
    569 
    570     SkWriter32 writer(100);
    571     p.flatten(writer);
    572     size_t size = writer.size();
    573     SkAutoMalloc storage(size);
    574     writer.flatten(storage.get());
    575     SkReader32 reader(storage.get(), size);
    576 
    577     SkPath p1;
    578     REPORTER_ASSERT(reporter, p1 != p);
    579     p1.unflatten(reader);
    580     REPORTER_ASSERT(reporter, p1 == p);
    581 }
    582 
    583 static void test_transform(skiatest::Reporter* reporter) {
    584     SkPath p, p1;
    585 
    586     static const SkPoint pts[] = {
    587         { 0, 0 },
    588         { SkIntToScalar(10), SkIntToScalar(10) },
    589         { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
    590         { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
    591     };
    592     p.moveTo(pts[0]);
    593     p.lineTo(pts[1]);
    594     p.quadTo(pts[2], pts[3]);
    595     p.cubicTo(pts[4], pts[5], pts[6]);
    596 
    597     SkMatrix matrix;
    598     matrix.reset();
    599     p.transform(matrix, &p1);
    600     REPORTER_ASSERT(reporter, p == p1);
    601 
    602     matrix.setScale(SK_Scalar1 * 2, SK_Scalar1 * 3);
    603     p.transform(matrix, &p1);
    604     SkPoint pts1[7];
    605     int count = p1.getPoints(pts1, 7);
    606     REPORTER_ASSERT(reporter, 7 == count);
    607     for (int i = 0; i < count; ++i) {
    608         SkPoint newPt = SkPoint::Make(pts[i].fX * 2, pts[i].fY * 3);
    609         REPORTER_ASSERT(reporter, newPt == pts1[i]);
    610     }
    611 }
    612 
    613 static void test_zero_length_paths(skiatest::Reporter* reporter) {
    614     SkPath  p;
    615     SkPoint pt;
    616     SkRect  bounds;
    617 
    618     // Lone moveTo case
    619     p.moveTo(SK_Scalar1, SK_Scalar1);
    620     REPORTER_ASSERT(reporter, !p.isEmpty());
    621     REPORTER_ASSERT(reporter, 1 == p.countPoints());
    622     p.getLastPt(&pt);
    623     REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1);
    624     REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
    625     bounds.set(0, 0, 0, 0);
    626     REPORTER_ASSERT(reporter, bounds == p.getBounds());
    627 
    628     // MoveTo-MoveTo case
    629     p.moveTo(SK_Scalar1*2, SK_Scalar1);
    630     REPORTER_ASSERT(reporter, !p.isEmpty());
    631     REPORTER_ASSERT(reporter, 2 == p.countPoints());
    632     p.getLastPt(&pt);
    633     REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1*2);
    634     REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
    635     bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
    636     REPORTER_ASSERT(reporter, bounds == p.getBounds());
    637 
    638     // moveTo-close case
    639     p.reset();
    640     p.moveTo(SK_Scalar1, SK_Scalar1);
    641     p.close();
    642     bounds.set(0, 0, 0, 0);
    643     REPORTER_ASSERT(reporter, !p.isEmpty());
    644     REPORTER_ASSERT(reporter, 1 == p.countPoints());
    645     REPORTER_ASSERT(reporter, bounds == p.getBounds());
    646 
    647     // moveTo-close-moveTo-close case
    648     p.moveTo(SK_Scalar1*2, SK_Scalar1);
    649     p.close();
    650     bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
    651     REPORTER_ASSERT(reporter, !p.isEmpty());
    652     REPORTER_ASSERT(reporter, 2 == p.countPoints());
    653     REPORTER_ASSERT(reporter, bounds == p.getBounds());
    654 
    655     // moveTo-line case
    656     p.reset();
    657     p.moveTo(SK_Scalar1, SK_Scalar1);
    658     p.lineTo(SK_Scalar1, SK_Scalar1);
    659     bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
    660     REPORTER_ASSERT(reporter, !p.isEmpty());
    661     REPORTER_ASSERT(reporter, 2 == p.countPoints());
    662     REPORTER_ASSERT(reporter, bounds == p.getBounds());
    663 
    664     // moveTo-lineTo-moveTo-lineTo case
    665     p.moveTo(SK_Scalar1*2, SK_Scalar1);
    666     p.lineTo(SK_Scalar1*2, SK_Scalar1);
    667     bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
    668     REPORTER_ASSERT(reporter, !p.isEmpty());
    669     REPORTER_ASSERT(reporter, 4 == p.countPoints());
    670     REPORTER_ASSERT(reporter, bounds == p.getBounds());
    671 
    672     // moveTo-line-close case
    673     p.reset();
    674     p.moveTo(SK_Scalar1, SK_Scalar1);
    675     p.lineTo(SK_Scalar1, SK_Scalar1);
    676     p.close();
    677     bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
    678     REPORTER_ASSERT(reporter, !p.isEmpty());
    679     REPORTER_ASSERT(reporter, 2 == p.countPoints());
    680     REPORTER_ASSERT(reporter, bounds == p.getBounds());
    681 
    682     // moveTo-line-close-moveTo-line-close case
    683     p.moveTo(SK_Scalar1*2, SK_Scalar1);
    684     p.lineTo(SK_Scalar1*2, SK_Scalar1);
    685     p.close();
    686     bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
    687     REPORTER_ASSERT(reporter, !p.isEmpty());
    688     REPORTER_ASSERT(reporter, 4 == p.countPoints());
    689     REPORTER_ASSERT(reporter, bounds == p.getBounds());
    690 
    691     // moveTo-quadTo case
    692     p.reset();
    693     p.moveTo(SK_Scalar1, SK_Scalar1);
    694     p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
    695     bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
    696     REPORTER_ASSERT(reporter, !p.isEmpty());
    697     REPORTER_ASSERT(reporter, 3 == p.countPoints());
    698     REPORTER_ASSERT(reporter, bounds == p.getBounds());
    699 
    700     // moveTo-quadTo-close case
    701     p.close();
    702     REPORTER_ASSERT(reporter, !p.isEmpty());
    703     REPORTER_ASSERT(reporter, 3 == p.countPoints());
    704     REPORTER_ASSERT(reporter, bounds == p.getBounds());
    705 
    706     // moveTo-quadTo-moveTo-quadTo case
    707     p.reset();
    708     p.moveTo(SK_Scalar1, SK_Scalar1);
    709     p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
    710     p.moveTo(SK_Scalar1*2, SK_Scalar1);
    711     p.quadTo(SK_Scalar1*2, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
    712     bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
    713     REPORTER_ASSERT(reporter, !p.isEmpty());
    714     REPORTER_ASSERT(reporter, 6 == p.countPoints());
    715     REPORTER_ASSERT(reporter, bounds == p.getBounds());
    716 
    717     // moveTo-cubicTo case
    718     p.reset();
    719     p.moveTo(SK_Scalar1, SK_Scalar1);
    720     p.cubicTo(SK_Scalar1, SK_Scalar1,
    721               SK_Scalar1, SK_Scalar1,
    722               SK_Scalar1, SK_Scalar1);
    723     bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
    724     REPORTER_ASSERT(reporter, !p.isEmpty());
    725     REPORTER_ASSERT(reporter, 4 == p.countPoints());
    726     REPORTER_ASSERT(reporter, bounds == p.getBounds());
    727 
    728     // moveTo-quadTo-close case
    729     p.close();
    730     REPORTER_ASSERT(reporter, !p.isEmpty());
    731     REPORTER_ASSERT(reporter, 4 == p.countPoints());
    732     REPORTER_ASSERT(reporter, bounds == p.getBounds());
    733 
    734     // moveTo-quadTo-moveTo-quadTo case
    735     p.reset();
    736     p.moveTo(SK_Scalar1, SK_Scalar1);
    737     p.cubicTo(SK_Scalar1, SK_Scalar1,
    738               SK_Scalar1, SK_Scalar1,
    739               SK_Scalar1, SK_Scalar1);
    740     p.moveTo(SK_Scalar1*2, SK_Scalar1);
    741     p.cubicTo(SK_Scalar1*2, SK_Scalar1,
    742               SK_Scalar1*2, SK_Scalar1,
    743               SK_Scalar1*2, SK_Scalar1);
    744     bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
    745     REPORTER_ASSERT(reporter, !p.isEmpty());
    746     REPORTER_ASSERT(reporter, 8 == p.countPoints());
    747     REPORTER_ASSERT(reporter, bounds == p.getBounds());
    748 }
    749 
    750 struct SegmentInfo {
    751     SkPath fPath;
    752     int    fPointCount;
    753 };
    754 
    755 #define kCurveSegmentMask   (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)
    756 
    757 static void test_segment_masks(skiatest::Reporter* reporter) {
    758     SkPath p;
    759     p.moveTo(0, 0);
    760     p.quadTo(100, 100, 200, 200);
    761     REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == p.getSegmentMasks());
    762     REPORTER_ASSERT(reporter, !p.isEmpty());
    763     p.cubicTo(100, 100, 200, 200, 300, 300);
    764     REPORTER_ASSERT(reporter, kCurveSegmentMask == p.getSegmentMasks());
    765     REPORTER_ASSERT(reporter, !p.isEmpty());
    766     p.reset();
    767     p.moveTo(0, 0);
    768     p.cubicTo(100, 100, 200, 200, 300, 300);
    769     REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == p.getSegmentMasks());
    770     REPORTER_ASSERT(reporter, !p.isEmpty());
    771 }
    772 
    773 static void test_iter(skiatest::Reporter* reporter) {
    774     SkPath p;
    775     SkPoint pts[4];
    776 
    777     // Test an iterator with no path
    778     SkPath::Iter noPathIter;
    779     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
    780     // Test that setting an empty path works
    781     noPathIter.setPath(p, false);
    782     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
    783     // Test that close path makes no difference for an empty path
    784     noPathIter.setPath(p, true);
    785     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
    786 
    787     // Test an iterator with an initial empty path
    788     SkPath::Iter iter(p, false);
    789     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
    790 
    791     // Test that close path makes no difference
    792     SkPath::Iter forceCloseIter(p, true);
    793     REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
    794 
    795     // Test that a move-only path produces nothing when iterated.
    796     p.moveTo(SK_Scalar1, 0);
    797     iter.setPath(p, false);
    798     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
    799 
    800     // No matter how many moves we add, we should still get nothing back.
    801     p.moveTo(SK_Scalar1*2, 0);
    802     p.moveTo(SK_Scalar1*3, 0);
    803     p.moveTo(SK_Scalar1*4, 0);
    804     p.moveTo(SK_Scalar1*5, 0);
    805     iter.setPath(p, false);
    806     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
    807 
    808     // Nor should force closing
    809     forceCloseIter.setPath(p, true);
    810     REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
    811 
    812     // Initial closes should be ignored
    813     p.reset();
    814     p.close();
    815     iter.setPath(p, false);
    816     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
    817     // Even if force closed
    818     forceCloseIter.setPath(p, true);
    819     REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
    820 
    821     // Move/close sequences should also be ignored
    822     p.reset();
    823     p.close();
    824     p.moveTo(SK_Scalar1, 0);
    825     p.close();
    826     p.close();
    827     p.moveTo(SK_Scalar1*2, 0);
    828     p.close();
    829     p.moveTo(SK_Scalar1*3, 0);
    830     p.moveTo(SK_Scalar1*4, 0);
    831     p.close();
    832     iter.setPath(p, false);
    833     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
    834     // Even if force closed
    835     forceCloseIter.setPath(p, true);
    836     REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
    837 
    838     // The GM degeneratesegments.cpp test is more extensive
    839 }
    840 
    841 static void test_raw_iter(skiatest::Reporter* reporter) {
    842     SkPath p;
    843     SkPoint pts[4];
    844 
    845     // Test an iterator with no path
    846     SkPath::RawIter noPathIter;
    847     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
    848     // Test that setting an empty path works
    849     noPathIter.setPath(p);
    850     REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
    851 
    852     // Test an iterator with an initial empty path
    853     SkPath::RawIter iter(p);
    854     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
    855 
    856     // Test that a move-only path returns the move.
    857     p.moveTo(SK_Scalar1, 0);
    858     iter.setPath(p);
    859     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
    860     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
    861     REPORTER_ASSERT(reporter, pts[0].fY == 0);
    862     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
    863 
    864     // No matter how many moves we add, we should get them all back
    865     p.moveTo(SK_Scalar1*2, SK_Scalar1);
    866     p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
    867     iter.setPath(p);
    868     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
    869     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
    870     REPORTER_ASSERT(reporter, pts[0].fY == 0);
    871     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
    872     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
    873     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
    874     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
    875     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
    876     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
    877     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
    878 
    879     // Initial close is never ever stored
    880     p.reset();
    881     p.close();
    882     iter.setPath(p);
    883     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
    884 
    885     // Move/close sequences
    886     p.reset();
    887     p.close(); // Not stored, no purpose
    888     p.moveTo(SK_Scalar1, 0);
    889     p.close();
    890     p.close(); // Not stored, no purpose
    891     p.moveTo(SK_Scalar1*2, SK_Scalar1);
    892     p.close();
    893     p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
    894     p.moveTo(SK_Scalar1*4, SK_Scalar1*3);
    895     p.close();
    896     iter.setPath(p);
    897     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
    898     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
    899     REPORTER_ASSERT(reporter, pts[0].fY == 0);
    900     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
    901     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
    902     REPORTER_ASSERT(reporter, pts[0].fY == 0);
    903     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
    904     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
    905     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
    906     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
    907     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
    908     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
    909     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
    910     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
    911     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
    912     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
    913     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
    914     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
    915     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
    916     REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
    917     REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
    918     REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
    919 
    920     // Generate random paths and verify
    921     SkPoint randomPts[25];
    922     for (int i = 0; i < 5; ++i) {
    923         for (int j = 0; j < 5; ++j) {
    924             randomPts[i*5+j].set(SK_Scalar1*i, SK_Scalar1*j);
    925         }
    926     }
    927 
    928     // Max of 10 segments, max 3 points per segment
    929     SkRandom rand(9876543);
    930     SkPoint          expectedPts[31]; // May have leading moveTo
    931     SkPath::Verb     expectedVerbs[22]; // May have leading moveTo
    932     SkPath::Verb     nextVerb;
    933 
    934     for (int i = 0; i < 500; ++i) {
    935         p.reset();
    936         bool lastWasClose = true;
    937         bool haveMoveTo = false;
    938         SkPoint lastMoveToPt = { 0, 0 };
    939         int numPoints = 0;
    940         int numVerbs = (rand.nextU() >> 16) % 10;
    941         int numIterVerbs = 0;
    942         for (int j = 0; j < numVerbs; ++j) {
    943             do {
    944                 nextVerb = static_cast<SkPath::Verb>((rand.nextU() >> 16) % SkPath::kDone_Verb);
    945             } while (lastWasClose && nextVerb == SkPath::kClose_Verb);
    946             int numRequiredPts;
    947             switch (nextVerb) {
    948                 case SkPath::kMove_Verb:
    949                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
    950                     p.moveTo(expectedPts[numPoints]);
    951                     lastMoveToPt = expectedPts[numPoints];
    952                     numPoints += 1;
    953                     lastWasClose = false;
    954                     haveMoveTo = true;
    955                     break;
    956                 case SkPath::kLine_Verb:
    957                     if (!haveMoveTo) {
    958                         expectedPts[numPoints++] = lastMoveToPt;
    959                         expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
    960                         haveMoveTo = true;
    961                     }
    962                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
    963                     p.lineTo(expectedPts[numPoints]);
    964                     numPoints += 1;
    965                     lastWasClose = false;
    966                     break;
    967                 case SkPath::kQuad_Verb:
    968                     if (!haveMoveTo) {
    969                         expectedPts[numPoints++] = lastMoveToPt;
    970                         expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
    971                         haveMoveTo = true;
    972                     }
    973                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
    974                     expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
    975                     p.quadTo(expectedPts[numPoints], expectedPts[numPoints + 1]);
    976                     numPoints += 2;
    977                     lastWasClose = false;
    978                     break;
    979                 case SkPath::kCubic_Verb:
    980                     if (!haveMoveTo) {
    981                         expectedPts[numPoints++] = lastMoveToPt;
    982                         expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
    983                         haveMoveTo = true;
    984                     }
    985                     expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
    986                     expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
    987                     expectedPts[numPoints + 2] = randomPts[(rand.nextU() >> 16) % 25];
    988                     p.cubicTo(expectedPts[numPoints], expectedPts[numPoints + 1],
    989                               expectedPts[numPoints + 2]);
    990                     numPoints += 3;
    991                     lastWasClose = false;
    992                     break;
    993                 case SkPath::kClose_Verb:
    994                     p.close();
    995                     haveMoveTo = false;
    996                     lastWasClose = true;
    997                     break;
    998                 default:;
    999             }
   1000             expectedVerbs[numIterVerbs++] = nextVerb;
   1001         }
   1002 
   1003         iter.setPath(p);
   1004         numVerbs = numIterVerbs;
   1005         numIterVerbs = 0;
   1006         int numIterPts = 0;
   1007         SkPoint lastMoveTo;
   1008         SkPoint lastPt;
   1009         lastMoveTo.set(0, 0);
   1010         lastPt.set(0, 0);
   1011         while ((nextVerb = iter.next(pts)) != SkPath::kDone_Verb) {
   1012             REPORTER_ASSERT(reporter, nextVerb == expectedVerbs[numIterVerbs]);
   1013             numIterVerbs++;
   1014             switch (nextVerb) {
   1015                 case SkPath::kMove_Verb:
   1016                     REPORTER_ASSERT(reporter, numIterPts < numPoints);
   1017                     REPORTER_ASSERT(reporter, pts[0] == expectedPts[numIterPts]);
   1018                     lastPt = lastMoveTo = pts[0];
   1019                     numIterPts += 1;
   1020                     break;
   1021                 case SkPath::kLine_Verb:
   1022                     REPORTER_ASSERT(reporter, numIterPts < numPoints + 1);
   1023                     REPORTER_ASSERT(reporter, pts[0] == lastPt);
   1024                     REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
   1025                     lastPt = pts[1];
   1026                     numIterPts += 1;
   1027                     break;
   1028                 case SkPath::kQuad_Verb:
   1029                     REPORTER_ASSERT(reporter, numIterPts < numPoints + 2);
   1030                     REPORTER_ASSERT(reporter, pts[0] == lastPt);
   1031                     REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
   1032                     REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
   1033                     lastPt = pts[2];
   1034                     numIterPts += 2;
   1035                     break;
   1036                 case SkPath::kCubic_Verb:
   1037                     REPORTER_ASSERT(reporter, numIterPts < numPoints + 3);
   1038                     REPORTER_ASSERT(reporter, pts[0] == lastPt);
   1039                     REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
   1040                     REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
   1041                     REPORTER_ASSERT(reporter, pts[3] == expectedPts[numIterPts + 2]);
   1042                     lastPt = pts[3];
   1043                     numIterPts += 3;
   1044                     break;
   1045                 case SkPath::kClose_Verb:
   1046                     REPORTER_ASSERT(reporter, pts[0] == lastMoveTo);
   1047                     lastPt = lastMoveTo;
   1048                     break;
   1049                 default:;
   1050             }
   1051         }
   1052         REPORTER_ASSERT(reporter, numIterPts == numPoints);
   1053         REPORTER_ASSERT(reporter, numIterVerbs == numVerbs);
   1054     }
   1055 }
   1056 
   1057 void TestPath(skiatest::Reporter* reporter);
   1058 void TestPath(skiatest::Reporter* reporter) {
   1059     {
   1060         SkSize size;
   1061         size.fWidth = 3.4f;
   1062         size.width();
   1063         size = SkSize::Make(3,4);
   1064         SkISize isize = SkISize::Make(3,4);
   1065     }
   1066 
   1067     SkTSize<SkScalar>::Make(3,4);
   1068 
   1069     SkPath  p, p2;
   1070     SkRect  bounds, bounds2;
   1071 
   1072     REPORTER_ASSERT(reporter, p.isEmpty());
   1073     REPORTER_ASSERT(reporter, 0 == p.countPoints());
   1074     REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
   1075     REPORTER_ASSERT(reporter, p.isConvex());
   1076     REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType);
   1077     REPORTER_ASSERT(reporter, !p.isInverseFillType());
   1078     REPORTER_ASSERT(reporter, p == p2);
   1079     REPORTER_ASSERT(reporter, !(p != p2));
   1080 
   1081     REPORTER_ASSERT(reporter, p.getBounds().isEmpty());
   1082 
   1083     bounds.set(0, 0, SK_Scalar1, SK_Scalar1);
   1084 
   1085     p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1);
   1086     check_convex_bounds(reporter, p, bounds);
   1087     // we have quads or cubics
   1088     REPORTER_ASSERT(reporter, p.getSegmentMasks() & kCurveSegmentMask);
   1089     REPORTER_ASSERT(reporter, !p.isEmpty());
   1090 
   1091     p.reset();
   1092     REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
   1093     REPORTER_ASSERT(reporter, p.isEmpty());
   1094 
   1095     p.addOval(bounds);
   1096     check_convex_bounds(reporter, p, bounds);
   1097     REPORTER_ASSERT(reporter, !p.isEmpty());
   1098 
   1099     p.reset();
   1100     p.addRect(bounds);
   1101     check_convex_bounds(reporter, p, bounds);
   1102     // we have only lines
   1103     REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == p.getSegmentMasks());
   1104     REPORTER_ASSERT(reporter, !p.isEmpty());
   1105 
   1106     REPORTER_ASSERT(reporter, p != p2);
   1107     REPORTER_ASSERT(reporter, !(p == p2));
   1108 
   1109     // does getPoints return the right result
   1110     REPORTER_ASSERT(reporter, p.getPoints(NULL, 5) == 4);
   1111     SkPoint pts[4];
   1112     int count = p.getPoints(pts, 4);
   1113     REPORTER_ASSERT(reporter, count == 4);
   1114     bounds2.set(pts, 4);
   1115     REPORTER_ASSERT(reporter, bounds == bounds2);
   1116 
   1117     bounds.offset(SK_Scalar1*3, SK_Scalar1*4);
   1118     p.offset(SK_Scalar1*3, SK_Scalar1*4);
   1119     REPORTER_ASSERT(reporter, bounds == p.getBounds());
   1120 
   1121     REPORTER_ASSERT(reporter, p.isRect(NULL));
   1122     bounds2.setEmpty();
   1123     REPORTER_ASSERT(reporter, p.isRect(&bounds2));
   1124     REPORTER_ASSERT(reporter, bounds == bounds2);
   1125 
   1126     // now force p to not be a rect
   1127     bounds.set(0, 0, SK_Scalar1/2, SK_Scalar1/2);
   1128     p.addRect(bounds);
   1129     REPORTER_ASSERT(reporter, !p.isRect(NULL));
   1130     test_isRect(reporter);
   1131 
   1132     test_zero_length_paths(reporter);
   1133     test_direction(reporter);
   1134     test_convexity(reporter);
   1135     test_convexity2(reporter);
   1136     test_close(reporter);
   1137     test_segment_masks(reporter);
   1138     test_flattening(reporter);
   1139     test_transform(reporter);
   1140     test_bounds(reporter);
   1141     test_iter(reporter);
   1142     test_raw_iter(reporter);
   1143 }
   1144 
   1145 #include "TestClassDef.h"
   1146 DEFINE_TESTCLASS("Path", PathTestClass, TestPath)
   1147