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         titlePaint.setLCDRenderText(true);
    134         titlePaint.setTextSize(15 * SK_Scalar1);
    135         const char title[] = "Cubic Drawn Into Rectangle Clips With "
    136                              "Indicated Style, Fill and Linecaps, with stroke width 10";
    137         canvas->drawText(title, strlen(title),
    138                             20 * SK_Scalar1,
    139                             20 * SK_Scalar1,
    140                             titlePaint);
    141 
    142         SkLCGRandom rand;
    143         SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
    144         canvas->save();
    145         canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
    146         canvas->save();
    147         for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
    148             if (0 < cap) {
    149                 canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
    150             }
    151             canvas->save();
    152             for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
    153                 if (0 < fill) {
    154                     canvas->translate(0, rect.height() + 40 * SK_Scalar1);
    155                 }
    156                 canvas->save();
    157                 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
    158                     if (0 < style) {
    159                         canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
    160                     }
    161 
    162                     SkColor color = 0xff007000;
    163                     this->drawPath(path.fPath, canvas, color, rect,
    164                                     gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
    165                                     gFills[fill].fFill, SK_Scalar1*10);
    166 
    167                     SkPaint rectPaint;
    168                     rectPaint.setColor(SK_ColorBLACK);
    169                     rectPaint.setStyle(SkPaint::kStroke_Style);
    170                     rectPaint.setStrokeWidth(-1);
    171                     rectPaint.setAntiAlias(true);
    172                     canvas->drawRect(rect, rectPaint);
    173 
    174                     SkPaint labelPaint;
    175                     labelPaint.setColor(color);
    176                     labelPaint.setAntiAlias(true);
    177                     labelPaint.setLCDRenderText(true);
    178                     labelPaint.setTextSize(10 * SK_Scalar1);
    179                     canvas->drawText(gStyles[style].fName,
    180                                         strlen(gStyles[style].fName),
    181                                         0, rect.height() + 12 * SK_Scalar1,
    182                                         labelPaint);
    183                     canvas->drawText(gFills[fill].fName,
    184                                         strlen(gFills[fill].fName),
    185                                         0, rect.height() + 24 * SK_Scalar1,
    186                                         labelPaint);
    187                     canvas->drawText(gCaps[cap].fName,
    188                                         strlen(gCaps[cap].fName),
    189                                         0, rect.height() + 36 * SK_Scalar1,
    190                                         labelPaint);
    191                 }
    192                 canvas->restore();
    193             }
    194             canvas->restore();
    195         }
    196         canvas->restore();
    197         canvas->restore();
    198     }
    199 
    200 private:
    201     typedef skiagm::GM INHERITED;
    202 };
    203 
    204 class CubicClosePathGM : public skiagm::GM {
    205 public:
    206     CubicClosePathGM() {}
    207 
    208 protected:
    209     virtual uint32_t onGetFlags() const SK_OVERRIDE {
    210         return kSkipTiled_Flag;
    211     }
    212 
    213     SkString onShortName() {
    214         return SkString("cubicclosepath");
    215     }
    216 
    217     SkISize onISize() { return SkISize::Make(1240, 390); }
    218 
    219     void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
    220                   const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
    221                   SkPaint::Style style, SkPath::FillType fill,
    222                   SkScalar strokeWidth) {
    223         path.setFillType(fill);
    224         SkPaint paint;
    225         paint.setStrokeCap(cap);
    226         paint.setStrokeWidth(strokeWidth);
    227         paint.setStrokeJoin(join);
    228         paint.setColor(color);
    229         paint.setStyle(style);
    230         canvas->save();
    231         canvas->clipRect(clip);
    232         canvas->drawPath(path, paint);
    233         canvas->restore();
    234     }
    235 
    236     virtual void onDraw(SkCanvas* canvas) {
    237         struct FillAndName {
    238             SkPath::FillType fFill;
    239             const char*      fName;
    240         };
    241         static const FillAndName gFills[] = {
    242             {SkPath::kWinding_FillType, "Winding"},
    243             {SkPath::kEvenOdd_FillType, "Even / Odd"},
    244             {SkPath::kInverseWinding_FillType, "Inverse Winding"},
    245             {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
    246         };
    247         struct StyleAndName {
    248             SkPaint::Style fStyle;
    249             const char*    fName;
    250         };
    251         static const StyleAndName gStyles[] = {
    252             {SkPaint::kFill_Style, "Fill"},
    253             {SkPaint::kStroke_Style, "Stroke"},
    254             {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
    255         };
    256         struct CapAndName {
    257             SkPaint::Cap  fCap;
    258             SkPaint::Join fJoin;
    259             const char*   fName;
    260         };
    261         static const CapAndName gCaps[] = {
    262             {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
    263             {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
    264             {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
    265         };
    266         struct PathAndName {
    267             SkPath      fPath;
    268             const char* fName;
    269         };
    270         PathAndName path;
    271         path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
    272         path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
    273                            60*SK_Scalar1, 20*SK_Scalar1,
    274                            75*SK_Scalar1, 10*SK_Scalar1);
    275         path.fPath.close();
    276         path.fName = "moveTo-cubic-close";
    277 
    278         SkPaint titlePaint;
    279         titlePaint.setColor(SK_ColorBLACK);
    280         titlePaint.setAntiAlias(true);
    281         titlePaint.setLCDRenderText(true);
    282         titlePaint.setTextSize(15 * SK_Scalar1);
    283         const char title[] = "Cubic Closed Drawn Into Rectangle Clips With "
    284                              "Indicated Style, Fill and Linecaps, with stroke width 10";
    285         canvas->drawText(title, strlen(title),
    286                             20 * SK_Scalar1,
    287                             20 * SK_Scalar1,
    288                             titlePaint);
    289 
    290         SkLCGRandom rand;
    291         SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
    292         canvas->save();
    293         canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
    294         canvas->save();
    295         for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
    296             if (0 < cap) {
    297                 canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
    298             }
    299             canvas->save();
    300             for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
    301                 if (0 < fill) {
    302                     canvas->translate(0, rect.height() + 40 * SK_Scalar1);
    303                 }
    304                 canvas->save();
    305                 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
    306                     if (0 < style) {
    307                         canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
    308                     }
    309 
    310                     SkColor color = 0xff007000;
    311                     this->drawPath(path.fPath, canvas, color, rect,
    312                                     gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
    313                                     gFills[fill].fFill, SK_Scalar1*10);
    314 
    315                     SkPaint rectPaint;
    316                     rectPaint.setColor(SK_ColorBLACK);
    317                     rectPaint.setStyle(SkPaint::kStroke_Style);
    318                     rectPaint.setStrokeWidth(-1);
    319                     rectPaint.setAntiAlias(true);
    320                     canvas->drawRect(rect, rectPaint);
    321 
    322                     SkPaint labelPaint;
    323                     labelPaint.setColor(color);
    324                     labelPaint.setAntiAlias(true);
    325                     labelPaint.setLCDRenderText(true);
    326                     labelPaint.setTextSize(10 * SK_Scalar1);
    327                     canvas->drawText(gStyles[style].fName,
    328                                         strlen(gStyles[style].fName),
    329                                         0, rect.height() + 12 * SK_Scalar1,
    330                                         labelPaint);
    331                     canvas->drawText(gFills[fill].fName,
    332                                         strlen(gFills[fill].fName),
    333                                         0, rect.height() + 24 * SK_Scalar1,
    334                                         labelPaint);
    335                     canvas->drawText(gCaps[cap].fName,
    336                                         strlen(gCaps[cap].fName),
    337                                         0, rect.height() + 36 * SK_Scalar1,
    338                                         labelPaint);
    339                 }
    340                 canvas->restore();
    341             }
    342             canvas->restore();
    343         }
    344         canvas->restore();
    345         canvas->restore();
    346     }
    347 
    348 private:
    349     typedef skiagm::GM INHERITED;
    350 };
    351 
    352 //////////////////////////////////////////////////////////////////////////////
    353 
    354 DEF_GM( return new CubicPathGM; )
    355 DEF_GM( return new CubicClosePathGM; )
    356 DEF_GM( return new ClippedCubicGM; )
    357