Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "gm.h"
      9 #include "SkPath.h"
     10 
     11 typedef SkScalar (*MakePathProc)(SkPath*);
     12 
     13 static SkScalar make_frame(SkPath* path) {
     14     SkRect r = { SkIntToScalar(10), SkIntToScalar(10),
     15                  SkIntToScalar(630), SkIntToScalar(470) };
     16     path->addRoundRect(r, SkIntToScalar(15), SkIntToScalar(15));
     17 
     18     SkPaint paint;
     19     paint.setStyle(SkPaint::kStroke_Style);
     20     paint.setStrokeWidth(SkIntToScalar(5));
     21     paint.getFillPath(*path, path);
     22     return SkIntToScalar(15);
     23 }
     24 
     25 static SkScalar make_triangle(SkPath* path) {
     26     constexpr int gCoord[] = {
     27         10, 20, 15, 5, 30, 30
     28     };
     29     path->moveTo(SkIntToScalar(gCoord[0]), SkIntToScalar(gCoord[1]));
     30     path->lineTo(SkIntToScalar(gCoord[2]), SkIntToScalar(gCoord[3]));
     31     path->lineTo(SkIntToScalar(gCoord[4]), SkIntToScalar(gCoord[5]));
     32     path->close();
     33     path->offset(SkIntToScalar(10), SkIntToScalar(0));
     34     return SkIntToScalar(30);
     35 }
     36 
     37 static SkScalar make_rect(SkPath* path) {
     38     SkRect r = { SkIntToScalar(10), SkIntToScalar(10),
     39                  SkIntToScalar(30), SkIntToScalar(30) };
     40     path->addRect(r);
     41     path->offset(SkIntToScalar(10), SkIntToScalar(0));
     42     return SkIntToScalar(30);
     43 }
     44 
     45 static SkScalar make_oval(SkPath* path) {
     46     SkRect r = { SkIntToScalar(10), SkIntToScalar(10),
     47                  SkIntToScalar(30), SkIntToScalar(30) };
     48     path->addOval(r);
     49     path->offset(SkIntToScalar(10), SkIntToScalar(0));
     50     return SkIntToScalar(30);
     51 }
     52 
     53 static SkScalar make_sawtooth(SkPath* path, int teeth) {
     54     SkScalar x = SkIntToScalar(20);
     55     SkScalar y = SkIntToScalar(20);
     56     const SkScalar x0 = x;
     57     const SkScalar dx = SkIntToScalar(5);
     58     const SkScalar dy = SkIntToScalar(10);
     59 
     60     path->moveTo(x, y);
     61     for (int i = 0; i < teeth; i++) {
     62         x += dx;
     63         path->lineTo(x, y - dy);
     64         x += dx;
     65         path->lineTo(x, y + dy);
     66     }
     67     path->lineTo(x, y + (2 * dy));
     68     path->lineTo(x0, y + (2 * dy));
     69     path->close();
     70     return SkIntToScalar(30);
     71 }
     72 
     73 static SkScalar make_sawtooth_3(SkPath* path) { return make_sawtooth(path, 3); }
     74 static SkScalar make_sawtooth_32(SkPath* path) { return make_sawtooth(path, 32); }
     75 
     76 static SkScalar make_house(SkPath* path) {
     77     path->moveTo(21, 23);
     78     path->lineTo(21, 11.534f);
     79     path->lineTo(22.327f, 12.741f);
     80     path->lineTo(23.673f, 11.261f);
     81     path->lineTo(12, 0.648f);
     82     path->lineTo(8, 4.285f);
     83     path->lineTo(8, 2);
     84     path->lineTo(4, 2);
     85     path->lineTo(4, 7.921f);
     86     path->lineTo(0.327f, 11.26f);
     87     path->lineTo(1.673f, 12.74f);
     88     path->lineTo(3, 11.534f);
     89     path->lineTo(3, 23);
     90     path->lineTo(11, 23);
     91     path->lineTo(11, 18);
     92     path->lineTo(13, 18);
     93     path->lineTo(13, 23);
     94     path->lineTo(21, 23);
     95     path->close();
     96     path->lineTo(9, 16);
     97     path->lineTo(9, 21);
     98     path->lineTo(5, 21);
     99     path->lineTo(5, 9.715f);
    100     path->lineTo(12, 3.351f);
    101     path->lineTo(19, 9.715f);
    102     path->lineTo(19, 21);
    103     path->lineTo(15, 21);
    104     path->lineTo(15, 16);
    105     path->lineTo(9, 16);
    106     path->close();
    107     path->offset(20, 0);
    108     return SkIntToScalar(30);
    109 }
    110 
    111 static SkScalar make_star(SkPath* path, int n) {
    112     const SkScalar c = SkIntToScalar(45);
    113     const SkScalar r = SkIntToScalar(20);
    114 
    115     SkScalar rad = -SK_ScalarPI / 2;
    116     const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;
    117 
    118     path->moveTo(c, c - r);
    119     for (int i = 1; i < n; i++) {
    120         rad += drad;
    121         SkScalar cosV, sinV = SkScalarSinCos(rad, &cosV);
    122         path->lineTo(c + cosV * r, c + sinV * r);
    123     }
    124     path->close();
    125     return r * 2 * 6 / 5;
    126 }
    127 
    128 static SkScalar make_star_5(SkPath* path) { return make_star(path, 5); }
    129 static SkScalar make_star_13(SkPath* path) { return make_star(path, 13); }
    130 
    131 // We don't expect any output from this path.
    132 static SkScalar make_line(SkPath* path) {
    133     path->moveTo(SkIntToScalar(30), SkIntToScalar(30));
    134     path->lineTo(SkIntToScalar(120), SkIntToScalar(40));
    135     path->close();
    136     path->moveTo(SkIntToScalar(150), SkIntToScalar(30));
    137     path->lineTo(SkIntToScalar(150), SkIntToScalar(30));
    138     path->lineTo(SkIntToScalar(300), SkIntToScalar(40));
    139     path->close();
    140     return SkIntToScalar(40);
    141 }
    142 
    143 static void make_info(SkPath* path) {
    144     path->moveTo(24, 4);
    145     path->cubicTo(12.94999980926514f,
    146                   4,
    147                   4,
    148                   12.94999980926514f,
    149                   4,
    150                   24);
    151     path->cubicTo(4,
    152                   35.04999923706055f,
    153                   12.94999980926514f,
    154                   44,
    155                   24,
    156                   44);
    157     path->cubicTo(35.04999923706055f,
    158                   44,
    159                   44,
    160                   35.04999923706055f,
    161                   44,
    162                   24);
    163     path->cubicTo(44,
    164                   12.95000076293945f,
    165                   35.04999923706055f,
    166                   4,
    167                   24,
    168                   4);
    169     path->close();
    170     path->moveTo(26, 34);
    171     path->lineTo(22, 34);
    172     path->lineTo(22, 22);
    173     path->lineTo(26, 22);
    174     path->lineTo(26, 34);
    175     path->close();
    176     path->moveTo(26, 18);
    177     path->lineTo(22, 18);
    178     path->lineTo(22, 14);
    179     path->lineTo(26, 14);
    180     path->lineTo(26, 18);
    181     path->close();
    182 }
    183 
    184 static void make_accessibility(SkPath* path) {
    185     path->moveTo(12, 2);
    186     path->cubicTo(13.10000038146973f,
    187                   2,
    188                   14,
    189                   2.900000095367432f,
    190                   14,
    191                   4);
    192     path->cubicTo(14,
    193                   5.099999904632568f,
    194                   13.10000038146973f,
    195                   6,
    196                   12,
    197                   6);
    198     path->cubicTo(10.89999961853027f,
    199                   6,
    200                   10,
    201                   5.099999904632568f,
    202                   10,
    203                   4);
    204     path->cubicTo(10,
    205                   2.900000095367432f,
    206                   10.89999961853027f,
    207                   2,
    208                   12,
    209                   2);
    210     path->close();
    211     path->moveTo(21, 9);
    212     path->lineTo(15, 9);
    213     path->lineTo(15, 22);
    214     path->lineTo(13, 22);
    215     path->lineTo(13, 16);
    216     path->lineTo(11, 16);
    217     path->lineTo(11, 22);
    218     path->lineTo(9, 22);
    219     path->lineTo(9, 9);
    220     path->lineTo(3, 9);
    221     path->lineTo(3, 7);
    222     path->lineTo(21, 7);
    223     path->lineTo(21, 9);
    224     path->close();
    225 }
    226 
    227 // test case for http://crbug.com/695196
    228 static void make_visualizer(SkPath* path) {
    229     path->moveTo(1.9520f, 2.0000f);
    230     path->conicTo(1.5573f, 1.9992f, 1.2782f, 2.2782f, 0.9235f);
    231     path->conicTo(0.9992f, 2.5573f, 1.0000f, 2.9520f, 0.9235f);
    232     path->lineTo(1.0000f, 5.4300f);
    233     path->lineTo(17.0000f, 5.4300f);
    234     path->lineTo(17.0000f, 2.9520f);
    235     path->conicTo(17.0008f, 2.5573f, 16.7218f, 2.2782f, 0.9235f);
    236     path->conicTo(16.4427f, 1.9992f, 16.0480f, 2.0000f, 0.9235f);
    237     path->lineTo(1.9520f, 2.0000f);
    238     path->close();
    239     path->moveTo(2.7140f, 3.1430f);
    240     path->conicTo(3.0547f, 3.1287f, 3.2292f, 3.4216f, 0.8590f);
    241     path->conicTo(3.4038f, 3.7145f, 3.2292f, 4.0074f, 0.8590f);
    242     path->conicTo(3.0547f, 4.3003f, 2.7140f, 4.2860f, 0.8590f);
    243     path->conicTo(2.1659f, 4.2631f, 2.1659f, 3.7145f, 0.7217f);
    244     path->conicTo(2.1659f, 3.1659f, 2.7140f, 3.1430f, 0.7217f);
    245     path->lineTo(2.7140f, 3.1430f);
    246     path->close();
    247     path->moveTo(5.0000f, 3.1430f);
    248     path->conicTo(5.3407f, 3.1287f, 5.5152f, 3.4216f, 0.8590f);
    249     path->conicTo(5.6898f, 3.7145f, 5.5152f, 4.0074f, 0.8590f);
    250     path->conicTo(5.3407f, 4.3003f, 5.0000f, 4.2860f, 0.8590f);
    251     path->conicTo(4.4519f, 4.2631f, 4.4519f, 3.7145f, 0.7217f);
    252     path->conicTo(4.4519f, 3.1659f, 5.0000f, 3.1430f, 0.7217f);
    253     path->lineTo(5.0000f, 3.1430f);
    254     path->close();
    255     path->moveTo(7.2860f, 3.1430f);
    256     path->conicTo(7.6267f, 3.1287f, 7.8012f, 3.4216f, 0.8590f);
    257     path->conicTo(7.9758f, 3.7145f, 7.8012f, 4.0074f, 0.8590f);
    258     path->conicTo(7.6267f, 4.3003f, 7.2860f, 4.2860f, 0.8590f);
    259     path->conicTo(6.7379f, 4.2631f, 6.7379f, 3.7145f, 0.7217f);
    260     path->conicTo(6.7379f, 3.1659f, 7.2860f, 3.1430f, 0.7217f);
    261     path->close();
    262     path->moveTo(1.0000f, 6.1900f);
    263     path->lineTo(1.0000f, 14.3810f);
    264     path->conicTo(0.9992f, 14.7757f, 1.2782f, 15.0548f, 0.9235f);
    265     path->conicTo(1.5573f, 15.3338f, 1.9520f, 15.3330f, 0.9235f);
    266     path->lineTo(16.0480f, 15.3330f);
    267     path->conicTo(16.4427f, 15.3338f, 16.7218f, 15.0548f, 0.9235f);
    268     path->conicTo(17.0008f, 14.7757f, 17.0000f, 14.3810f, 0.9235f);
    269     path->lineTo(17.0000f, 6.1910f);
    270     path->lineTo(1.0000f, 6.1910f);
    271     path->lineTo(1.0000f, 6.1900f);
    272     path->close();
    273 }
    274 
    275 constexpr MakePathProc gProcs[] = {
    276     make_frame,
    277     make_triangle,
    278     make_rect,
    279     make_oval,
    280     make_sawtooth_32,
    281     make_star_5,
    282     make_star_13,
    283     make_line,
    284     make_house,
    285     make_sawtooth_3,
    286 };
    287 
    288 #define N   SK_ARRAY_COUNT(gProcs)
    289 
    290 class PathFillGM : public skiagm::GM {
    291     SkPath  fPath[N];
    292     SkScalar fDY[N];
    293     SkPath  fInfoPath;
    294     SkPath  fAccessibilityPath;
    295     SkPath  fVisualizerPath;
    296 protected:
    297     void onOnceBeforeDraw() override {
    298         for (size_t i = 0; i < N; i++) {
    299             fDY[i] = gProcs[i](&fPath[i]);
    300         }
    301 
    302         make_info(&fInfoPath);
    303         make_accessibility(&fAccessibilityPath);
    304         make_visualizer(&fVisualizerPath);
    305     }
    306 
    307 
    308     SkString onShortName() override {
    309         return SkString("pathfill");
    310     }
    311 
    312     SkISize onISize() override {
    313         return SkISize::Make(640, 480);
    314     }
    315 
    316     void onDraw(SkCanvas* canvas) override {
    317         SkPaint paint;
    318         paint.setAntiAlias(true);
    319 
    320         for (size_t i = 0; i < N; i++) {
    321             canvas->drawPath(fPath[i], paint);
    322             canvas->translate(SkIntToScalar(0), fDY[i]);
    323         }
    324 
    325         canvas->save();
    326         canvas->scale(0.300000011920929f, 0.300000011920929f);
    327         canvas->translate(50, 50);
    328         canvas->drawPath(fInfoPath, paint);
    329         canvas->restore();
    330 
    331         canvas->scale(2, 2);
    332         canvas->translate(5, 15);
    333         canvas->drawPath(fAccessibilityPath, paint);
    334 
    335         canvas->scale(0.5f, 0.5f);
    336         canvas->translate(5, 50);
    337         canvas->drawPath(fVisualizerPath, paint);
    338     }
    339 
    340 private:
    341     typedef skiagm::GM INHERITED;
    342 };
    343 
    344 // test inverse-fill w/ a clip that completely excludes the geometry
    345 class PathInverseFillGM : public skiagm::GM {
    346     SkPath  fPath[N];
    347     SkScalar fDY[N];
    348 protected:
    349     void onOnceBeforeDraw() override {
    350         for (size_t i = 0; i < N; i++) {
    351             fDY[i] = gProcs[i](&fPath[i]);
    352         }
    353     }
    354 
    355     SkString onShortName() override {
    356         return SkString("pathinvfill");
    357     }
    358 
    359     SkISize onISize() override {
    360         return SkISize::Make(450, 220);
    361     }
    362 
    363     static void show(SkCanvas* canvas, const SkPath& path, const SkPaint& paint,
    364                      const SkRect* clip, SkScalar top, const SkScalar bottom) {
    365         canvas->save();
    366         if (clip) {
    367             SkRect r = *clip;
    368             r.fTop = top;
    369             r.fBottom = bottom;
    370             canvas->clipRect(r);
    371         }
    372         canvas->drawPath(path, paint);
    373         canvas->restore();
    374     }
    375 
    376     void onDraw(SkCanvas* canvas) override {
    377         SkPath path;
    378 
    379         path.addCircle(SkIntToScalar(50), SkIntToScalar(50), SkIntToScalar(40));
    380         path.toggleInverseFillType();
    381 
    382         SkRect clipR = { 0, 0, SkIntToScalar(100), SkIntToScalar(200) };
    383 
    384         canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
    385 
    386         for (int doclip = 0; doclip <= 1; ++doclip) {
    387             for (int aa = 0; aa <= 1; ++aa) {
    388                 SkPaint paint;
    389                 paint.setAntiAlias(SkToBool(aa));
    390 
    391                 canvas->save();
    392                 canvas->clipRect(clipR);
    393 
    394                 const SkRect* clipPtr = doclip ? &clipR : nullptr;
    395 
    396                 show(canvas, path, paint, clipPtr, clipR.fTop, clipR.centerY());
    397                 show(canvas, path, paint, clipPtr, clipR.centerY(), clipR.fBottom);
    398 
    399                 canvas->restore();
    400                 canvas->translate(SkIntToScalar(110), 0);
    401             }
    402         }
    403     }
    404 
    405 private:
    406     typedef skiagm::GM INHERITED;
    407 };
    408 
    409 DEF_SIMPLE_GM(rotatedcubicpath, canvas, 200, 200) {
    410     SkPaint p;
    411     p.setAntiAlias(true);
    412     p.setStyle(SkPaint::kFill_Style);
    413 
    414     canvas->translate(50, 50);
    415     SkPath path;
    416     path.moveTo(48,-23);
    417     path.cubicTo(48,-29.5, 6,-30, 6,-30);
    418     path.cubicTo(6,-30, 2,0, 2,0);
    419     path.cubicTo(2,0, 44,-21.5, 48,-23);
    420     path.close();
    421 
    422     p.setColor(SK_ColorBLUE);
    423     canvas->drawPath(path, p);
    424 
    425     // Rotated path, which is not antialiased on GPU
    426     p.setColor(SK_ColorRED);
    427     canvas->rotate(90);
    428     canvas->drawPath(path, p);
    429 }
    430 
    431 ///////////////////////////////////////////////////////////////////////////////
    432 
    433 DEF_GM( return new PathFillGM; )
    434 DEF_GM( return new PathInverseFillGM; )
    435 
    436 DEF_SIMPLE_GM(bug7792, canvas, 800, 800) {
    437     // from skbug.com/7792 bug description
    438     SkPaint p;
    439     SkPath path;
    440     path.moveTo(10, 10);
    441     path.moveTo(75, 75);
    442     path.lineTo(150, 75);
    443     path.lineTo(150, 150);
    444     path.lineTo(75, 150);
    445     canvas->drawPath(path, p);
    446     // from skbug.com/7792#c3
    447     canvas->translate(200, 0);
    448     path.reset();
    449     path.moveTo(75, 50);
    450     path.moveTo(100, 75);
    451     path.lineTo(150, 75);
    452     path.lineTo(150, 150);
    453     path.lineTo(75, 150);
    454     path.lineTo(75, 50);
    455     path.close();
    456     canvas->drawPath(path, p);
    457     // from skbug.com/7792#c9
    458     canvas->translate(200, 0);
    459     path.reset();
    460     path.moveTo(10, 10);
    461     path.moveTo(75, 75);
    462     path.lineTo(150, 75);
    463     path.lineTo(150, 150);
    464     path.lineTo(75, 150);
    465     path.close();
    466     canvas->drawPath(path, p);
    467     // from skbug.com/7792#c11
    468     canvas->translate(-200 * 2, 200);
    469     path.reset();
    470     path.moveTo(75, 150);
    471     path.lineTo(75, 75);
    472     path.lineTo(150, 75);
    473     path.lineTo(150, 150);
    474     path.lineTo(75, 150);
    475     path.moveTo(75, 150);
    476     canvas->drawPath(path, p);
    477     // from skbug.com/7792#c14
    478     canvas->translate(200, 0);
    479     path.reset();
    480     path.moveTo(250, 75);
    481     path.moveTo(250, 75);
    482     path.moveTo(250, 75);
    483     path.moveTo(100, 75);
    484     path.lineTo(150, 75);
    485     path.lineTo(150, 150);
    486     path.lineTo(75, 150);
    487     path.lineTo(75, 75);
    488     path.close();
    489     path.lineTo(0, 0);
    490     path.close();
    491     canvas->drawPath(path, p);
    492     // from skbug.com/7792#c15
    493     canvas->translate(200, 0);
    494     path.reset();
    495     path.moveTo(75, 75);
    496     path.lineTo(150, 75);
    497     path.lineTo(150, 150);
    498     path.lineTo(75, 150);
    499     path.moveTo(250, 75);
    500     canvas->drawPath(path, p);
    501     // from skbug.com/7792#c17
    502     canvas->translate(-200 * 2, 200);
    503     path.reset();
    504     path.moveTo(75, 10);
    505     path.moveTo(75, 75);
    506     path.lineTo(150, 75);
    507     path.lineTo(150, 150);
    508     path.lineTo(75, 150);
    509     path.lineTo(75, 10);
    510     path.close();
    511     canvas->drawPath(path, p);
    512     // from skbug.com/7792#c19
    513     canvas->translate(200, 0);
    514     path.reset();
    515     path.moveTo(75, 75);
    516     path.lineTo(75, 75);
    517     path.lineTo(75, 75);
    518     path.lineTo(75, 75);
    519     path.lineTo(150, 75);
    520     path.lineTo(150, 150);
    521     path.lineTo(75, 150);
    522     path.close();
    523     path.moveTo(10, 10);
    524     path.lineTo(30, 10);
    525     path.lineTo(10, 30);
    526     canvas->drawPath(path, p);
    527     // from skbug.com/7792#c23
    528     canvas->translate(200, 0);
    529     path.reset();
    530     path.moveTo(75, 75);
    531     path.lineTo(75, 75);
    532     path.moveTo(75, 75);
    533     path.lineTo(75, 75);
    534     path.lineTo(150, 75);
    535     path.lineTo(150, 150);
    536     path.lineTo(75, 150);
    537     path.close();
    538     canvas->drawPath(path, p);
    539     // from skbug.com/7792#c29
    540     canvas->translate(-200 * 2, 200);
    541     path.reset();
    542     path.moveTo(75, 75);
    543     path.lineTo(150, 75);
    544     path.lineTo(150, 150);
    545     path.lineTo(75, 150);
    546     path.lineTo(75, 250);
    547     path.moveTo(75, 75);
    548     path.close();
    549     canvas->drawPath(path, p);
    550     // from skbug.com/7792#c31
    551     canvas->translate(200, 0);
    552     path.reset();
    553     path.moveTo(75, 75);
    554     path.lineTo(150, 75);
    555     path.lineTo(150, 150);
    556     path.lineTo(75, 150);
    557     path.lineTo(75, 10);
    558     path.moveTo(75, 75);
    559     path.close();
    560     canvas->drawPath(path, p);
    561     // from skbug.com/7792#c36
    562     canvas->translate(200, 0);
    563     path.reset();
    564     path.moveTo(75, 75);
    565     path.lineTo(150, 75);
    566     path.lineTo(150, 150);
    567     path.lineTo(10, 150);
    568     path.moveTo(75, 75);
    569     path.lineTo(75, 75);
    570     canvas->drawPath(path, p);
    571     // from skbug.com/7792#c39
    572     canvas->translate(200, -200 * 3);
    573     path.reset();
    574     path.moveTo(150, 75);
    575     path.lineTo(150, 150);
    576     path.lineTo(75, 150);
    577     path.lineTo(75, 100);
    578     canvas->drawPath(path, p);
    579     // from zero_length_paths_aa
    580     canvas->translate(0, 200);
    581     path.reset();
    582     path.moveTo(150, 100);
    583     path.lineTo(150, 100);
    584     path.lineTo(150, 150);
    585     path.lineTo(75, 150);
    586     path.lineTo(75, 100);
    587     path.lineTo(75, 75);
    588     path.lineTo(150, 75);
    589     path.close();
    590     canvas->drawPath(path, p);
    591     // from skbug.com/7792#c41
    592     canvas->translate(0, 200);
    593     path.reset();
    594     path.moveTo(75, 75);
    595     path.lineTo(150, 75);
    596     path.lineTo(150, 150);
    597     path.lineTo(140, 150);
    598     path.lineTo(140, 75);
    599     path.moveTo(75, 75);
    600     path.close();
    601     canvas->drawPath(path, p);
    602     // from skbug.com/7792#c53
    603     canvas->translate(0, 200);
    604     path.reset();
    605     path.moveTo(75, 75);
    606     path.lineTo(150, 75);
    607     path.lineTo(150, 150);
    608     path.lineTo(140, 150);
    609     path.lineTo(140, 75);
    610     path.moveTo(75, 75);
    611     path.close();
    612     canvas->drawPath(path, p);
    613 }
    614