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         sk_tool_utils::set_portable_typeface(&titlePaint);
    293         titlePaint.setTextSize(15 * SK_Scalar1);
    294         const char title[] = "Random Paths Drawn Into Rectangle Clips With "
    295                              "Indicated Style, Fill and Linecaps, "
    296                              "with Stroke width 6";
    297         canvas->drawString(title,
    298                            20 * SK_Scalar1,
    299                            20 * SK_Scalar1,
    300                            titlePaint);
    301 
    302         SkRandom rand;
    303         SkRect rect = SkRect::MakeWH(220*SK_Scalar1, 50*SK_Scalar1);
    304         canvas->save();
    305         canvas->translate(2*SK_Scalar1, 30 * SK_Scalar1); // The title
    306         canvas->save();
    307         unsigned numSegments = SK_ARRAY_COUNT(gSegmentFunctions);
    308         unsigned numCaps = SK_ARRAY_COUNT(gCaps);
    309         unsigned numStyles = SK_ARRAY_COUNT(gStyles);
    310         unsigned numFills = SK_ARRAY_COUNT(gFills);
    311         for (size_t row = 0; row < 6; ++row) {
    312             if (0 < row) {
    313                 canvas->translate(0, rect.height() + 100*SK_Scalar1);
    314             }
    315             canvas->save();
    316             for (size_t column = 0; column < 4; ++column) {
    317                 if (0 < column) {
    318                     canvas->translate(rect.width() + 4*SK_Scalar1, 0);
    319                 }
    320 
    321                 SkColor color = sk_tool_utils::color_to_565(0xff007000);
    322                 StyleAndName style = gStyles[(rand.nextU() >> 16) % numStyles];
    323                 CapAndName cap = gCaps[(rand.nextU() >> 16) % numCaps];
    324                 FillAndName fill = gFills[(rand.nextU() >> 16) % numFills];
    325                 SkPath path;
    326                 unsigned s1 = (rand.nextU() >> 16) % numSegments;
    327                 unsigned s2 = (rand.nextU() >> 16) % numSegments;
    328                 unsigned s3 = (rand.nextU() >> 16) % numSegments;
    329                 unsigned s4 = (rand.nextU() >> 16) % numSegments;
    330                 unsigned s5 = (rand.nextU() >> 16) % numSegments;
    331                 SkPoint pt = SkPoint::Make(10*SK_Scalar1, 0);
    332                 pt = gSegmentFunctions[s1](path, pt);
    333                 pt = gSegmentFunctions[s2](path, pt);
    334                 pt = gSegmentFunctions[s3](path, pt);
    335                 pt = gSegmentFunctions[s4](path, pt);
    336                 pt = gSegmentFunctions[s5](path, pt);
    337 
    338                 this->drawPath(path, canvas, color, rect,
    339                                cap.fCap, cap.fJoin, style.fStyle,
    340                                fill.fFill, SK_Scalar1*6);
    341 
    342                 SkPaint rectPaint;
    343                 rectPaint.setColor(SK_ColorBLACK);
    344                 rectPaint.setStyle(SkPaint::kStroke_Style);
    345                 rectPaint.setStrokeWidth(-1);
    346                 rectPaint.setAntiAlias(true);
    347                 canvas->drawRect(rect, rectPaint);
    348 
    349                 SkPaint labelPaint;
    350                 labelPaint.setColor(color);
    351                 labelPaint.setAntiAlias(true);
    352                 sk_tool_utils::set_portable_typeface(&labelPaint);
    353                 labelPaint.setTextSize(10 * SK_Scalar1);
    354                 canvas->drawString(style.fName,
    355                                    0, rect.height() + 12 * SK_Scalar1,
    356                                    labelPaint);
    357                 canvas->drawString(fill.fName,
    358                                    0, rect.height() + 24 * SK_Scalar1,
    359                                    labelPaint);
    360                 canvas->drawString(cap.fName,
    361                                    0, rect.height() + 36 * SK_Scalar1,
    362                                    labelPaint);
    363                 canvas->drawString(gSegmentNames[s1],
    364                                    0, rect.height() + 48 * SK_Scalar1,
    365                                    labelPaint);
    366                 canvas->drawString(gSegmentNames[s2],
    367                                    0, rect.height() + 60 * SK_Scalar1,
    368                                    labelPaint);
    369                 canvas->drawString(gSegmentNames[s3],
    370                                    0, rect.height() + 72 * SK_Scalar1,
    371                                    labelPaint);
    372                 canvas->drawString(gSegmentNames[s4],
    373                                    0, rect.height() + 84 * SK_Scalar1,
    374                                    labelPaint);
    375                 canvas->drawString(gSegmentNames[s5],
    376                                    0, rect.height() + 96 * SK_Scalar1,
    377                                    labelPaint);
    378             }
    379             canvas->restore();
    380         }
    381         canvas->restore();
    382         canvas->restore();
    383     }
    384 
    385 private:
    386     typedef GM INHERITED;
    387 };
    388 
    389 //////////////////////////////////////////////////////////////////////////////
    390 
    391 static GM* MyFactory(void*) { return new DegenerateSegmentsGM; }
    392 static GMRegistry reg(MyFactory);
    393 
    394 }
    395