Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkMatrix.h"
      9 #include "SkPointPriv.h"
     10 #include "SkRRect.h"
     11 #include "Test.h"
     12 
     13 static void test_tricky_radii(skiatest::Reporter* reporter) {
     14     {
     15         // crbug.com/458522
     16         SkRRect rr;
     17         const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 };
     18         const SkScalar rad = 12814;
     19         const SkVector vec[] = { { rad, rad }, { 0, rad }, { rad, rad }, { 0, rad } };
     20         rr.setRectRadii(bounds, vec);
     21     }
     22 
     23     {
     24         // crbug.com//463920
     25         SkRect r = SkRect::MakeLTRB(0, 0, 1009, 33554432.0);
     26         SkVector radii[4] = {
     27             { 13.0f, 8.0f }, { 170.0f, 2.0 }, { 256.0f, 33554432.0 }, { 110.0f, 5.0f }
     28         };
     29         SkRRect rr;
     30         rr.setRectRadii(r, radii);
     31 
     32         REPORTER_ASSERT(reporter, (double) rr.radii(SkRRect::kUpperRight_Corner).fY +
     33                                   (double) rr.radii(SkRRect::kLowerRight_Corner).fY <=
     34                                   rr.height());
     35     }
     36 }
     37 
     38 static void test_empty_crbug_458524(skiatest::Reporter* reporter) {
     39     SkRRect rr;
     40     const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 };
     41     const SkScalar rad = 40;
     42     rr.setRectXY(bounds, rad, rad);
     43 
     44     SkRRect other;
     45     SkMatrix matrix;
     46     matrix.setScale(0, 1);
     47     rr.transform(matrix, &other);
     48     REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == other.getType());
     49 }
     50 
     51 // Test that all the SkRRect entry points correctly handle un-sorted and
     52 // zero-sized input rects
     53 static void test_empty(skiatest::Reporter* reporter) {
     54     static const SkRect oooRects[] = {  // out of order
     55         { 100, 0, 0, 100 },  // ooo horizontal
     56         { 0, 100, 100, 0 },  // ooo vertical
     57         { 100, 100, 0, 0 },  // ooo both
     58     };
     59 
     60     static const SkRect emptyRects[] = {
     61         { 100, 100, 100, 200 }, // empty horizontal
     62         { 100, 100, 200, 100 }, // empty vertical
     63         { 100, 100, 100, 100 }, // empty both
     64         { 0, 0, 0, 0 }          // setEmpty-empty
     65     };
     66 
     67     static const SkVector radii[4] = { { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 } };
     68 
     69     SkRRect r;
     70 
     71     for (size_t i = 0; i < SK_ARRAY_COUNT(oooRects); ++i) {
     72         r.setRect(oooRects[i]);
     73         REPORTER_ASSERT(reporter, !r.isEmpty());
     74         REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
     75 
     76         r.setOval(oooRects[i]);
     77         REPORTER_ASSERT(reporter, !r.isEmpty());
     78         REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
     79 
     80         r.setRectXY(oooRects[i], 1, 2);
     81         REPORTER_ASSERT(reporter, !r.isEmpty());
     82         REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
     83 
     84         r.setNinePatch(oooRects[i], 0, 1, 2, 3);
     85         REPORTER_ASSERT(reporter, !r.isEmpty());
     86         REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
     87 
     88         r.setRectRadii(oooRects[i], radii);
     89         REPORTER_ASSERT(reporter, !r.isEmpty());
     90         REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
     91     }
     92 
     93     for (size_t i = 0; i < SK_ARRAY_COUNT(emptyRects); ++i) {
     94         r.setRect(emptyRects[i]);
     95         REPORTER_ASSERT(reporter, r.isEmpty());
     96         REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
     97 
     98         r.setOval(emptyRects[i]);
     99         REPORTER_ASSERT(reporter, r.isEmpty());
    100         REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
    101 
    102         r.setRectXY(emptyRects[i], 1, 2);
    103         REPORTER_ASSERT(reporter, r.isEmpty());
    104         REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
    105 
    106         r.setNinePatch(emptyRects[i], 0, 1, 2, 3);
    107         REPORTER_ASSERT(reporter, r.isEmpty());
    108         REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
    109 
    110         r.setRectRadii(emptyRects[i], radii);
    111         REPORTER_ASSERT(reporter, r.isEmpty());
    112         REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
    113     }
    114 
    115     r.setRect({SK_ScalarNaN, 10, 10, 20});
    116     REPORTER_ASSERT(reporter, r == SkRRect::MakeEmpty());
    117     r.setRect({0, 10, 10, SK_ScalarInfinity});
    118     REPORTER_ASSERT(reporter, r == SkRRect::MakeEmpty());
    119 }
    120 
    121 static const SkScalar kWidth = 100.0f;
    122 static const SkScalar kHeight = 100.0f;
    123 
    124 static void test_inset(skiatest::Reporter* reporter) {
    125     SkRRect rr, rr2;
    126     SkRect r = { 0, 0, 100, 100 };
    127 
    128     rr.setRect(r);
    129     rr.inset(-20, -20, &rr2);
    130     REPORTER_ASSERT(reporter, rr2.isRect());
    131 
    132     rr.inset(20, 20, &rr2);
    133     REPORTER_ASSERT(reporter, rr2.isRect());
    134 
    135     rr.inset(r.width()/2, r.height()/2, &rr2);
    136     REPORTER_ASSERT(reporter, rr2.isEmpty());
    137 
    138     rr.setRectXY(r, 20, 20);
    139     rr.inset(19, 19, &rr2);
    140     REPORTER_ASSERT(reporter, rr2.isSimple());
    141     rr.inset(20, 20, &rr2);
    142     REPORTER_ASSERT(reporter, rr2.isRect());
    143 }
    144 
    145 
    146 static void test_9patch_rrect(skiatest::Reporter* reporter,
    147                               const SkRect& rect,
    148                               SkScalar l, SkScalar t, SkScalar r, SkScalar b,
    149                               bool checkRadii) {
    150     SkRRect rr;
    151     rr.setNinePatch(rect, l, t, r, b);
    152 
    153     REPORTER_ASSERT(reporter, SkRRect::kNinePatch_Type == rr.type());
    154     REPORTER_ASSERT(reporter, rr.rect() == rect);
    155 
    156     if (checkRadii) {
    157         // This test doesn't hold if the radii will be rescaled by SkRRect
    158         SkRect ninePatchRadii = { l, t, r, b };
    159         SkPoint rquad[4];
    160         ninePatchRadii.toQuad(rquad);
    161         for (int i = 0; i < 4; ++i) {
    162             REPORTER_ASSERT(reporter, rquad[i] == rr.radii((SkRRect::Corner) i));
    163         }
    164     }
    165     SkRRect rr2; // construct the same RR using the most general set function
    166     SkVector radii[4] = { { l, t }, { r, t }, { r, b }, { l, b } };
    167     rr2.setRectRadii(rect, radii);
    168     REPORTER_ASSERT(reporter, rr2 == rr && rr2.getType() == rr.getType());
    169 }
    170 
    171 // Test out the basic API entry points
    172 static void test_round_rect_basic(skiatest::Reporter* reporter) {
    173     // Test out initialization methods
    174     SkPoint zeroPt = { 0, 0 };
    175     SkRRect empty;
    176 
    177     empty.setEmpty();
    178 
    179     REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
    180     REPORTER_ASSERT(reporter, empty.rect().isEmpty());
    181 
    182     for (int i = 0; i < 4; ++i) {
    183         REPORTER_ASSERT(reporter, zeroPt == empty.radii((SkRRect::Corner) i));
    184     }
    185 
    186     //----
    187     SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
    188 
    189     SkRRect rr1;
    190     rr1.setRect(rect);
    191 
    192     REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
    193     REPORTER_ASSERT(reporter, rr1.rect() == rect);
    194 
    195     for (int i = 0; i < 4; ++i) {
    196         REPORTER_ASSERT(reporter, zeroPt == rr1.radii((SkRRect::Corner) i));
    197     }
    198     SkRRect rr1_2; // construct the same RR using the most general set function
    199     SkVector rr1_2_radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
    200     rr1_2.setRectRadii(rect, rr1_2_radii);
    201     REPORTER_ASSERT(reporter, rr1_2 == rr1 && rr1_2.getType() == rr1.getType());
    202     SkRRect rr1_3;  // construct the same RR using the nine patch set function
    203     rr1_3.setNinePatch(rect, 0, 0, 0, 0);
    204     REPORTER_ASSERT(reporter, rr1_3 == rr1 && rr1_3.getType() == rr1.getType());
    205 
    206     //----
    207     SkPoint halfPoint = { SkScalarHalf(kWidth), SkScalarHalf(kHeight) };
    208     SkRRect rr2;
    209     rr2.setOval(rect);
    210 
    211     REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr2.type());
    212     REPORTER_ASSERT(reporter, rr2.rect() == rect);
    213 
    214     for (int i = 0; i < 4; ++i) {
    215         REPORTER_ASSERT(reporter,
    216                         SkPointPriv::EqualsWithinTolerance(rr2.radii((SkRRect::Corner) i),
    217                         halfPoint));
    218     }
    219     SkRRect rr2_2;  // construct the same RR using the most general set function
    220     SkVector rr2_2_radii[4] = { { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY },
    221                                 { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY } };
    222     rr2_2.setRectRadii(rect, rr2_2_radii);
    223     REPORTER_ASSERT(reporter, rr2_2 == rr2 && rr2_2.getType() == rr2.getType());
    224     SkRRect rr2_3;  // construct the same RR using the nine patch set function
    225     rr2_3.setNinePatch(rect, halfPoint.fX, halfPoint.fY, halfPoint.fX, halfPoint.fY);
    226     REPORTER_ASSERT(reporter, rr2_3 == rr2 && rr2_3.getType() == rr2.getType());
    227 
    228     //----
    229     SkPoint p = { 5, 5 };
    230     SkRRect rr3;
    231     rr3.setRectXY(rect, p.fX, p.fY);
    232 
    233     REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr3.type());
    234     REPORTER_ASSERT(reporter, rr3.rect() == rect);
    235 
    236     for (int i = 0; i < 4; ++i) {
    237         REPORTER_ASSERT(reporter, p == rr3.radii((SkRRect::Corner) i));
    238     }
    239     SkRRect rr3_2; // construct the same RR using the most general set function
    240     SkVector rr3_2_radii[4] = { { 5, 5 }, { 5, 5 }, { 5, 5 }, { 5, 5 } };
    241     rr3_2.setRectRadii(rect, rr3_2_radii);
    242     REPORTER_ASSERT(reporter, rr3_2 == rr3 && rr3_2.getType() == rr3.getType());
    243     SkRRect rr3_3;  // construct the same RR using the nine patch set function
    244     rr3_3.setNinePatch(rect, 5, 5, 5, 5);
    245     REPORTER_ASSERT(reporter, rr3_3 == rr3 && rr3_3.getType() == rr3.getType());
    246 
    247     //----
    248     test_9patch_rrect(reporter, rect, 10, 9, 8, 7, true);
    249 
    250     {
    251         // Test out the rrect from skia:3466
    252         SkRect rect2 = SkRect::MakeLTRB(0.358211994f, 0.755430222f, 0.872866154f, 0.806214333f);
    253 
    254         test_9patch_rrect(reporter,
    255                           rect2,
    256                           0.926942348f, 0.642850280f, 0.529063463f, 0.587844372f,
    257                           false);
    258     }
    259 
    260     //----
    261     SkPoint radii2[4] = { { 0, 0 }, { 0, 0 }, { 50, 50 }, { 20, 50 } };
    262 
    263     SkRRect rr5;
    264     rr5.setRectRadii(rect, radii2);
    265 
    266     REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr5.type());
    267     REPORTER_ASSERT(reporter, rr5.rect() == rect);
    268 
    269     for (int i = 0; i < 4; ++i) {
    270         REPORTER_ASSERT(reporter, radii2[i] == rr5.radii((SkRRect::Corner) i));
    271     }
    272 
    273     // Test out == & !=
    274     REPORTER_ASSERT(reporter, empty != rr3);
    275     REPORTER_ASSERT(reporter, rr3 != rr5);
    276 }
    277 
    278 // Test out the cases when the RR degenerates to a rect
    279 static void test_round_rect_rects(skiatest::Reporter* reporter) {
    280     SkRect r;
    281 
    282     //----
    283     SkRRect empty;
    284 
    285     empty.setEmpty();
    286 
    287     REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
    288     r = empty.rect();
    289     REPORTER_ASSERT(reporter, 0 == r.fLeft && 0 == r.fTop && 0 == r.fRight && 0 == r.fBottom);
    290 
    291     //----
    292     SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
    293     SkRRect rr1;
    294     rr1.setRectXY(rect, 0, 0);
    295 
    296     REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
    297     r = rr1.rect();
    298     REPORTER_ASSERT(reporter, rect == r);
    299 
    300     //----
    301     SkPoint radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
    302 
    303     SkRRect rr2;
    304     rr2.setRectRadii(rect, radii);
    305 
    306     REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
    307     r = rr2.rect();
    308     REPORTER_ASSERT(reporter, rect == r);
    309 
    310     //----
    311     SkPoint radii2[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
    312 
    313     SkRRect rr3;
    314     rr3.setRectRadii(rect, radii2);
    315     REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr3.type());
    316 }
    317 
    318 // Test out the cases when the RR degenerates to an oval
    319 static void test_round_rect_ovals(skiatest::Reporter* reporter) {
    320     //----
    321     SkRect oval;
    322     SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
    323     SkRRect rr1;
    324     rr1.setRectXY(rect, SkScalarHalf(kWidth), SkScalarHalf(kHeight));
    325 
    326     REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr1.type());
    327     oval = rr1.rect();
    328     REPORTER_ASSERT(reporter, oval == rect);
    329 }
    330 
    331 // Test out the non-degenerate RR cases
    332 static void test_round_rect_general(skiatest::Reporter* reporter) {
    333     //----
    334     SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
    335     SkRRect rr1;
    336     rr1.setRectXY(rect, 20, 20);
    337 
    338     REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr1.type());
    339 
    340     //----
    341     SkPoint radii[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
    342 
    343     SkRRect rr2;
    344     rr2.setRectRadii(rect, radii);
    345 
    346     REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr2.type());
    347 }
    348 
    349 // Test out questionable-parameter handling
    350 static void test_round_rect_iffy_parameters(skiatest::Reporter* reporter) {
    351 
    352     // When the radii exceed the base rect they are proportionally scaled down
    353     // to fit
    354     SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
    355     SkPoint radii[4] = { { 50, 100 }, { 100, 50 }, { 50, 100 }, { 100, 50 } };
    356 
    357     SkRRect rr1;
    358     rr1.setRectRadii(rect, radii);
    359 
    360     REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr1.type());
    361 
    362     const SkPoint& p = rr1.radii(SkRRect::kUpperLeft_Corner);
    363 
    364     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fX, 33.33333f));
    365     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fY, 66.66666f));
    366 
    367     // Negative radii should be capped at zero
    368     SkRRect rr2;
    369     rr2.setRectXY(rect, -10, -20);
    370 
    371     REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
    372 
    373     const SkPoint& p2 = rr2.radii(SkRRect::kUpperLeft_Corner);
    374 
    375     REPORTER_ASSERT(reporter, 0.0f == p2.fX);
    376     REPORTER_ASSERT(reporter, 0.0f == p2.fY);
    377 }
    378 
    379 // Move a small box from the start position by (stepX, stepY) 'numSteps' times
    380 // testing for containment in 'rr' at each step.
    381 static void test_direction(skiatest::Reporter* reporter, const SkRRect &rr,
    382                            SkScalar initX, int stepX, SkScalar initY, int stepY,
    383                            int numSteps, const bool* contains) {
    384     SkScalar x = initX, y = initY;
    385     for (int i = 0; i < numSteps; ++i) {
    386         SkRect test = SkRect::MakeXYWH(x, y,
    387                                        stepX ? SkIntToScalar(stepX) : SK_Scalar1,
    388                                        stepY ? SkIntToScalar(stepY) : SK_Scalar1);
    389         test.sort();
    390 
    391         REPORTER_ASSERT(reporter, contains[i] == rr.contains(test));
    392 
    393         x += stepX;
    394         y += stepY;
    395     }
    396 }
    397 
    398 // Exercise the RR's contains rect method
    399 static void test_round_rect_contains_rect(skiatest::Reporter* reporter) {
    400 
    401     static const int kNumRRects = 4;
    402     static const SkVector gRadii[kNumRRects][4] = {
    403         { {  0,  0 }, {  0,  0 }, {  0,  0 }, {  0,  0 } },  // rect
    404         { { 20, 20 }, { 20, 20 }, { 20, 20 }, { 20, 20 } },  // circle
    405         { { 10, 10 }, { 10, 10 }, { 10, 10 }, { 10, 10 } },  // simple
    406         { {  0,  0 }, { 20, 20 }, { 10, 10 }, { 30, 30 } }   // complex
    407     };
    408 
    409     SkRRect rrects[kNumRRects];
    410     for (int i = 0; i < kNumRRects; ++i) {
    411         rrects[i].setRectRadii(SkRect::MakeWH(40, 40), gRadii[i]);
    412     }
    413 
    414     // First test easy outs - boxes that are obviously out on
    415     // each corner and edge
    416     static const SkRect easyOuts[] = {
    417         { -5, -5,  5,  5 }, // NW
    418         { 15, -5, 20,  5 }, // N
    419         { 35, -5, 45,  5 }, // NE
    420         { 35, 15, 45, 20 }, // E
    421         { 35, 45, 35, 45 }, // SE
    422         { 15, 35, 20, 45 }, // S
    423         { -5, 35,  5, 45 }, // SW
    424         { -5, 15,  5, 20 }  // W
    425     };
    426 
    427     for (int i = 0; i < kNumRRects; ++i) {
    428         for (size_t j = 0; j < SK_ARRAY_COUNT(easyOuts); ++j) {
    429             REPORTER_ASSERT(reporter, !rrects[i].contains(easyOuts[j]));
    430         }
    431     }
    432 
    433     // Now test non-trivial containment. For each compass
    434     // point walk a 1x1 rect in from the edge  of the bounding
    435     // rect
    436     static const int kNumSteps = 15;
    437     bool answers[kNumRRects][8][kNumSteps] = {
    438         // all the test rects are inside the degenerate rrect
    439         {
    440             // rect
    441             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    442             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    443             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    444             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    445             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    446             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    447             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    448             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    449         },
    450         // for the circle we expect 6 blocks to be out on the
    451         // corners (then the rest in) and only the first block
    452         // out on the vertical and horizontal axes (then
    453         // the rest in)
    454         {
    455             // circle
    456             { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    457             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    458             { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    459             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    460             { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    461             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    462             { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    463             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    464         },
    465         // for the simple round rect we expect 3 out on
    466         // the corners (then the rest in) and no blocks out
    467         // on the vertical and horizontal axes
    468         {
    469             // simple RR
    470             { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    471             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    472             { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    473             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    474             { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    475             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    476             { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    477             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    478         },
    479         // for the complex case the answer is different for each direction
    480         {
    481             // complex RR
    482             // all in for NW (rect) corner (same as rect case)
    483             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    484             // only first block out for N (same as circle case)
    485             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    486             // first 6 blocks out for NE (same as circle case)
    487             { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    488             // only first block out for E (same as circle case)
    489             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    490             // first 3 blocks out for SE (same as simple case)
    491             { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    492             // first two blocks out for S
    493             { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    494             // first 9 blocks out for SW
    495             { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
    496             // first two blocks out for W (same as S)
    497             { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    498          }
    499     };
    500 
    501     for (int i = 0; i < kNumRRects; ++i) {
    502         test_direction(reporter, rrects[i],     0,  1,     0,  1, kNumSteps, answers[i][0]); // NW
    503         test_direction(reporter, rrects[i], 19.5f,  0,     0,  1, kNumSteps, answers[i][1]); // N
    504         test_direction(reporter, rrects[i],    40, -1,     0,  1, kNumSteps, answers[i][2]); // NE
    505         test_direction(reporter, rrects[i],    40, -1, 19.5f,  0, kNumSteps, answers[i][3]); // E
    506         test_direction(reporter, rrects[i],    40, -1,    40, -1, kNumSteps, answers[i][4]); // SE
    507         test_direction(reporter, rrects[i], 19.5f,  0,    40, -1, kNumSteps, answers[i][5]); // S
    508         test_direction(reporter, rrects[i],     0,  1,    40, -1, kNumSteps, answers[i][6]); // SW
    509         test_direction(reporter, rrects[i],     0,  1, 19.5f,  0, kNumSteps, answers[i][7]); // W
    510     }
    511 }
    512 
    513 // Called for a matrix that should cause SkRRect::transform to fail.
    514 static void assert_transform_failure(skiatest::Reporter* reporter, const SkRRect& orig,
    515                                      const SkMatrix& matrix) {
    516     // The test depends on the fact that the original is not empty.
    517     SkASSERT(!orig.isEmpty());
    518     SkRRect dst;
    519     dst.setEmpty();
    520 
    521     const SkRRect copyOfDst = dst;
    522     const SkRRect copyOfOrig = orig;
    523     bool success = orig.transform(matrix, &dst);
    524     // This transform should fail.
    525     REPORTER_ASSERT(reporter, !success);
    526     // Since the transform failed, dst should be unchanged.
    527     REPORTER_ASSERT(reporter, copyOfDst == dst);
    528     // original should not be modified.
    529     REPORTER_ASSERT(reporter, copyOfOrig == orig);
    530     REPORTER_ASSERT(reporter, orig != dst);
    531 }
    532 
    533 #define GET_RADII                                                       \
    534     const SkVector& origUL = orig.radii(SkRRect::kUpperLeft_Corner);    \
    535     const SkVector& origUR = orig.radii(SkRRect::kUpperRight_Corner);   \
    536     const SkVector& origLR = orig.radii(SkRRect::kLowerRight_Corner);   \
    537     const SkVector& origLL = orig.radii(SkRRect::kLowerLeft_Corner);    \
    538     const SkVector& dstUL = dst.radii(SkRRect::kUpperLeft_Corner);      \
    539     const SkVector& dstUR = dst.radii(SkRRect::kUpperRight_Corner);     \
    540     const SkVector& dstLR = dst.radii(SkRRect::kLowerRight_Corner);     \
    541     const SkVector& dstLL = dst.radii(SkRRect::kLowerLeft_Corner)
    542 
    543 // Called to test various transforms on a single SkRRect.
    544 static void test_transform_helper(skiatest::Reporter* reporter, const SkRRect& orig) {
    545     SkRRect dst;
    546     dst.setEmpty();
    547 
    548     // The identity matrix will duplicate the rrect.
    549     bool success = orig.transform(SkMatrix::I(), &dst);
    550     REPORTER_ASSERT(reporter, success);
    551     REPORTER_ASSERT(reporter, orig == dst);
    552 
    553     // Skew and Perspective make transform fail.
    554     SkMatrix matrix;
    555     matrix.reset();
    556     matrix.setSkewX(SkIntToScalar(2));
    557     assert_transform_failure(reporter, orig, matrix);
    558 
    559     matrix.reset();
    560     matrix.setSkewY(SkIntToScalar(3));
    561     assert_transform_failure(reporter, orig, matrix);
    562 
    563     matrix.reset();
    564     matrix.setPerspX(4);
    565     assert_transform_failure(reporter, orig, matrix);
    566 
    567     matrix.reset();
    568     matrix.setPerspY(5);
    569     assert_transform_failure(reporter, orig, matrix);
    570 
    571     // Rotation fails.
    572     matrix.reset();
    573     matrix.setRotate(SkIntToScalar(90));
    574     assert_transform_failure(reporter, orig, matrix);
    575     matrix.setRotate(SkIntToScalar(37));
    576     assert_transform_failure(reporter, orig, matrix);
    577 
    578     // Translate will keep the rect moved, but otherwise the same.
    579     matrix.reset();
    580     SkScalar translateX = SkIntToScalar(32);
    581     SkScalar translateY = SkIntToScalar(15);
    582     matrix.setTranslateX(translateX);
    583     matrix.setTranslateY(translateY);
    584     dst.setEmpty();
    585     success = orig.transform(matrix, &dst);
    586     REPORTER_ASSERT(reporter, success);
    587     for (int i = 0; i < 4; ++i) {
    588         REPORTER_ASSERT(reporter,
    589                 orig.radii((SkRRect::Corner) i) == dst.radii((SkRRect::Corner) i));
    590     }
    591     REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
    592     REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
    593     REPORTER_ASSERT(reporter, dst.rect().left() == orig.rect().left() + translateX);
    594     REPORTER_ASSERT(reporter, dst.rect().top() == orig.rect().top() + translateY);
    595 
    596     // Keeping the translation, but adding skew will make transform fail.
    597     matrix.setSkewY(SkIntToScalar(7));
    598     assert_transform_failure(reporter, orig, matrix);
    599 
    600     // Scaling in -x will flip the round rect horizontally.
    601     matrix.reset();
    602     matrix.setScaleX(SkIntToScalar(-1));
    603     dst.setEmpty();
    604     success = orig.transform(matrix, &dst);
    605     REPORTER_ASSERT(reporter, success);
    606     {
    607         GET_RADII;
    608         // Radii have swapped in x.
    609         REPORTER_ASSERT(reporter, origUL == dstUR);
    610         REPORTER_ASSERT(reporter, origUR == dstUL);
    611         REPORTER_ASSERT(reporter, origLR == dstLL);
    612         REPORTER_ASSERT(reporter, origLL == dstLR);
    613     }
    614     // Width and height remain the same.
    615     REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
    616     REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
    617     // Right and left have swapped (sort of)
    618     REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
    619     // Top has stayed the same.
    620     REPORTER_ASSERT(reporter, orig.rect().top() == dst.rect().top());
    621 
    622     // Keeping the scale, but adding a persp will make transform fail.
    623     matrix.setPerspX(7);
    624     assert_transform_failure(reporter, orig, matrix);
    625 
    626     // Scaling in -y will flip the round rect vertically.
    627     matrix.reset();
    628     matrix.setScaleY(SkIntToScalar(-1));
    629     dst.setEmpty();
    630     success = orig.transform(matrix, &dst);
    631     REPORTER_ASSERT(reporter, success);
    632     {
    633         GET_RADII;
    634         // Radii have swapped in y.
    635         REPORTER_ASSERT(reporter, origUL == dstLL);
    636         REPORTER_ASSERT(reporter, origUR == dstLR);
    637         REPORTER_ASSERT(reporter, origLR == dstUR);
    638         REPORTER_ASSERT(reporter, origLL == dstUL);
    639     }
    640     // Width and height remain the same.
    641     REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
    642     REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
    643     // Top and bottom have swapped (sort of)
    644     REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
    645     // Left has stayed the same.
    646     REPORTER_ASSERT(reporter, orig.rect().left() == dst.rect().left());
    647 
    648     // Scaling in -x and -y will swap in both directions.
    649     matrix.reset();
    650     matrix.setScaleY(SkIntToScalar(-1));
    651     matrix.setScaleX(SkIntToScalar(-1));
    652     dst.setEmpty();
    653     success = orig.transform(matrix, &dst);
    654     REPORTER_ASSERT(reporter, success);
    655     {
    656         GET_RADII;
    657         REPORTER_ASSERT(reporter, origUL == dstLR);
    658         REPORTER_ASSERT(reporter, origUR == dstLL);
    659         REPORTER_ASSERT(reporter, origLR == dstUL);
    660         REPORTER_ASSERT(reporter, origLL == dstUR);
    661     }
    662     // Width and height remain the same.
    663     REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
    664     REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
    665     REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
    666     REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
    667 
    668     // Scale in both directions.
    669     SkScalar xScale = SkIntToScalar(3);
    670     SkScalar yScale = 3.2f;
    671     matrix.reset();
    672     matrix.setScaleX(xScale);
    673     matrix.setScaleY(yScale);
    674     dst.setEmpty();
    675     success = orig.transform(matrix, &dst);
    676     REPORTER_ASSERT(reporter, success);
    677     // Radii are scaled.
    678     for (int i = 0; i < 4; ++i) {
    679         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.radii((SkRRect::Corner) i).fX,
    680                                     orig.radii((SkRRect::Corner) i).fX * xScale));
    681         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.radii((SkRRect::Corner) i).fY,
    682                                     orig.radii((SkRRect::Corner) i).fY * yScale));
    683     }
    684     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().width(),
    685                                                   orig.rect().width() * xScale));
    686     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().height(),
    687                                                   orig.rect().height() * yScale));
    688     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().left(),
    689                                                   orig.rect().left() * xScale));
    690     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().top(),
    691                                                   orig.rect().top() * yScale));
    692 }
    693 
    694 static void test_round_rect_transform(skiatest::Reporter* reporter) {
    695     SkRRect rrect;
    696     {
    697         SkRect r = { 0, 0, kWidth, kHeight };
    698         rrect.setRectXY(r, SkIntToScalar(4), SkIntToScalar(7));
    699         test_transform_helper(reporter, rrect);
    700     }
    701     {
    702         SkRect r = { SkIntToScalar(5), SkIntToScalar(15),
    703                      SkIntToScalar(27), SkIntToScalar(34) };
    704         SkVector radii[4] = { { 0, SkIntToScalar(1) },
    705                               { SkIntToScalar(2), SkIntToScalar(3) },
    706                               { SkIntToScalar(4), SkIntToScalar(5) },
    707                               { SkIntToScalar(6), SkIntToScalar(7) } };
    708         rrect.setRectRadii(r, radii);
    709         test_transform_helper(reporter, rrect);
    710     }
    711 }
    712 
    713 // Test out the case where an oval already off in space is translated/scaled
    714 // further off into space - yielding numerical issues when the rect & radii
    715 // are transformed separatly
    716 // BUG=skia:2696
    717 static void test_issue_2696(skiatest::Reporter* reporter) {
    718     SkRRect rrect;
    719     SkRect r = { 28443.8594f, 53.1428604f, 28446.7148f, 56.0000038f };
    720     rrect.setOval(r);
    721 
    722     SkMatrix xform;
    723     xform.setAll(2.44f,  0.0f, 485411.7f,
    724                  0.0f,  2.44f,   -438.7f,
    725                  0.0f,   0.0f,      1.0f);
    726     SkRRect dst;
    727 
    728     bool success = rrect.transform(xform, &dst);
    729     REPORTER_ASSERT(reporter, success);
    730 
    731     SkScalar halfWidth = SkScalarHalf(dst.width());
    732     SkScalar halfHeight = SkScalarHalf(dst.height());
    733 
    734     for (int i = 0; i < 4; ++i) {
    735         REPORTER_ASSERT(reporter,
    736                         SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fX, halfWidth));
    737         REPORTER_ASSERT(reporter,
    738                         SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fY, halfHeight));
    739     }
    740 }
    741 
    742 void test_read_rrect(skiatest::Reporter* reporter, const SkRRect& rrect, bool shouldEqualSrc) {
    743     // It would be cleaner to call rrect.writeToMemory into a buffer. However, writeToMemory asserts
    744     // that the rrect is valid and our caller may have fiddled with the internals of rrect to make
    745     // it invalid.
    746     const void* buffer = reinterpret_cast<const void*>(&rrect);
    747     SkRRect deserialized;
    748     size_t size = deserialized.readFromMemory(buffer, sizeof(SkRRect));
    749     REPORTER_ASSERT(reporter, size == SkRRect::kSizeInMemory);
    750     REPORTER_ASSERT(reporter, deserialized.isValid());
    751     if (shouldEqualSrc) {
    752        REPORTER_ASSERT(reporter, rrect == deserialized);
    753     }
    754 }
    755 
    756 static void test_read(skiatest::Reporter* reporter) {
    757     static const SkRect kRect = {10.f, 10.f, 20.f, 20.f};
    758     static const SkRect kNaNRect = {10.f, 10.f, 20.f, SK_ScalarNaN};
    759     static const SkRect kInfRect = {10.f, 10.f, SK_ScalarInfinity, 20.f};
    760     SkRRect rrect;
    761 
    762     test_read_rrect(reporter, SkRRect::MakeEmpty(), true);
    763     test_read_rrect(reporter, SkRRect::MakeRect(kRect), true);
    764     // These get coerced to empty.
    765     test_read_rrect(reporter, SkRRect::MakeRect(kInfRect), true);
    766     test_read_rrect(reporter, SkRRect::MakeRect(kNaNRect), true);
    767 
    768     rrect.setRect(kRect);
    769     SkRect* innerRect = reinterpret_cast<SkRect*>(&rrect);
    770     SkASSERT(*innerRect == kRect);
    771     *innerRect = kInfRect;
    772     test_read_rrect(reporter, rrect, false);
    773     *innerRect = kNaNRect;
    774     test_read_rrect(reporter, rrect, false);
    775 
    776     test_read_rrect(reporter, SkRRect::MakeOval(kRect), true);
    777     test_read_rrect(reporter, SkRRect::MakeOval(kInfRect), true);
    778     test_read_rrect(reporter, SkRRect::MakeOval(kNaNRect), true);
    779     rrect.setOval(kRect);
    780     *innerRect = kInfRect;
    781     test_read_rrect(reporter, rrect, false);
    782     *innerRect = kNaNRect;
    783     test_read_rrect(reporter, rrect, false);
    784 
    785     test_read_rrect(reporter, SkRRect::MakeRectXY(kRect, 5.f, 5.f), true);
    786     // rrect should scale down the radii to make this legal
    787     test_read_rrect(reporter, SkRRect::MakeRectXY(kRect, 5.f, 400.f), true);
    788 
    789     static const SkVector kRadii[4] = {{0.5f, 1.f}, {1.5f, 2.f}, {2.5f, 3.f}, {3.5f, 4.f}};
    790     rrect.setRectRadii(kRect, kRadii);
    791     test_read_rrect(reporter, rrect, true);
    792     SkScalar* innerRadius = reinterpret_cast<SkScalar*>(&rrect) + 6;
    793     SkASSERT(*innerRadius == 1.5f);
    794     *innerRadius = 400.f;
    795     test_read_rrect(reporter, rrect, false);
    796     *innerRadius = SK_ScalarInfinity;
    797     test_read_rrect(reporter, rrect, false);
    798     *innerRadius = SK_ScalarNaN;
    799     test_read_rrect(reporter, rrect, false);
    800     *innerRadius = -10.f;
    801     test_read_rrect(reporter, rrect, false);
    802 }
    803 
    804 DEF_TEST(RoundRect, reporter) {
    805     test_round_rect_basic(reporter);
    806     test_round_rect_rects(reporter);
    807     test_round_rect_ovals(reporter);
    808     test_round_rect_general(reporter);
    809     test_round_rect_iffy_parameters(reporter);
    810     test_inset(reporter);
    811     test_round_rect_contains_rect(reporter);
    812     test_round_rect_transform(reporter);
    813     test_issue_2696(reporter);
    814     test_tricky_radii(reporter);
    815     test_empty_crbug_458524(reporter);
    816     test_empty(reporter);
    817     test_read(reporter);
    818 }
    819