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