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 "sk_tool_utils.h"
     10 #include "SkCanvas.h"
     11 #include "SkPaint.h"
     12 #include "SkPath.h"
     13 #include "SkRandom.h"
     14 
     15 // https://bug.skia.org/1316 shows that this cubic, when slightly clipped, creates big
     16 // (incorrect) changes to its control points.
     17 class ClippedCubicGM : public skiagm::GM {
     18 public:
     19     ClippedCubicGM() {}
     20 
     21 protected:
     22 
     23     SkString onShortName() {
     24         return SkString("clippedcubic");
     25     }
     26 
     27     SkISize onISize() { return SkISize::Make(1240, 390); }
     28 
     29     virtual void onDraw(SkCanvas* canvas) {
     30         SkPath path;
     31         path.moveTo(0, 0);
     32         path.cubicTo(140, 150, 40, 10, 170, 150);
     33 
     34         SkPaint paint;
     35         SkRect bounds = path.getBounds();
     36 
     37         for (SkScalar dy = -1; dy <= 1; dy += 1) {
     38             canvas->save();
     39             for (SkScalar dx = -1; dx <= 1; dx += 1) {
     40                 canvas->save();
     41                 canvas->clipRect(bounds);
     42                 canvas->translate(dx, dy);
     43                 canvas->drawPath(path, paint);
     44                 canvas->restore();
     45 
     46                 canvas->translate(bounds.width(), 0);
     47             }
     48             canvas->restore();
     49             canvas->translate(0, bounds.height());
     50         }
     51     }
     52 
     53 private:
     54     typedef skiagm::GM INHERITED;
     55 };
     56 
     57 
     58 class ClippedCubic2GM : public skiagm::GM {
     59 public:
     60     ClippedCubic2GM() {}
     61 
     62 protected:
     63 
     64     SkString onShortName() override {
     65         return SkString("clippedcubic2");
     66     }
     67 
     68     SkISize onISize() override { return SkISize::Make(1240, 390); }
     69 
     70     void onDraw(SkCanvas* canvas) override {
     71         canvas->save();
     72         canvas->translate(-2, 120);
     73         drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 80, 150));
     74         canvas->translate(0, 170);
     75         drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 80, 100));
     76         canvas->translate(0, 170);
     77         drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 30, 150));
     78         canvas->translate(0, 170);
     79         drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 10, 150));
     80         canvas->restore();
     81         canvas->save();
     82         canvas->translate(20, -2);
     83         drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 150, 80));
     84         canvas->translate(170, 0);
     85         drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 100, 80));
     86         canvas->translate(170, 0);
     87         drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 150, 30));
     88         canvas->translate(170, 0);
     89         drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 150, 10));
     90         canvas->restore();
     91     }
     92 
     93     void drawOne(SkCanvas* canvas, const SkPath& path, const SkRect& clip) {
     94         SkPaint framePaint, fillPaint;
     95         framePaint.setStyle(SkPaint::kStroke_Style);
     96         canvas->drawRect(clip, framePaint);
     97         canvas->drawPath(path, framePaint);
     98         canvas->save();
     99         canvas->clipRect(clip);
    100         canvas->drawPath(path, fillPaint);
    101         canvas->restore();
    102     }
    103 
    104     void onOnceBeforeDraw() override {
    105         fPath.moveTo(69.7030518991886f, 0);
    106         fPath.cubicTo( 69.7030518991886f, 21.831149999999997f,
    107                 58.08369508178456f, 43.66448333333333f, 34.8449814469765f, 65.5f);
    108         fPath.cubicTo( 11.608591683531916f, 87.33115f, -0.010765133872116195f, 109.16448333333332f,
    109                 -0.013089005235602302f, 131);
    110         fPath.close();
    111         fFlipped = fPath;
    112         SkMatrix matrix;
    113         matrix.reset();
    114         matrix.setScaleX(0);
    115         matrix.setScaleY(0);
    116         matrix.setSkewX(1);
    117         matrix.setSkewY(1);
    118         fFlipped.transform(matrix);
    119     }
    120 
    121     SkPath fPath;
    122     SkPath fFlipped;
    123 private:
    124     typedef skiagm::GM INHERITED;
    125 };
    126 
    127 
    128 class CubicPathGM : public skiagm::GM {
    129 public:
    130     CubicPathGM() {}
    131 
    132 protected:
    133 
    134     SkString onShortName() {
    135         return SkString("cubicpath");
    136     }
    137 
    138     SkISize onISize() { return SkISize::Make(1240, 390); }
    139 
    140     void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
    141                   const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
    142                   SkPaint::Style style, SkPath::FillType fill,
    143                   SkScalar strokeWidth) {
    144         path.setFillType(fill);
    145         SkPaint paint;
    146         paint.setStrokeCap(cap);
    147         paint.setStrokeWidth(strokeWidth);
    148         paint.setStrokeJoin(join);
    149         paint.setColor(color);
    150         paint.setStyle(style);
    151         canvas->save();
    152         canvas->clipRect(clip);
    153         canvas->drawPath(path, paint);
    154         canvas->restore();
    155     }
    156 
    157     virtual void onDraw(SkCanvas* canvas) {
    158         struct FillAndName {
    159             SkPath::FillType fFill;
    160             const char*      fName;
    161         };
    162         constexpr FillAndName gFills[] = {
    163             {SkPath::kWinding_FillType, "Winding"},
    164             {SkPath::kEvenOdd_FillType, "Even / Odd"},
    165             {SkPath::kInverseWinding_FillType, "Inverse Winding"},
    166             {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
    167         };
    168         struct StyleAndName {
    169             SkPaint::Style fStyle;
    170             const char*    fName;
    171         };
    172         constexpr StyleAndName gStyles[] = {
    173             {SkPaint::kFill_Style, "Fill"},
    174             {SkPaint::kStroke_Style, "Stroke"},
    175             {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
    176         };
    177         struct CapAndName {
    178             SkPaint::Cap  fCap;
    179             SkPaint::Join fJoin;
    180             const char*   fName;
    181         };
    182         constexpr CapAndName gCaps[] = {
    183             {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
    184             {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
    185             {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
    186         };
    187         struct PathAndName {
    188             SkPath      fPath;
    189             const char* fName;
    190         };
    191         PathAndName path;
    192         path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
    193         path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
    194                            60*SK_Scalar1, 20*SK_Scalar1,
    195                            75*SK_Scalar1, 10*SK_Scalar1);
    196         path.fName = "moveTo-cubic";
    197 
    198         SkPaint titlePaint;
    199         titlePaint.setColor(SK_ColorBLACK);
    200         titlePaint.setAntiAlias(true);
    201         sk_tool_utils::set_portable_typeface(&titlePaint);
    202         titlePaint.setTextSize(15 * SK_Scalar1);
    203         const char title[] = "Cubic Drawn Into Rectangle Clips With "
    204                              "Indicated Style, Fill and Linecaps, with stroke width 10";
    205         canvas->drawString(title,
    206                            20 * SK_Scalar1,
    207                            20 * SK_Scalar1,
    208                            titlePaint);
    209 
    210         SkRandom rand;
    211         SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
    212         canvas->save();
    213         canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
    214         canvas->save();
    215         for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
    216             if (0 < cap) {
    217                 canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
    218             }
    219             canvas->save();
    220             for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
    221                 if (0 < fill) {
    222                     canvas->translate(0, rect.height() + 40 * SK_Scalar1);
    223                 }
    224                 canvas->save();
    225                 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
    226                     if (0 < style) {
    227                         canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
    228                     }
    229 
    230                     SkColor color = 0xff007000;
    231                     this->drawPath(path.fPath, canvas, color, rect,
    232                                     gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
    233                                     gFills[fill].fFill, SK_Scalar1*10);
    234 
    235                     SkPaint rectPaint;
    236                     rectPaint.setColor(SK_ColorBLACK);
    237                     rectPaint.setStyle(SkPaint::kStroke_Style);
    238                     rectPaint.setStrokeWidth(-1);
    239                     rectPaint.setAntiAlias(true);
    240                     canvas->drawRect(rect, rectPaint);
    241 
    242                     SkPaint labelPaint;
    243                     labelPaint.setColor(color);
    244                     labelPaint.setAntiAlias(true);
    245                     sk_tool_utils::set_portable_typeface(&labelPaint);
    246                     labelPaint.setTextSize(10 * SK_Scalar1);
    247                     canvas->drawString(gStyles[style].fName,
    248                                        0, rect.height() + 12 * SK_Scalar1,
    249                                        labelPaint);
    250                     canvas->drawString(gFills[fill].fName,
    251                                        0, rect.height() + 24 * SK_Scalar1,
    252                                        labelPaint);
    253                     canvas->drawString(gCaps[cap].fName,
    254                                        0, rect.height() + 36 * SK_Scalar1,
    255                                        labelPaint);
    256                 }
    257                 canvas->restore();
    258             }
    259             canvas->restore();
    260         }
    261         canvas->restore();
    262         canvas->restore();
    263     }
    264 
    265 private:
    266     typedef skiagm::GM INHERITED;
    267 };
    268 
    269 class CubicClosePathGM : public skiagm::GM {
    270 public:
    271     CubicClosePathGM() {}
    272 
    273 protected:
    274 
    275     SkString onShortName() {
    276         return SkString("cubicclosepath");
    277     }
    278 
    279     SkISize onISize() { return SkISize::Make(1240, 390); }
    280 
    281     void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
    282                   const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
    283                   SkPaint::Style style, SkPath::FillType fill,
    284                   SkScalar strokeWidth) {
    285         path.setFillType(fill);
    286         SkPaint paint;
    287         paint.setStrokeCap(cap);
    288         paint.setStrokeWidth(strokeWidth);
    289         paint.setStrokeJoin(join);
    290         paint.setColor(color);
    291         paint.setStyle(style);
    292         canvas->save();
    293         canvas->clipRect(clip);
    294         canvas->drawPath(path, paint);
    295         canvas->restore();
    296     }
    297 
    298     virtual void onDraw(SkCanvas* canvas) {
    299         struct FillAndName {
    300             SkPath::FillType fFill;
    301             const char*      fName;
    302         };
    303         constexpr FillAndName gFills[] = {
    304             {SkPath::kWinding_FillType, "Winding"},
    305             {SkPath::kEvenOdd_FillType, "Even / Odd"},
    306             {SkPath::kInverseWinding_FillType, "Inverse Winding"},
    307             {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
    308         };
    309         struct StyleAndName {
    310             SkPaint::Style fStyle;
    311             const char*    fName;
    312         };
    313         constexpr StyleAndName gStyles[] = {
    314             {SkPaint::kFill_Style, "Fill"},
    315             {SkPaint::kStroke_Style, "Stroke"},
    316             {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
    317         };
    318         struct CapAndName {
    319             SkPaint::Cap  fCap;
    320             SkPaint::Join fJoin;
    321             const char*   fName;
    322         };
    323         constexpr CapAndName gCaps[] = {
    324             {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
    325             {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
    326             {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
    327         };
    328         struct PathAndName {
    329             SkPath      fPath;
    330             const char* fName;
    331         };
    332         PathAndName path;
    333         path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
    334         path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
    335                            60*SK_Scalar1, 20*SK_Scalar1,
    336                            75*SK_Scalar1, 10*SK_Scalar1);
    337         path.fPath.close();
    338         path.fName = "moveTo-cubic-close";
    339 
    340         SkPaint titlePaint;
    341         titlePaint.setColor(SK_ColorBLACK);
    342         titlePaint.setAntiAlias(true);
    343         sk_tool_utils::set_portable_typeface(&titlePaint);
    344         titlePaint.setTextSize(15 * SK_Scalar1);
    345         const char title[] = "Cubic Closed Drawn Into Rectangle Clips With "
    346                              "Indicated Style, Fill and Linecaps, with stroke width 10";
    347         canvas->drawString(title,
    348                            20 * SK_Scalar1,
    349                            20 * SK_Scalar1,
    350                            titlePaint);
    351 
    352         SkRandom rand;
    353         SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
    354         canvas->save();
    355         canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
    356         canvas->save();
    357         for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
    358             if (0 < cap) {
    359                 canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
    360             }
    361             canvas->save();
    362             for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
    363                 if (0 < fill) {
    364                     canvas->translate(0, rect.height() + 40 * SK_Scalar1);
    365                 }
    366                 canvas->save();
    367                 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
    368                     if (0 < style) {
    369                         canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
    370                     }
    371 
    372                     SkColor color = 0xff007000;
    373                     this->drawPath(path.fPath, canvas, color, rect,
    374                                     gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
    375                                     gFills[fill].fFill, SK_Scalar1*10);
    376 
    377                     SkPaint rectPaint;
    378                     rectPaint.setColor(SK_ColorBLACK);
    379                     rectPaint.setStyle(SkPaint::kStroke_Style);
    380                     rectPaint.setStrokeWidth(-1);
    381                     rectPaint.setAntiAlias(true);
    382                     canvas->drawRect(rect, rectPaint);
    383 
    384                     SkPaint labelPaint;
    385                     labelPaint.setColor(color);
    386                     labelPaint.setAntiAlias(true);
    387                     sk_tool_utils::set_portable_typeface(&labelPaint);
    388                     labelPaint.setTextSize(10 * SK_Scalar1);
    389                     canvas->drawString(gStyles[style].fName,
    390                                        0, rect.height() + 12 * SK_Scalar1,
    391                                        labelPaint);
    392                     canvas->drawString(gFills[fill].fName,
    393                                        0, rect.height() + 24 * SK_Scalar1,
    394                                        labelPaint);
    395                     canvas->drawString(gCaps[cap].fName,
    396                                        0, rect.height() + 36 * SK_Scalar1,
    397                                        labelPaint);
    398                 }
    399                 canvas->restore();
    400             }
    401             canvas->restore();
    402         }
    403         canvas->restore();
    404         canvas->restore();
    405     }
    406 
    407 private:
    408     typedef skiagm::GM INHERITED;
    409 };
    410 
    411 DEF_SIMPLE_GM(bug5099, canvas, 50, 50) {
    412     SkPaint p;
    413     p.setColor(SK_ColorRED);
    414     p.setAntiAlias(true);
    415     p.setStyle(SkPaint::kStroke_Style);
    416     p.setStrokeWidth(10);
    417 
    418     SkPath path;
    419     path.moveTo(6, 27);
    420     path.cubicTo(31.5f, 1.5f, 3.5f, 4.5f, 29, 29);
    421     canvas->drawPath(path, p);
    422 }
    423 
    424 DEF_SIMPLE_GM(bug6083, canvas, 100, 50) {
    425     SkPaint p;
    426     p.setColor(SK_ColorRED);
    427     p.setAntiAlias(true);
    428     p.setStyle(SkPaint::kStroke_Style);
    429     p.setStrokeWidth(15);
    430     canvas->translate(-500, -130);
    431     SkPath path;
    432     path.moveTo(500.988f, 155.200f);
    433     path.lineTo(526.109f, 155.200f);
    434     SkPoint p1 = { 526.109f, 155.200f };
    435     SkPoint p2 = { 525.968f, 212.968f };
    436     SkPoint p3 = { 526.109f, 241.840f };
    437     path.cubicTo(p1, p2, p3);
    438     canvas->drawPath(path, p);
    439     canvas->translate(50, 0);
    440     path.reset();
    441     p2.set(525.968f, 213.172f);
    442     path.moveTo(500.988f, 155.200f);
    443     path.lineTo(526.109f, 155.200f);
    444     path.cubicTo(p1, p2, p3);
    445     canvas->drawPath(path, p);
    446 }
    447 
    448 //////////////////////////////////////////////////////////////////////////////
    449 
    450 DEF_GM( return new CubicPathGM; )
    451 DEF_GM( return new CubicClosePathGM; )
    452 DEF_GM( return new ClippedCubicGM; )
    453 DEF_GM( return new ClippedCubic2GM; )
    454