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 #include "SkRandom.h"
     11 #include "SkDashPathEffect.h"
     12 #include "SkParsePath.h"
     13 
     14 #define W   400
     15 #define H   400
     16 #define N   50
     17 
     18 static const SkScalar SW = SkIntToScalar(W);
     19 static const SkScalar SH = SkIntToScalar(H);
     20 
     21 static void rnd_rect(SkRect* r, SkPaint* paint, SkRandom& rand) {
     22     SkScalar x = rand.nextUScalar1() * W;
     23     SkScalar y = rand.nextUScalar1() * H;
     24     SkScalar w = rand.nextUScalar1() * (W >> 2);
     25     SkScalar h = rand.nextUScalar1() * (H >> 2);
     26     SkScalar hoffset = rand.nextSScalar1();
     27     SkScalar woffset = rand.nextSScalar1();
     28 
     29     r->set(x, y, x + w, y + h);
     30     r->offset(-w/2 + woffset, -h/2 + hoffset);
     31 
     32     paint->setColor(rand.nextU());
     33     paint->setAlpha(0xFF);
     34 }
     35 
     36 
     37 class StrokesGM : public skiagm::GM {
     38 public:
     39     StrokesGM() {}
     40 
     41 protected:
     42 
     43     SkString onShortName() override {
     44         return SkString("strokes_round");
     45     }
     46 
     47     SkISize onISize() override {
     48         return SkISize::Make(W, H*2);
     49     }
     50 
     51     void onDraw(SkCanvas* canvas) override {
     52         SkPaint paint;
     53         paint.setStyle(SkPaint::kStroke_Style);
     54         paint.setStrokeWidth(SkIntToScalar(9)/2);
     55 
     56         for (int y = 0; y < 2; y++) {
     57             paint.setAntiAlias(!!y);
     58             SkAutoCanvasRestore acr(canvas, true);
     59             canvas->translate(0, SH * y);
     60             canvas->clipRect(SkRect::MakeLTRB(
     61                                               SkIntToScalar(2), SkIntToScalar(2)
     62                                               , SW - SkIntToScalar(2), SH - SkIntToScalar(2)
     63                                               ));
     64 
     65             SkRandom rand;
     66             for (int i = 0; i < N; i++) {
     67                 SkRect r;
     68                 rnd_rect(&r, &paint, rand);
     69                 canvas->drawOval(r, paint);
     70                 rnd_rect(&r, &paint, rand);
     71                 canvas->drawRoundRect(r, r.width()/4, r.height()/4, paint);
     72                 rnd_rect(&r, &paint, rand);
     73             }
     74         }
     75     }
     76 
     77 private:
     78     typedef skiagm::GM INHERITED;
     79 };
     80 
     81 /* See
     82    https://code.google.com/p/chromium/issues/detail?id=422974          and
     83    http://jsfiddle.net/1xnku3sg/2/
     84  */
     85 class ZeroLenStrokesGM : public skiagm::GM {
     86     SkPath fMoveHfPath, fMoveZfPath, fDashedfPath, fRefPath[4];
     87     SkPath fCubicPath, fQuadPath, fLinePath;
     88 protected:
     89     void onOnceBeforeDraw() override {
     90 
     91         SkAssertResult(SkParsePath::FromSVGString("M0,0h0M10,0h0M20,0h0", &fMoveHfPath));
     92         SkAssertResult(SkParsePath::FromSVGString("M0,0zM10,0zM20,0z", &fMoveZfPath));
     93         SkAssertResult(SkParsePath::FromSVGString("M0,0h25", &fDashedfPath));
     94         SkAssertResult(SkParsePath::FromSVGString("M 0 0 C 0 0 0 0 0 0", &fCubicPath));
     95         SkAssertResult(SkParsePath::FromSVGString("M 0 0 Q 0 0 0 0", &fQuadPath));
     96         SkAssertResult(SkParsePath::FromSVGString("M 0 0 L 0 0", &fLinePath));
     97 
     98         for (int i = 0; i < 3; ++i) {
     99             fRefPath[0].addCircle(i * 10.f, 0, 5);
    100             fRefPath[1].addCircle(i * 10.f, 0, 10);
    101             fRefPath[2].addRect(i * 10.f - 4, -2, i * 10.f + 4, 6);
    102             fRefPath[3].addRect(i * 10.f - 10, -10, i * 10.f + 10, 10);
    103         }
    104     }
    105 
    106     SkString onShortName() override {
    107         return SkString("zeroPath");
    108     }
    109 
    110     SkISize onISize() override {
    111         return SkISize::Make(W, H*2);
    112     }
    113 
    114     void onDraw(SkCanvas* canvas) override {
    115         SkPaint fillPaint, strokePaint, dashPaint;
    116         fillPaint.setAntiAlias(true);
    117         strokePaint = fillPaint;
    118         strokePaint.setStyle(SkPaint::kStroke_Style);
    119         for (int i = 0; i < 2; ++i) {
    120             fillPaint.setAlpha(255);
    121             strokePaint.setAlpha(255);
    122             strokePaint.setStrokeWidth(i ? 8.f : 10.f);
    123             strokePaint.setStrokeCap(i ? SkPaint::kSquare_Cap : SkPaint::kRound_Cap);
    124             canvas->save();
    125             canvas->translate(10 + i * 100.f, 10);
    126             canvas->drawPath(fMoveHfPath, strokePaint);
    127             canvas->translate(0, 20);
    128             canvas->drawPath(fMoveZfPath, strokePaint);
    129             dashPaint = strokePaint;
    130             const SkScalar intervals[] = { 0, 10 };
    131             dashPaint.setPathEffect(SkDashPathEffect::Create(intervals, 2, 0))->unref();
    132             SkPath fillPath;
    133             dashPaint.getFillPath(fDashedfPath, &fillPath);
    134             canvas->translate(0, 20);
    135             canvas->drawPath(fDashedfPath, dashPaint);
    136             canvas->translate(0, 20);
    137             canvas->drawPath(fRefPath[i * 2], fillPaint);
    138             strokePaint.setStrokeWidth(20);
    139             strokePaint.setAlpha(127);
    140             canvas->translate(0, 50);
    141             canvas->drawPath(fMoveHfPath, strokePaint);
    142             canvas->translate(0, 30);
    143             canvas->drawPath(fMoveZfPath, strokePaint);
    144             canvas->translate(0, 30);
    145             fillPaint.setAlpha(127);
    146             canvas->drawPath(fRefPath[1 + i * 2], fillPaint);
    147             canvas->translate(0, 30);
    148             canvas->drawPath(fCubicPath, strokePaint);
    149             canvas->translate(0, 30);
    150             canvas->drawPath(fQuadPath, strokePaint);
    151             canvas->translate(0, 30);
    152             canvas->drawPath(fLinePath, strokePaint);
    153             canvas->restore();
    154         }
    155     }
    156 
    157 private:
    158     typedef skiagm::GM INHERITED;
    159 };
    160 
    161 class TeenyStrokesGM : public skiagm::GM {
    162 
    163     SkString onShortName() override {
    164         return SkString("teenyStrokes");
    165     }
    166 
    167     SkISize onISize() override {
    168         return SkISize::Make(W, H*2);
    169     }
    170 
    171     static void line(SkScalar scale, SkCanvas* canvas, SkColor color) {
    172         SkPaint p;
    173         p.setAntiAlias(true);
    174         p.setStyle(SkPaint::kStroke_Style);
    175         p.setColor(color);
    176         canvas->translate(50, 0);
    177 	    canvas->save();
    178         p.setStrokeWidth(scale * 5);
    179 	    canvas->scale(1 / scale, 1 / scale);
    180         canvas->drawLine(20 * scale, 20 * scale, 20 * scale, 100 * scale, p);
    181         canvas->drawLine(20 * scale, 20 * scale, 100 * scale, 100 * scale, p);
    182         canvas->restore();
    183     }
    184 
    185     void onDraw(SkCanvas* canvas) override {
    186         line(0.00005f, canvas, SK_ColorBLACK);
    187         line(0.000045f, canvas, SK_ColorRED);
    188         line(0.0000035f, canvas, SK_ColorGREEN);
    189         line(0.000003f, canvas, SK_ColorBLUE);
    190         line(0.000002f, canvas, SK_ColorBLACK);
    191     }
    192 private:
    193     typedef skiagm::GM INHERITED;
    194 };
    195 
    196 DEF_SIMPLE_GM(CubicStroke, canvas, 384, 384) {
    197     SkPaint p;
    198     p.setAntiAlias(true);
    199     p.setStyle(SkPaint::kStroke_Style);
    200     p.setStrokeWidth(1.0720f);
    201 	SkPath path;
    202     path.moveTo(-6000,-6000);
    203     path.cubicTo(-3500,5500,-500,5500,2500,-6500);
    204     canvas->drawPath(path, p);
    205     p.setStrokeWidth(1.0721f);
    206     canvas->translate(10, 10);
    207     canvas->drawPath(path, p);
    208     p.setStrokeWidth(1.0722f);
    209     canvas->translate(10, 10);
    210     canvas->drawPath(path, p);
    211 }
    212 
    213 DEF_SIMPLE_GM(zerolinestroke, canvas, 90, 120) {
    214     SkPaint paint;
    215     paint.setStyle(SkPaint::kStroke_Style);
    216     paint.setStrokeWidth(20);
    217     paint.setAntiAlias(true);
    218     paint.setStrokeCap(SkPaint::kRound_Cap);
    219 
    220     SkPath path;
    221     path.moveTo(30, 90);
    222     path.lineTo(30, 90);
    223     path.lineTo(60, 90);
    224     path.lineTo(60, 90);
    225     canvas->drawPath(path, paint);
    226 
    227     path.reset();
    228     path.moveTo(30, 30);
    229     path.lineTo(60, 30);
    230     canvas->drawPath(path, paint);
    231 
    232     path.reset();
    233     path.moveTo(30, 60);
    234     path.lineTo(30, 60);
    235     path.lineTo(60, 60);
    236     canvas->drawPath(path, paint);
    237 }
    238 
    239 DEF_SIMPLE_GM(quadcap, canvas, 200, 200) {
    240     SkPaint p;
    241     p.setAntiAlias(true);
    242     p.setStyle(SkPaint::kStroke_Style);
    243     p.setStrokeWidth(0);
    244     SkPath path;
    245     SkPoint pts[] = {{105.738571f,13.126318f},
    246             {105.738571f,13.126318f},
    247             {123.753784f,1.f}};
    248     SkVector tangent = pts[1] - pts[2];
    249     tangent.normalize();
    250     SkPoint pts2[3];
    251     memcpy(pts2, pts, sizeof(pts));
    252     const SkScalar capOutset = SK_ScalarPI / 8;
    253     pts2[0].fX += tangent.fX * capOutset;
    254     pts2[0].fY += tangent.fY * capOutset;
    255     pts2[1].fX += tangent.fX * capOutset;
    256     pts2[1].fY += tangent.fY * capOutset;
    257     pts2[2].fX += -tangent.fX * capOutset;
    258     pts2[2].fY += -tangent.fY * capOutset;
    259     path.moveTo(pts2[0]);
    260     path.quadTo(pts2[1], pts2[2]);
    261     canvas->drawPath(path, p);
    262 
    263     path.reset();
    264     path.moveTo(pts[0]);
    265     path.quadTo(pts[1], pts[2]);
    266     p.setStrokeCap(SkPaint::kRound_Cap);
    267     canvas->translate(30, 0);
    268     canvas->drawPath(path, p);
    269 }
    270 
    271 class Strokes2GM : public skiagm::GM {
    272     SkPath fPath;
    273 protected:
    274     void onOnceBeforeDraw() override {
    275         SkRandom rand;
    276         fPath.moveTo(0, 0);
    277         for (int i = 0; i < 13; i++) {
    278             SkScalar x = rand.nextUScalar1() * (W >> 1);
    279             SkScalar y = rand.nextUScalar1() * (H >> 1);
    280             fPath.lineTo(x, y);
    281         }
    282     }
    283 
    284 
    285     SkString onShortName() override {
    286         return SkString("strokes_poly");
    287     }
    288 
    289     SkISize onISize() override {
    290         return SkISize::Make(W, H*2);
    291     }
    292 
    293     static void rotate(SkScalar angle, SkScalar px, SkScalar py, SkCanvas* canvas) {
    294         SkMatrix matrix;
    295         matrix.setRotate(angle, px, py);
    296         canvas->concat(matrix);
    297     }
    298 
    299     void onDraw(SkCanvas* canvas) override {
    300         canvas->drawColor(SK_ColorWHITE);
    301 
    302         SkPaint paint;
    303         paint.setStyle(SkPaint::kStroke_Style);
    304         paint.setStrokeWidth(SkIntToScalar(9)/2);
    305 
    306         for (int y = 0; y < 2; y++) {
    307             paint.setAntiAlias(!!y);
    308             SkAutoCanvasRestore acr(canvas, true);
    309             canvas->translate(0, SH * y);
    310             canvas->clipRect(SkRect::MakeLTRB(SkIntToScalar(2),
    311                                               SkIntToScalar(2),
    312                                               SW - SkIntToScalar(2),
    313                                               SH - SkIntToScalar(2)));
    314 
    315             SkRandom rand;
    316             for (int i = 0; i < N/2; i++) {
    317                 SkRect r;
    318                 rnd_rect(&r, &paint, rand);
    319                 rotate(SkIntToScalar(15), SW/2, SH/2, canvas);
    320                 canvas->drawPath(fPath, paint);
    321             }
    322         }
    323     }
    324 
    325 private:
    326     typedef skiagm::GM INHERITED;
    327 };
    328 
    329 //////////////////////////////////////////////////////////////////////////////
    330 
    331 static SkRect inset(const SkRect& r) {
    332     SkRect rr(r);
    333     rr.inset(r.width()/10, r.height()/10);
    334     return rr;
    335 }
    336 
    337 class Strokes3GM : public skiagm::GM {
    338     static void make0(SkPath* path, const SkRect& bounds, SkString* title) {
    339         path->addRect(bounds, SkPath::kCW_Direction);
    340         path->addRect(inset(bounds), SkPath::kCW_Direction);
    341         title->set("CW CW");
    342     }
    343 
    344     static void make1(SkPath* path, const SkRect& bounds, SkString* title) {
    345         path->addRect(bounds, SkPath::kCW_Direction);
    346         path->addRect(inset(bounds), SkPath::kCCW_Direction);
    347         title->set("CW CCW");
    348     }
    349 
    350     static void make2(SkPath* path, const SkRect& bounds, SkString* title) {
    351         path->addOval(bounds, SkPath::kCW_Direction);
    352         path->addOval(inset(bounds), SkPath::kCW_Direction);
    353         title->set("CW CW");
    354     }
    355 
    356     static void make3(SkPath* path, const SkRect& bounds, SkString* title) {
    357         path->addOval(bounds, SkPath::kCW_Direction);
    358         path->addOval(inset(bounds), SkPath::kCCW_Direction);
    359         title->set("CW CCW");
    360     }
    361 
    362     static void make4(SkPath* path, const SkRect& bounds, SkString* title) {
    363         path->addRect(bounds, SkPath::kCW_Direction);
    364         SkRect r = bounds;
    365         r.inset(bounds.width() / 10, -bounds.height() / 10);
    366         path->addOval(r, SkPath::kCW_Direction);
    367         title->set("CW CW");
    368     }
    369 
    370     static void make5(SkPath* path, const SkRect& bounds, SkString* title) {
    371         path->addRect(bounds, SkPath::kCW_Direction);
    372         SkRect r = bounds;
    373         r.inset(bounds.width() / 10, -bounds.height() / 10);
    374         path->addOval(r, SkPath::kCCW_Direction);
    375         title->set("CW CCW");
    376     }
    377 
    378 public:
    379     Strokes3GM() {}
    380 
    381 protected:
    382 
    383     SkString onShortName() override {
    384         return SkString("strokes3");
    385     }
    386 
    387     SkISize onISize() override {
    388         return SkISize::Make(1500, 1500);
    389     }
    390 
    391     void onDraw(SkCanvas* canvas) override {
    392         SkPaint origPaint;
    393         origPaint.setAntiAlias(true);
    394         origPaint.setStyle(SkPaint::kStroke_Style);
    395         SkPaint fillPaint(origPaint);
    396         fillPaint.setColor(SK_ColorRED);
    397         SkPaint strokePaint(origPaint);
    398         strokePaint.setColor(sk_tool_utils::color_to_565(0xFF4444FF));
    399 
    400         void (*procs[])(SkPath*, const SkRect&, SkString*) = {
    401             make0, make1, make2, make3, make4, make5
    402         };
    403 
    404         canvas->translate(SkIntToScalar(20), SkIntToScalar(80));
    405 
    406         SkRect bounds = SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(50));
    407         SkScalar dx = bounds.width() * 4/3;
    408         SkScalar dy = bounds.height() * 5;
    409 
    410         for (size_t i = 0; i < SK_ARRAY_COUNT(procs); ++i) {
    411             SkPath orig;
    412             SkString str;
    413             procs[i](&orig, bounds, &str);
    414 
    415             canvas->save();
    416             for (int j = 0; j < 13; ++j) {
    417                 strokePaint.setStrokeWidth(SK_Scalar1 * j * j);
    418                 canvas->drawPath(orig, strokePaint);
    419                 canvas->drawPath(orig, origPaint);
    420                 SkPath fill;
    421                 strokePaint.getFillPath(orig, &fill);
    422                 canvas->drawPath(fill, fillPaint);
    423                 canvas->translate(dx + strokePaint.getStrokeWidth(), 0);
    424             }
    425             canvas->restore();
    426             canvas->translate(0, dy);
    427         }
    428     }
    429 
    430 private:
    431     typedef skiagm::GM INHERITED;
    432 };
    433 
    434 class Strokes4GM : public skiagm::GM {
    435 public:
    436     Strokes4GM() {}
    437 
    438 protected:
    439 
    440     SkString onShortName() override {
    441         return SkString("strokes_zoomed");
    442     }
    443 
    444     SkISize onISize() override {
    445         return SkISize::Make(W, H*2);
    446     }
    447 
    448     void onDraw(SkCanvas* canvas) override {
    449         SkPaint paint;
    450         paint.setStyle(SkPaint::kStroke_Style);
    451         paint.setStrokeWidth(0.055f);
    452 
    453         canvas->scale(1000, 1000);
    454         canvas->drawCircle(0, 2, 1.97f, paint);
    455     }
    456 
    457 private:
    458     typedef skiagm::GM INHERITED;
    459 };
    460 
    461 // Test stroking for curves that produce degenerate tangents when t is 0 or 1 (see bug 4191)
    462 class Strokes5GM : public skiagm::GM {
    463 public:
    464     Strokes5GM() {}
    465 
    466 protected:
    467 
    468     SkString onShortName() override {
    469         return SkString("zero_control_stroke");
    470     }
    471 
    472     SkISize onISize() override {
    473         return SkISize::Make(W, H*2);
    474     }
    475 
    476     void onDraw(SkCanvas* canvas) override {
    477         SkPaint p;
    478         p.setColor(SK_ColorRED);
    479         p.setAntiAlias(true);
    480         p.setStyle(SkPaint::kStroke_Style);
    481         p.setStrokeWidth(40);
    482         p.setStrokeCap(SkPaint::kButt_Cap);
    483 
    484         SkPath path;
    485         path.moveTo(157.474f,111.753f);
    486         path.cubicTo(128.5f,111.5f,35.5f,29.5f,35.5f,29.5f);
    487         canvas->drawPath(path, p);
    488         path.reset();
    489         path.moveTo(250, 50);
    490         path.quadTo(280, 80, 280, 80);
    491         canvas->drawPath(path, p);
    492         path.reset();
    493         path.moveTo(150, 50);
    494         path.conicTo(180, 80, 180, 80, 0.707f);
    495         canvas->drawPath(path, p);
    496 
    497         path.reset();
    498         path.moveTo(157.474f,311.753f);
    499         path.cubicTo(157.474f,311.753f,85.5f,229.5f,35.5f,229.5f);
    500         canvas->drawPath(path, p);
    501         path.reset();
    502         path.moveTo(280, 250);
    503         path.quadTo(280, 250, 310, 280);
    504         canvas->drawPath(path, p);
    505         path.reset();
    506         path.moveTo(180, 250);
    507         path.conicTo(180, 250, 210, 280, 0.707f);
    508         canvas->drawPath(path, p);
    509     }
    510 
    511 private:
    512     typedef skiagm::GM INHERITED;
    513 };
    514 
    515 
    516 //////////////////////////////////////////////////////////////////////////////
    517 
    518 DEF_GM( return new StrokesGM; )
    519 DEF_GM( return new Strokes2GM; )
    520 DEF_GM( return new Strokes3GM; )
    521 DEF_GM( return new Strokes4GM; )
    522 DEF_GM( return new Strokes5GM; )
    523 
    524 DEF_GM( return new ZeroLenStrokesGM; )
    525 DEF_GM( return new TeenyStrokesGM; )
    526