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