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 #include "gm.h"
      8 #include "SkCanvas.h"
      9 #include "SkPaint.h"
     10 #include "SkRandom.h"
     11 
     12 // skbug.com/1316 shows that this cubic, when slightly clipped, creates big
     13 // (incorrect) changes to its control points.
     14 class ClippedCubicGM : public skiagm::GM {
     15 public:
     16     ClippedCubicGM() {}
     17 
     18 protected:
     19     virtual uint32_t onGetFlags() const SK_OVERRIDE {
     20         return kSkipTiled_Flag;
     21     }
     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 class CubicPathGM : public skiagm::GM {
     58 public:
     59     CubicPathGM() {}
     60 
     61 protected:
     62     virtual uint32_t onGetFlags() const SK_OVERRIDE {
     63         return kSkipTiled_Flag;
     64     }
     65 
     66     SkString onShortName() {
     67         return SkString("cubicpath");
     68     }
     69 
     70     SkISize onISize() { return SkISize::Make(1240, 390); }
     71 
     72     void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
     73                   const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
     74                   SkPaint::Style style, SkPath::FillType fill,
     75                   SkScalar strokeWidth) {
     76         path.setFillType(fill);
     77         SkPaint paint;
     78         paint.setStrokeCap(cap);
     79         paint.setStrokeWidth(strokeWidth);
     80         paint.setStrokeJoin(join);
     81         paint.setColor(color);
     82         paint.setStyle(style);
     83         canvas->save();
     84         canvas->clipRect(clip);
     85         canvas->drawPath(path, paint);
     86         canvas->restore();
     87     }
     88 
     89     virtual void onDraw(SkCanvas* canvas) {
     90         struct FillAndName {
     91             SkPath::FillType fFill;
     92             const char*      fName;
     93         };
     94         static const FillAndName gFills[] = {
     95             {SkPath::kWinding_FillType, "Winding"},
     96             {SkPath::kEvenOdd_FillType, "Even / Odd"},
     97             {SkPath::kInverseWinding_FillType, "Inverse Winding"},
     98             {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
     99         };
    100         struct StyleAndName {
    101             SkPaint::Style fStyle;
    102             const char*    fName;
    103         };
    104         static const StyleAndName gStyles[] = {
    105             {SkPaint::kFill_Style, "Fill"},
    106             {SkPaint::kStroke_Style, "Stroke"},
    107             {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
    108         };
    109         struct CapAndName {
    110             SkPaint::Cap  fCap;
    111             SkPaint::Join fJoin;
    112             const char*   fName;
    113         };
    114         static const CapAndName gCaps[] = {
    115             {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
    116             {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
    117             {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
    118         };
    119         struct PathAndName {
    120             SkPath      fPath;
    121             const char* fName;
    122         };
    123         PathAndName path;
    124         path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
    125         path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
    126                            60*SK_Scalar1, 20*SK_Scalar1,
    127                            75*SK_Scalar1, 10*SK_Scalar1);
    128         path.fName = "moveTo-cubic";
    129 
    130         SkPaint titlePaint;
    131         titlePaint.setColor(SK_ColorBLACK);
    132         titlePaint.setAntiAlias(true);
    133         sk_tool_utils::set_portable_typeface(&titlePaint);
    134         titlePaint.setLCDRenderText(true);
    135         titlePaint.setTextSize(15 * SK_Scalar1);
    136         const char title[] = "Cubic Drawn Into Rectangle Clips With "
    137                              "Indicated Style, Fill and Linecaps, with stroke width 10";
    138         canvas->drawText(title, strlen(title),
    139                             20 * SK_Scalar1,
    140                             20 * SK_Scalar1,
    141                             titlePaint);
    142 
    143         SkLCGRandom rand;
    144         SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
    145         canvas->save();
    146         canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
    147         canvas->save();
    148         for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
    149             if (0 < cap) {
    150                 canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
    151             }
    152             canvas->save();
    153             for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
    154                 if (0 < fill) {
    155                     canvas->translate(0, rect.height() + 40 * SK_Scalar1);
    156                 }
    157                 canvas->save();
    158                 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
    159                     if (0 < style) {
    160                         canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
    161                     }
    162 
    163                     SkColor color = 0xff007000;
    164                     this->drawPath(path.fPath, canvas, color, rect,
    165                                     gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
    166                                     gFills[fill].fFill, SK_Scalar1*10);
    167 
    168                     SkPaint rectPaint;
    169                     rectPaint.setColor(SK_ColorBLACK);
    170                     rectPaint.setStyle(SkPaint::kStroke_Style);
    171                     rectPaint.setStrokeWidth(-1);
    172                     rectPaint.setAntiAlias(true);
    173                     canvas->drawRect(rect, rectPaint);
    174 
    175                     SkPaint labelPaint;
    176                     labelPaint.setColor(color);
    177                     labelPaint.setAntiAlias(true);
    178                     sk_tool_utils::set_portable_typeface(&labelPaint);
    179                     labelPaint.setLCDRenderText(true);
    180                     labelPaint.setTextSize(10 * SK_Scalar1);
    181                     canvas->drawText(gStyles[style].fName,
    182                                         strlen(gStyles[style].fName),
    183                                         0, rect.height() + 12 * SK_Scalar1,
    184                                         labelPaint);
    185                     canvas->drawText(gFills[fill].fName,
    186                                         strlen(gFills[fill].fName),
    187                                         0, rect.height() + 24 * SK_Scalar1,
    188                                         labelPaint);
    189                     canvas->drawText(gCaps[cap].fName,
    190                                         strlen(gCaps[cap].fName),
    191                                         0, rect.height() + 36 * SK_Scalar1,
    192                                         labelPaint);
    193                 }
    194                 canvas->restore();
    195             }
    196             canvas->restore();
    197         }
    198         canvas->restore();
    199         canvas->restore();
    200     }
    201 
    202 private:
    203     typedef skiagm::GM INHERITED;
    204 };
    205 
    206 class CubicClosePathGM : public skiagm::GM {
    207 public:
    208     CubicClosePathGM() {}
    209 
    210 protected:
    211     virtual uint32_t onGetFlags() const SK_OVERRIDE {
    212         return kSkipTiled_Flag;
    213     }
    214 
    215     SkString onShortName() {
    216         return SkString("cubicclosepath");
    217     }
    218 
    219     SkISize onISize() { return SkISize::Make(1240, 390); }
    220 
    221     void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
    222                   const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
    223                   SkPaint::Style style, SkPath::FillType fill,
    224                   SkScalar strokeWidth) {
    225         path.setFillType(fill);
    226         SkPaint paint;
    227         paint.setStrokeCap(cap);
    228         paint.setStrokeWidth(strokeWidth);
    229         paint.setStrokeJoin(join);
    230         paint.setColor(color);
    231         paint.setStyle(style);
    232         canvas->save();
    233         canvas->clipRect(clip);
    234         canvas->drawPath(path, paint);
    235         canvas->restore();
    236     }
    237 
    238     virtual void onDraw(SkCanvas* canvas) {
    239         struct FillAndName {
    240             SkPath::FillType fFill;
    241             const char*      fName;
    242         };
    243         static const FillAndName gFills[] = {
    244             {SkPath::kWinding_FillType, "Winding"},
    245             {SkPath::kEvenOdd_FillType, "Even / Odd"},
    246             {SkPath::kInverseWinding_FillType, "Inverse Winding"},
    247             {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
    248         };
    249         struct StyleAndName {
    250             SkPaint::Style fStyle;
    251             const char*    fName;
    252         };
    253         static const StyleAndName gStyles[] = {
    254             {SkPaint::kFill_Style, "Fill"},
    255             {SkPaint::kStroke_Style, "Stroke"},
    256             {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
    257         };
    258         struct CapAndName {
    259             SkPaint::Cap  fCap;
    260             SkPaint::Join fJoin;
    261             const char*   fName;
    262         };
    263         static const CapAndName gCaps[] = {
    264             {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
    265             {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
    266             {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
    267         };
    268         struct PathAndName {
    269             SkPath      fPath;
    270             const char* fName;
    271         };
    272         PathAndName path;
    273         path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
    274         path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
    275                            60*SK_Scalar1, 20*SK_Scalar1,
    276                            75*SK_Scalar1, 10*SK_Scalar1);
    277         path.fPath.close();
    278         path.fName = "moveTo-cubic-close";
    279 
    280         SkPaint titlePaint;
    281         titlePaint.setColor(SK_ColorBLACK);
    282         titlePaint.setAntiAlias(true);
    283         sk_tool_utils::set_portable_typeface(&titlePaint);
    284         titlePaint.setLCDRenderText(true);
    285         titlePaint.setTextSize(15 * SK_Scalar1);
    286         const char title[] = "Cubic Closed Drawn Into Rectangle Clips With "
    287                              "Indicated Style, Fill and Linecaps, with stroke width 10";
    288         canvas->drawText(title, strlen(title),
    289                             20 * SK_Scalar1,
    290                             20 * SK_Scalar1,
    291                             titlePaint);
    292 
    293         SkLCGRandom rand;
    294         SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
    295         canvas->save();
    296         canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
    297         canvas->save();
    298         for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
    299             if (0 < cap) {
    300                 canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
    301             }
    302             canvas->save();
    303             for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
    304                 if (0 < fill) {
    305                     canvas->translate(0, rect.height() + 40 * SK_Scalar1);
    306                 }
    307                 canvas->save();
    308                 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
    309                     if (0 < style) {
    310                         canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
    311                     }
    312 
    313                     SkColor color = 0xff007000;
    314                     this->drawPath(path.fPath, canvas, color, rect,
    315                                     gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
    316                                     gFills[fill].fFill, SK_Scalar1*10);
    317 
    318                     SkPaint rectPaint;
    319                     rectPaint.setColor(SK_ColorBLACK);
    320                     rectPaint.setStyle(SkPaint::kStroke_Style);
    321                     rectPaint.setStrokeWidth(-1);
    322                     rectPaint.setAntiAlias(true);
    323                     canvas->drawRect(rect, rectPaint);
    324 
    325                     SkPaint labelPaint;
    326                     labelPaint.setColor(color);
    327                     labelPaint.setAntiAlias(true);
    328                     sk_tool_utils::set_portable_typeface(&labelPaint);
    329                     labelPaint.setLCDRenderText(true);
    330                     labelPaint.setTextSize(10 * SK_Scalar1);
    331                     canvas->drawText(gStyles[style].fName,
    332                                         strlen(gStyles[style].fName),
    333                                         0, rect.height() + 12 * SK_Scalar1,
    334                                         labelPaint);
    335                     canvas->drawText(gFills[fill].fName,
    336                                         strlen(gFills[fill].fName),
    337                                         0, rect.height() + 24 * SK_Scalar1,
    338                                         labelPaint);
    339                     canvas->drawText(gCaps[cap].fName,
    340                                         strlen(gCaps[cap].fName),
    341                                         0, rect.height() + 36 * SK_Scalar1,
    342                                         labelPaint);
    343                 }
    344                 canvas->restore();
    345             }
    346             canvas->restore();
    347         }
    348         canvas->restore();
    349         canvas->restore();
    350     }
    351 
    352 private:
    353     typedef skiagm::GM INHERITED;
    354 };
    355 
    356 //////////////////////////////////////////////////////////////////////////////
    357 
    358 DEF_GM( return new CubicPathGM; )
    359 DEF_GM( return new CubicClosePathGM; )
    360 DEF_GM( return new ClippedCubicGM; )
    361