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