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 "SkPath.h"
      9 #include "SkRandom.h"
     10 #include "SkTArray.h"
     11 
     12 class SkDoOnce : SkNoncopyable {
     13 public:
     14     SkDoOnce() { fDidOnce = false; }
     15 
     16     bool needToDo() const { return !fDidOnce; }
     17     bool alreadyDone() const { return fDidOnce; }
     18     void accomplished() {
     19         SkASSERT(!fDidOnce);
     20         fDidOnce = true;
     21     }
     22 
     23 private:
     24     bool fDidOnce;
     25 };
     26 
     27 namespace skiagm {
     28 
     29 class ConvexPathsGM : public GM {
     30     SkDoOnce fOnce;
     31 public:
     32     ConvexPathsGM() {
     33         this->setBGColor(0xFF000000);
     34     }
     35 
     36 protected:
     37 
     38     virtual SkString onShortName() {
     39         return SkString("convexpaths");
     40     }
     41 
     42 
     43     virtual SkISize onISize() {
     44         return SkISize::Make(1200, 1100);
     45     }
     46 
     47     void makePaths() {
     48         if (fOnce.alreadyDone()) {
     49             return;
     50         }
     51         fOnce.accomplished();
     52 
     53         fPaths.push_back().moveTo(0, 0);
     54         fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
     55                              0, 100 * SK_Scalar1);
     56         fPaths.back().lineTo(0, 0);
     57 
     58         fPaths.push_back().moveTo(0, 50 * SK_Scalar1);
     59         fPaths.back().quadTo(50 * SK_Scalar1, 0,
     60                              100 * SK_Scalar1, 50 * SK_Scalar1);
     61         fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
     62                              0, 50 * SK_Scalar1);
     63 
     64         fPaths.push_back().addRect(0, 0,
     65                                    100 * SK_Scalar1, 100 * SK_Scalar1,
     66                                    SkPath::kCW_Direction);
     67 
     68         fPaths.push_back().addRect(0, 0,
     69                                    100 * SK_Scalar1, 100 * SK_Scalar1,
     70                                    SkPath::kCCW_Direction);
     71 
     72         fPaths.push_back().addCircle(50  * SK_Scalar1, 50  * SK_Scalar1,
     73                                      50  * SK_Scalar1, SkPath::kCW_Direction);
     74 
     75 
     76         fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
     77                                                     50 * SK_Scalar1,
     78                                                     100 * SK_Scalar1),
     79                                    SkPath::kCW_Direction);
     80 
     81         fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
     82                                                     100 * SK_Scalar1,
     83                                                     5 * SK_Scalar1),
     84                                    SkPath::kCCW_Direction);
     85 
     86         fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
     87                                                     SK_Scalar1,
     88                                                     100 * SK_Scalar1),
     89                                                     SkPath::kCCW_Direction);
     90 
     91         fPaths.push_back().addRoundRect(SkRect::MakeXYWH(0, 0,
     92                                                          SK_Scalar1 * 100,
     93                                                          SK_Scalar1 * 100),
     94                                         40 * SK_Scalar1, 20 * SK_Scalar1,
     95                                         SkPath::kCW_Direction);
     96 
     97         // large number of points
     98         enum {
     99             kLength = 100,
    100             kPtsPerSide = (1 << 12),
    101         };
    102         fPaths.push_back().moveTo(0, 0);
    103         for (int i = 1; i < kPtsPerSide; ++i) { // skip the first point due to moveTo.
    104             fPaths.back().lineTo(kLength * SkIntToScalar(i) / kPtsPerSide, 0);
    105         }
    106         for (int i = 0; i < kPtsPerSide; ++i) {
    107             fPaths.back().lineTo(kLength, kLength * SkIntToScalar(i) / kPtsPerSide);
    108         }
    109         for (int i = kPtsPerSide; i > 0; --i) {
    110             fPaths.back().lineTo(kLength * SkIntToScalar(i) / kPtsPerSide, kLength);
    111         }
    112         for (int i = kPtsPerSide; i > 0; --i) {
    113             fPaths.back().lineTo(0, kLength * SkIntToScalar(i) / kPtsPerSide);
    114         }
    115 
    116         // shallow diagonals
    117         fPaths.push_back().lineTo(100 * SK_Scalar1, SK_Scalar1);
    118         fPaths.back().lineTo(98 * SK_Scalar1, 100 * SK_Scalar1);
    119         fPaths.back().lineTo(3 * SK_Scalar1, 96 * SK_Scalar1);
    120 
    121         fPaths.push_back().arcTo(SkRect::MakeXYWH(0, 0,
    122                                                   50 * SK_Scalar1,
    123                                                   100 * SK_Scalar1),
    124                                                   25 * SK_Scalar1,  130 * SK_Scalar1, false);
    125 
    126         // cubics
    127         fPaths.push_back().cubicTo( 1 * SK_Scalar1,  1 * SK_Scalar1,
    128                                    10 * SK_Scalar1,  90 * SK_Scalar1,
    129                                     0 * SK_Scalar1, 100 * SK_Scalar1);
    130         fPaths.push_back().cubicTo(100 * SK_Scalar1,  50 * SK_Scalar1,
    131                                     20 * SK_Scalar1, 100 * SK_Scalar1,
    132                                      0 * SK_Scalar1,   0 * SK_Scalar1);
    133 
    134         // path that has a cubic with a repeated first control point and
    135         // a repeated last control point.
    136         fPaths.push_back().moveTo(SK_Scalar1 * 10, SK_Scalar1 * 10);
    137         fPaths.back().cubicTo(10 * SK_Scalar1, 10 * SK_Scalar1,
    138                               10 * SK_Scalar1, 0,
    139                               20 * SK_Scalar1, 0);
    140         fPaths.back().lineTo(40 * SK_Scalar1, 0);
    141         fPaths.back().cubicTo(40 * SK_Scalar1, 0,
    142                               50 * SK_Scalar1, 0,
    143                               50 * SK_Scalar1, 10 * SK_Scalar1);
    144 
    145         // path that has two cubics with repeated middle control points.
    146         fPaths.push_back().moveTo(SK_Scalar1 * 10, SK_Scalar1 * 10);
    147         fPaths.back().cubicTo(10 * SK_Scalar1, 0,
    148                               10 * SK_Scalar1, 0,
    149                               20 * SK_Scalar1, 0);
    150         fPaths.back().lineTo(40 * SK_Scalar1, 0);
    151         fPaths.back().cubicTo(50 * SK_Scalar1, 0,
    152                               50 * SK_Scalar1, 0,
    153                               50 * SK_Scalar1, 10 * SK_Scalar1);
    154 
    155         // cubic where last three points are almost a line
    156         fPaths.push_back().moveTo(0, 228 * SK_Scalar1 / 8);
    157         fPaths.back().cubicTo(628 * SK_Scalar1 / 8, 82 * SK_Scalar1 / 8,
    158                               1255 * SK_Scalar1 / 8, 141 * SK_Scalar1 / 8,
    159                               1883 * SK_Scalar1 / 8, 202 * SK_Scalar1 / 8);
    160 
    161         // flat cubic where the at end point tangents both point outward.
    162         fPaths.push_back().moveTo(10 * SK_Scalar1, 0);
    163         fPaths.back().cubicTo(0, SK_Scalar1,
    164                               30 * SK_Scalar1, SK_Scalar1,
    165                               20 * SK_Scalar1, 0);
    166 
    167         // flat cubic where initial tangent is in, end tangent out
    168         fPaths.push_back().moveTo(0, 0 * SK_Scalar1);
    169         fPaths.back().cubicTo(10 * SK_Scalar1, SK_Scalar1,
    170                               30 * SK_Scalar1, SK_Scalar1,
    171                               20 * SK_Scalar1, 0);
    172 
    173         // flat cubic where initial tangent is out, end tangent in
    174         fPaths.push_back().moveTo(10 * SK_Scalar1, 0);
    175         fPaths.back().cubicTo(0, SK_Scalar1,
    176                               20 * SK_Scalar1, SK_Scalar1,
    177                               30 * SK_Scalar1, 0);
    178 
    179         // triangle where one edge is a degenerate quad
    180         fPaths.push_back().moveTo(8.59375f, 45 * SK_Scalar1);
    181         fPaths.back().quadTo(16.9921875f,   45 * SK_Scalar1,
    182                              31.25f,        45 * SK_Scalar1);
    183         fPaths.back().lineTo(100 * SK_Scalar1,              100 * SK_Scalar1);
    184         fPaths.back().lineTo(8.59375f,      45 * SK_Scalar1);
    185 
    186         // triangle where one edge is a quad with a repeated point
    187         fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
    188         fPaths.back().lineTo(50 * SK_Scalar1, 0);
    189         fPaths.back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1, 50 * SK_Scalar1, 50 * SK_Scalar1);
    190 
    191         // triangle where one edge is a cubic with a 2x repeated point
    192         fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
    193         fPaths.back().lineTo(50 * SK_Scalar1, 0);
    194         fPaths.back().cubicTo(50 * SK_Scalar1, 0,
    195                               50 * SK_Scalar1, 50 * SK_Scalar1,
    196                               50 * SK_Scalar1, 50 * SK_Scalar1);
    197 
    198         // triangle where one edge is a quad with a nearly repeated point
    199         fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
    200         fPaths.back().lineTo(50 * SK_Scalar1, 0);
    201         fPaths.back().quadTo(50 * SK_Scalar1, 49.95f,
    202                              50 * SK_Scalar1, 50 * SK_Scalar1);
    203 
    204         // triangle where one edge is a cubic with a 3x nearly repeated point
    205         fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
    206         fPaths.back().lineTo(50 * SK_Scalar1, 0);
    207         fPaths.back().cubicTo(50 * SK_Scalar1, 49.95f,
    208                               50 * SK_Scalar1, 49.97f,
    209                               50 * SK_Scalar1, 50 * SK_Scalar1);
    210 
    211         // triangle where there is a point degenerate cubic at one corner
    212         fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
    213         fPaths.back().lineTo(50 * SK_Scalar1, 0);
    214         fPaths.back().lineTo(50 * SK_Scalar1, 50 * SK_Scalar1);
    215         fPaths.back().cubicTo(50 * SK_Scalar1, 50 * SK_Scalar1,
    216                               50 * SK_Scalar1, 50 * SK_Scalar1,
    217                               50 * SK_Scalar1, 50 * SK_Scalar1);
    218 
    219         // point line
    220         fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
    221         fPaths.back().lineTo(50 * SK_Scalar1, 50 * SK_Scalar1);
    222 
    223         // point quad
    224         fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
    225         fPaths.back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1,
    226                              50 * SK_Scalar1, 50 * SK_Scalar1);
    227 
    228         // point cubic
    229         fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
    230         fPaths.back().cubicTo(50 * SK_Scalar1, 50 * SK_Scalar1,
    231                               50 * SK_Scalar1, 50 * SK_Scalar1,
    232                               50 * SK_Scalar1, 50 * SK_Scalar1);
    233 
    234         // moveTo only paths
    235         fPaths.push_back().moveTo(0, 0);
    236         fPaths.back().moveTo(0, 0);
    237         fPaths.back().moveTo(SK_Scalar1, SK_Scalar1);
    238         fPaths.back().moveTo(SK_Scalar1, SK_Scalar1);
    239         fPaths.back().moveTo(10 * SK_Scalar1, 10 * SK_Scalar1);
    240 
    241         fPaths.push_back().moveTo(0, 0);
    242         fPaths.back().moveTo(0, 0);
    243 
    244         // line degenerate
    245         fPaths.push_back().lineTo(100 * SK_Scalar1, 100 * SK_Scalar1);
    246         fPaths.push_back().quadTo(100 * SK_Scalar1, 100 * SK_Scalar1, 0, 0);
    247         fPaths.push_back().quadTo(100 * SK_Scalar1, 100 * SK_Scalar1,
    248                                   50 * SK_Scalar1, 50 * SK_Scalar1);
    249         fPaths.push_back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1,
    250                                   100 * SK_Scalar1, 100 * SK_Scalar1);
    251         fPaths.push_back().cubicTo(0, 0,
    252                                    0, 0,
    253                                    100 * SK_Scalar1, 100 * SK_Scalar1);
    254 
    255         // small circle. This is listed last so that it has device coords far
    256         // from the origin (small area relative to x,y values).
    257         fPaths.push_back().addCircle(0, 0, 1.2f);
    258     }
    259 
    260     virtual void onDraw(SkCanvas* canvas) {
    261         this->makePaths();
    262 
    263         SkPaint paint;
    264         paint.setAntiAlias(true);
    265         SkRandom rand;
    266         canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1);
    267 
    268         // As we've added more paths this has gotten pretty big. Scale the whole thing down.
    269         canvas->scale(2 * SK_Scalar1 / 3, 2 * SK_Scalar1 / 3);
    270 
    271         for (int i = 0; i < fPaths.count(); ++i) {
    272             canvas->save();
    273             // position the path, and make it at off-integer coords.
    274             canvas->translate(SK_Scalar1 * 200 * (i % 5) + SK_Scalar1 / 10,
    275                               SK_Scalar1 * 200 * (i / 5) + 9 * SK_Scalar1 / 10);
    276             SkColor color = rand.nextU();
    277             color |= 0xff000000;
    278             paint.setColor(color);
    279 #if 0       // This hitting on 32bit Linux builds for some paths. Temporarily disabling while it is
    280             // debugged.
    281             SkASSERT(fPaths[i].isConvex());
    282 #endif
    283             canvas->drawPath(fPaths[i], paint);
    284             canvas->restore();
    285         }
    286     }
    287 
    288 private:
    289     typedef GM INHERITED;
    290     SkTArray<SkPath> fPaths;
    291 };
    292 
    293 //////////////////////////////////////////////////////////////////////////////
    294 
    295 DEF_GM( return new ConvexPathsGM; )
    296 
    297 }
    298