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