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