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