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