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 "sk_tool_utils.h"
      9 #include "SkCanvas.h"
     10 #include "SkPaint.h"
     11 #include "SkPath.h"
     12 #include "SkRandom.h"
     13 
     14 namespace skiagm {
     15 
     16 class DegenerateSegmentsGM : public GM {
     17 public:
     18     DegenerateSegmentsGM() {}
     19 
     20 protected:
     21     struct PathAndName {
     22         SkPath      fPath;
     23         const char* fName1;
     24         const char* fName2;
     25     };
     26 
     27     SkString onShortName() {
     28         return SkString("degeneratesegments");
     29     }
     30 
     31     SkISize onISize() { return SkISize::Make(896, 930); }
     32 
     33     typedef SkPoint (*AddSegmentFunc)(SkPath&, SkPoint&);
     34 
     35     // We need to use explicit commands here, instead of addPath, because we
     36     // do not want the moveTo that is added at the beginning of a path to
     37     // appear in the appended path.
     38     static SkPoint AddMove(SkPath& path, SkPoint& startPt) {
     39         SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
     40         path.moveTo(moveToPt);
     41         return moveToPt;
     42     }
     43 
     44     static SkPoint AddMoveClose(SkPath& path, SkPoint& startPt) {
     45         SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
     46         path.moveTo(moveToPt);
     47         path.close();
     48         return moveToPt;
     49     }
     50 
     51     static SkPoint AddDegenLine(SkPath& path, SkPoint& startPt) {
     52         path.lineTo(startPt);
     53         return startPt;
     54     }
     55 
     56     static SkPoint AddMoveDegenLine(SkPath& path, SkPoint& startPt) {
     57         SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
     58         path.moveTo(moveToPt);
     59         path.lineTo(moveToPt);
     60         return moveToPt;
     61     }
     62 
     63     static SkPoint AddMoveDegenLineClose(SkPath& path, SkPoint& startPt) {
     64         SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
     65         path.moveTo(moveToPt);
     66         path.lineTo(moveToPt);
     67         path.close();
     68         return moveToPt;
     69     }
     70 
     71     static SkPoint AddDegenQuad(SkPath& path, SkPoint& startPt) {
     72         path.quadTo(startPt, startPt);
     73         return startPt;
     74     }
     75 
     76     static SkPoint AddMoveDegenQuad(SkPath& path, SkPoint& startPt) {
     77         SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
     78         path.moveTo(moveToPt);
     79         path.quadTo(moveToPt, moveToPt);
     80         return moveToPt;
     81     }
     82 
     83     static SkPoint AddMoveDegenQuadClose(SkPath& path, SkPoint& startPt) {
     84         SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
     85         path.moveTo(moveToPt);
     86         path.quadTo(moveToPt, moveToPt);
     87         path.close();
     88         return moveToPt;
     89     }
     90 
     91     static SkPoint AddDegenCubic(SkPath& path, SkPoint& startPt) {
     92         path.cubicTo(startPt, startPt, startPt);
     93         return startPt;
     94     }
     95 
     96     static SkPoint AddMoveDegenCubic(SkPath& path, SkPoint& startPt) {
     97         SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
     98         path.moveTo(moveToPt);
     99         path.cubicTo(moveToPt, moveToPt, moveToPt);
    100         return moveToPt;
    101     }
    102 
    103     static SkPoint AddMoveDegenCubicClose(SkPath& path, SkPoint& startPt) {
    104         SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
    105         path.moveTo(moveToPt);
    106         path.cubicTo(moveToPt, moveToPt, moveToPt);
    107         path.close();
    108         return moveToPt;
    109     }
    110 
    111     static SkPoint AddClose(SkPath& path, SkPoint& startPt) {
    112         path.close();
    113         return startPt;
    114     }
    115 
    116     static SkPoint AddLine(SkPath& path, SkPoint& startPt) {
    117         SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
    118         path.lineTo(endPt);
    119         return endPt;
    120     }
    121 
    122     static SkPoint AddMoveLine(SkPath& path, SkPoint& startPt) {
    123         SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
    124         SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
    125         path.moveTo(moveToPt);
    126         path.lineTo(endPt);
    127         return endPt;
    128     }
    129 
    130     static SkPoint AddMoveLineClose(SkPath& path, SkPoint& startPt) {
    131         SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
    132         SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
    133         path.moveTo(moveToPt);
    134         path.lineTo(endPt);
    135         path.close();
    136         return endPt;
    137     }
    138 
    139     static SkPoint AddQuad(SkPath& path, SkPoint& startPt) {
    140         SkPoint midPt = startPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
    141         SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
    142         path.quadTo(midPt, endPt);
    143         return endPt;
    144     }
    145 
    146     static SkPoint AddMoveQuad(SkPath& path, SkPoint& startPt) {
    147         SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
    148         SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
    149         SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
    150         path.moveTo(moveToPt);
    151         path.quadTo(midPt, endPt);
    152         return endPt;
    153     }
    154 
    155     static SkPoint AddMoveQuadClose(SkPath& path, SkPoint& startPt) {
    156         SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
    157         SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
    158         SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
    159         path.moveTo(moveToPt);
    160         path.quadTo(midPt, endPt);
    161         path.close();
    162         return endPt;
    163     }
    164 
    165     static SkPoint AddCubic(SkPath& path, SkPoint& startPt) {
    166         SkPoint t1Pt = startPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
    167         SkPoint t2Pt = startPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
    168         SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
    169         path.cubicTo(t1Pt, t2Pt, endPt);
    170         return endPt;
    171     }
    172 
    173     static SkPoint AddMoveCubic(SkPath& path, SkPoint& startPt) {
    174         SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
    175         SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
    176         SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
    177         SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
    178         path.moveTo(moveToPt);
    179         path.cubicTo(t1Pt, t2Pt, endPt);
    180         return endPt;
    181     }
    182 
    183     static SkPoint AddMoveCubicClose(SkPath& path, SkPoint& startPt) {
    184         SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
    185         SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
    186         SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
    187         SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
    188         path.moveTo(moveToPt);
    189         path.cubicTo(t1Pt, t2Pt, endPt);
    190         path.close();
    191         return endPt;
    192     }
    193 
    194     void drawPath(SkPath& path, SkCanvas* canvas, SkColor color,
    195                   const SkRect& clip, SkPaint::Cap cap, SkPaint::Join join,
    196                   SkPaint::Style style, SkPath::FillType fill,
    197                   SkScalar strokeWidth) {
    198         path.setFillType(fill);
    199         SkPaint paint;
    200         paint.setStrokeCap(cap);
    201         paint.setStrokeWidth(strokeWidth);
    202         paint.setStrokeJoin(join);
    203         paint.setColor(color);
    204         paint.setStyle(style);
    205         canvas->save();
    206         canvas->clipRect(clip);
    207         canvas->drawPath(path, paint);
    208         canvas->restore();
    209     }
    210 
    211     virtual void onDraw(SkCanvas* canvas) {
    212     constexpr AddSegmentFunc gSegmentFunctions[] = {
    213         AddMove,
    214         AddMoveClose,
    215         AddDegenLine,
    216         AddMoveDegenLine,
    217         AddMoveDegenLineClose,
    218         AddDegenQuad,
    219         AddMoveDegenQuad,
    220         AddMoveDegenQuadClose,
    221         AddDegenCubic,
    222         AddMoveDegenCubic,
    223         AddMoveDegenCubicClose,
    224         AddClose,
    225         AddLine,
    226         AddMoveLine,
    227         AddMoveLineClose,
    228         AddQuad,
    229         AddMoveQuad,
    230         AddMoveQuadClose,
    231         AddCubic,
    232         AddMoveCubic,
    233         AddMoveCubicClose
    234     };
    235     const char* gSegmentNames[] = {
    236         "Move",
    237         "MoveClose",
    238         "DegenLine",
    239         "MoveDegenLine",
    240         "MoveDegenLineClose",
    241         "DegenQuad",
    242         "MoveDegenQuad",
    243         "MoveDegenQuadClose",
    244         "DegenCubic",
    245         "MoveDegenCubic",
    246         "MoveDegenCubicClose",
    247         "Close",
    248         "Line",
    249         "MoveLine",
    250         "MoveLineClose",
    251         "Quad",
    252         "MoveQuad",
    253         "MoveQuadClose",
    254         "Cubic",
    255         "MoveCubic",
    256         "MoveCubicClose"
    257     };
    258 
    259         struct FillAndName {
    260             SkPath::FillType fFill;
    261             const char*      fName;
    262         };
    263         constexpr FillAndName gFills[] = {
    264             {SkPath::kWinding_FillType, "Winding"},
    265             {SkPath::kEvenOdd_FillType, "Even / Odd"},
    266             {SkPath::kInverseWinding_FillType, "Inverse Winding"},
    267             {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}
    268         };
    269         struct StyleAndName {
    270             SkPaint::Style fStyle;
    271             const char*    fName;
    272         };
    273         constexpr StyleAndName gStyles[] = {
    274             {SkPaint::kFill_Style, "Fill"},
    275             {SkPaint::kStroke_Style, "Stroke 10"},
    276             {SkPaint::kStrokeAndFill_Style, "Stroke 10 And Fill"}
    277         };
    278         struct CapAndName {
    279             SkPaint::Cap  fCap;
    280             SkPaint::Join fJoin;
    281             const char*   fName;
    282         };
    283         constexpr CapAndName gCaps[] = {
    284             {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
    285             {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
    286             {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
    287         };
    288 
    289         SkPaint titlePaint;
    290         titlePaint.setColor(SK_ColorBLACK);
    291         titlePaint.setAntiAlias(true);
    292         SkFont font(sk_tool_utils::create_portable_typeface(), 15);
    293         const char title[] = "Random Paths Drawn Into Rectangle Clips With "
    294                              "Indicated Style, Fill and Linecaps, "
    295                              "with Stroke width 6";
    296         canvas->drawString(title, 20, 20, font, titlePaint);
    297 
    298         SkRandom rand;
    299         SkRect rect = SkRect::MakeWH(220*SK_Scalar1, 50*SK_Scalar1);
    300         canvas->save();
    301         canvas->translate(2*SK_Scalar1, 30 * SK_Scalar1); // The title
    302         canvas->save();
    303         unsigned numSegments = SK_ARRAY_COUNT(gSegmentFunctions);
    304         unsigned numCaps = SK_ARRAY_COUNT(gCaps);
    305         unsigned numStyles = SK_ARRAY_COUNT(gStyles);
    306         unsigned numFills = SK_ARRAY_COUNT(gFills);
    307         for (size_t row = 0; row < 6; ++row) {
    308             if (0 < row) {
    309                 canvas->translate(0, rect.height() + 100*SK_Scalar1);
    310             }
    311             canvas->save();
    312             for (size_t column = 0; column < 4; ++column) {
    313                 if (0 < column) {
    314                     canvas->translate(rect.width() + 4*SK_Scalar1, 0);
    315                 }
    316 
    317                 SkColor color = sk_tool_utils::color_to_565(0xff007000);
    318                 StyleAndName style = gStyles[(rand.nextU() >> 16) % numStyles];
    319                 CapAndName cap = gCaps[(rand.nextU() >> 16) % numCaps];
    320                 FillAndName fill = gFills[(rand.nextU() >> 16) % numFills];
    321                 SkPath path;
    322                 unsigned s1 = (rand.nextU() >> 16) % numSegments;
    323                 unsigned s2 = (rand.nextU() >> 16) % numSegments;
    324                 unsigned s3 = (rand.nextU() >> 16) % numSegments;
    325                 unsigned s4 = (rand.nextU() >> 16) % numSegments;
    326                 unsigned s5 = (rand.nextU() >> 16) % numSegments;
    327                 SkPoint pt = SkPoint::Make(10*SK_Scalar1, 0);
    328                 pt = gSegmentFunctions[s1](path, pt);
    329                 pt = gSegmentFunctions[s2](path, pt);
    330                 pt = gSegmentFunctions[s3](path, pt);
    331                 pt = gSegmentFunctions[s4](path, pt);
    332                 pt = gSegmentFunctions[s5](path, pt);
    333 
    334                 this->drawPath(path, canvas, color, rect,
    335                                cap.fCap, cap.fJoin, style.fStyle,
    336                                fill.fFill, SK_Scalar1*6);
    337 
    338                 SkPaint rectPaint;
    339                 rectPaint.setColor(SK_ColorBLACK);
    340                 rectPaint.setStyle(SkPaint::kStroke_Style);
    341                 rectPaint.setStrokeWidth(-1);
    342                 rectPaint.setAntiAlias(true);
    343                 canvas->drawRect(rect, rectPaint);
    344 
    345                 SkPaint labelPaint;
    346                 labelPaint.setColor(color);
    347                 labelPaint.setAntiAlias(true);
    348                 font.setSize(10);
    349                 canvas->drawString(style.fName, 0, rect.height() + 12, font, labelPaint);
    350                 canvas->drawString(fill.fName, 0, rect.height() + 24, font, labelPaint);
    351                 canvas->drawString(cap.fName, 0, rect.height() + 36, font, labelPaint);
    352                 canvas->drawString(gSegmentNames[s1], 0, rect.height() + 48, font, labelPaint);
    353                 canvas->drawString(gSegmentNames[s2], 0, rect.height() + 60, font, labelPaint);
    354                 canvas->drawString(gSegmentNames[s3], 0, rect.height() + 72, font, labelPaint);
    355                 canvas->drawString(gSegmentNames[s4], 0, rect.height() + 84, font, labelPaint);
    356                 canvas->drawString(gSegmentNames[s5], 0, rect.height() + 96, font, labelPaint);
    357             }
    358             canvas->restore();
    359         }
    360         canvas->restore();
    361         canvas->restore();
    362     }
    363 
    364 private:
    365     typedef GM INHERITED;
    366 };
    367 
    368 //////////////////////////////////////////////////////////////////////////////
    369 
    370 DEF_GM( return new DegenerateSegmentsGM; )
    371 
    372 }
    373