Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2012 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 
      8 #include "gm.h"
      9 #include "SkCanvas.h"
     10 #include "SkPaint.h"
     11 #include "SkDashPathEffect.h"
     12 
     13 static void drawline(SkCanvas* canvas, int on, int off, const SkPaint& paint,
     14                      SkScalar finalX = SkIntToScalar(600), SkScalar finalY = SkIntToScalar(0),
     15                      SkScalar phase = SkIntToScalar(0)) {
     16     SkPaint p(paint);
     17 
     18     const SkScalar intervals[] = {
     19         SkIntToScalar(on),
     20         SkIntToScalar(off),
     21     };
     22 
     23     p.setPathEffect(SkDashPathEffect::Create(intervals, 2, phase))->unref();
     24     canvas->drawLine(0, 0, finalX, finalY, p);
     25 }
     26 
     27 // earlier bug stopped us from drawing very long single-segment dashes, because
     28 // SkPathMeasure was skipping very small delta-T values (nearlyzero). This is
     29 // now fixes, so this giant dash should appear.
     30 static void show_giant_dash(SkCanvas* canvas) {
     31     SkPaint paint;
     32 
     33     drawline(canvas, 1, 1, paint, SkIntToScalar(20 * 1000));
     34 }
     35 
     36 class DashingGM : public skiagm::GM {
     37 public:
     38     DashingGM() {}
     39 
     40 protected:
     41     virtual uint32_t onGetFlags() const SK_OVERRIDE {
     42         return kSkipTiled_Flag;
     43     }
     44 
     45     SkString onShortName() {
     46         return SkString("dashing");
     47     }
     48 
     49     SkISize onISize() { return SkISize::Make(640, 300); }
     50 
     51     virtual void onDraw(SkCanvas* canvas) {
     52         static const struct {
     53             int fOnInterval;
     54             int fOffInterval;
     55         } gData[] = {
     56             { 1, 1 },
     57             { 4, 1 },
     58         };
     59 
     60         SkPaint paint;
     61         paint.setStyle(SkPaint::kStroke_Style);
     62 
     63         canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
     64         canvas->translate(0, SK_ScalarHalf);
     65         for (int width = 0; width <= 2; ++width) {
     66             for (size_t data = 0; data < SK_ARRAY_COUNT(gData); ++data) {
     67                 for (int aa = 0; aa <= 1; ++aa) {
     68                     int w = width * width * width;
     69                     paint.setAntiAlias(SkToBool(aa));
     70                     paint.setStrokeWidth(SkIntToScalar(w));
     71 
     72                     int scale = w ? w : 1;
     73 
     74                     drawline(canvas, gData[data].fOnInterval * scale,
     75                              gData[data].fOffInterval * scale,
     76                              paint);
     77                     canvas->translate(0, SkIntToScalar(20));
     78                 }
     79             }
     80         }
     81 
     82         show_giant_dash(canvas);
     83     }
     84 };
     85 
     86 ///////////////////////////////////////////////////////////////////////////////
     87 
     88 static void make_unit_star(SkPath* path, int n) {
     89     SkScalar rad = -SK_ScalarPI / 2;
     90     const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;
     91 
     92     path->moveTo(0, -SK_Scalar1);
     93     for (int i = 1; i < n; i++) {
     94         rad += drad;
     95         SkScalar cosV, sinV = SkScalarSinCos(rad, &cosV);
     96         path->lineTo(cosV, sinV);
     97     }
     98     path->close();
     99 }
    100 
    101 static void make_path_line(SkPath* path, const SkRect& bounds) {
    102     path->moveTo(bounds.left(), bounds.top());
    103     path->lineTo(bounds.right(), bounds.bottom());
    104 }
    105 
    106 static void make_path_rect(SkPath* path, const SkRect& bounds) {
    107     path->addRect(bounds);
    108 }
    109 
    110 static void make_path_oval(SkPath* path, const SkRect& bounds) {
    111     path->addOval(bounds);
    112 }
    113 
    114 static void make_path_star(SkPath* path, const SkRect& bounds) {
    115     make_unit_star(path, 5);
    116     SkMatrix matrix;
    117     matrix.setRectToRect(path->getBounds(), bounds, SkMatrix::kCenter_ScaleToFit);
    118     path->transform(matrix);
    119 }
    120 
    121 class Dashing2GM : public skiagm::GM {
    122 public:
    123     Dashing2GM() {}
    124 
    125 protected:
    126     virtual uint32_t onGetFlags() const SK_OVERRIDE {
    127         return kSkipTiled_Flag;
    128     }
    129 
    130     SkString onShortName() {
    131         return SkString("dashing2");
    132     }
    133 
    134     SkISize onISize() { return SkISize::Make(640, 480); }
    135 
    136     virtual void onDraw(SkCanvas* canvas) {
    137         static const int gIntervals[] = {
    138             3,  // 3 dashes: each count [0] followed by intervals [1..count]
    139             2,  10, 10,
    140             4,  20, 5, 5, 5,
    141             2,  2, 2
    142         };
    143 
    144         void (*gProc[])(SkPath*, const SkRect&) = {
    145             make_path_line, make_path_rect, make_path_oval, make_path_star,
    146         };
    147 
    148         SkPaint paint;
    149         paint.setAntiAlias(true);
    150         paint.setStyle(SkPaint::kStroke_Style);
    151         paint.setStrokeWidth(SkIntToScalar(6));
    152 
    153         SkRect bounds = SkRect::MakeWH(SkIntToScalar(120), SkIntToScalar(120));
    154         bounds.offset(SkIntToScalar(20), SkIntToScalar(20));
    155         SkScalar dx = bounds.width() * 4 / 3;
    156         SkScalar dy = bounds.height() * 4 / 3;
    157 
    158         const int* intervals = &gIntervals[1];
    159         for (int y = 0; y < gIntervals[0]; ++y) {
    160             SkScalar vals[SK_ARRAY_COUNT(gIntervals)];  // more than enough
    161             int count = *intervals++;
    162             for (int i = 0; i < count; ++i) {
    163                 vals[i] = SkIntToScalar(*intervals++);
    164             }
    165             SkScalar phase = vals[0] / 2;
    166             paint.setPathEffect(SkDashPathEffect::Create(vals, count, phase))->unref();
    167 
    168             for (size_t x = 0; x < SK_ARRAY_COUNT(gProc); ++x) {
    169                 SkPath path;
    170                 SkRect r = bounds;
    171                 r.offset(x * dx, y * dy);
    172                 gProc[x](&path, r);
    173 
    174                 canvas->drawPath(path, paint);
    175             }
    176         }
    177     }
    178 };
    179 
    180 //////////////////////////////////////////////////////////////////////////////
    181 
    182 // Test out the on/off line dashing Chrome if fond of
    183 class Dashing3GM : public skiagm::GM {
    184 public:
    185     Dashing3GM() {}
    186 
    187 protected:
    188     virtual uint32_t onGetFlags() const SK_OVERRIDE {
    189         return kSkipTiled_Flag;
    190     }
    191 
    192     SkString onShortName() {
    193         return SkString("dashing3");
    194     }
    195 
    196     SkISize onISize() { return SkISize::Make(640, 480); }
    197 
    198     // Draw a 100x100 block of dashed lines. The horizontal ones are BW
    199     // while the vertical ones are AA.
    200     void drawDashedLines(SkCanvas* canvas,
    201                          SkScalar lineLength,
    202                          SkScalar phase,
    203                          SkScalar dashLength,
    204                          int strokeWidth,
    205                          bool circles) {
    206         SkPaint p;
    207         p.setColor(SK_ColorBLACK);
    208         p.setStyle(SkPaint::kStroke_Style);
    209         p.setStrokeWidth(SkIntToScalar(strokeWidth));
    210 
    211         if (circles) {
    212             p.setStrokeCap(SkPaint::kRound_Cap);
    213         }
    214 
    215         SkScalar intervals[2] = { dashLength, dashLength };
    216 
    217         p.setPathEffect(SkDashPathEffect::Create(intervals, 2, phase))->unref();
    218 
    219         SkPoint pts[2];
    220 
    221         for (int y = 0; y < 100; y += 10*strokeWidth) {
    222             pts[0].set(0, SkIntToScalar(y));
    223             pts[1].set(lineLength, SkIntToScalar(y));
    224 
    225             canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
    226         }
    227 
    228         p.setAntiAlias(true);
    229 
    230         for (int x = 0; x < 100; x += 14*strokeWidth) {
    231             pts[0].set(SkIntToScalar(x), 0);
    232             pts[1].set(SkIntToScalar(x), lineLength);
    233 
    234             canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
    235         }
    236     }
    237 
    238     virtual void onDraw(SkCanvas* canvas) {
    239         // 1on/1off 1x1 squares with phase of 0 - points fastpath
    240         canvas->save();
    241             canvas->translate(2, 0);
    242             this->drawDashedLines(canvas, 100, 0, SK_Scalar1, 1, false);
    243         canvas->restore();
    244 
    245         // 1on/1off 1x1 squares with phase of .5 - rects fastpath (due to partial squares)
    246         canvas->save();
    247             canvas->translate(112, 0);
    248             this->drawDashedLines(canvas, 100, SK_ScalarHalf, SK_Scalar1, 1, false);
    249         canvas->restore();
    250 
    251         // 1on/1off 1x1 squares with phase of 1 - points fastpath
    252         canvas->save();
    253             canvas->translate(222, 0);
    254             this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, false);
    255         canvas->restore();
    256 
    257         // 1on/1off 1x1 squares with phase of 1 and non-integer length - rects fastpath
    258         canvas->save();
    259             canvas->translate(332, 0);
    260             this->drawDashedLines(canvas, 99.5f, SK_ScalarHalf, SK_Scalar1, 1, false);
    261         canvas->restore();
    262 
    263         // 255on/255off 1x1 squares with phase of 0 - rects fast path
    264         canvas->save();
    265             canvas->translate(446, 0);
    266             this->drawDashedLines(canvas, 100, 0, SkIntToScalar(255), 1, false);
    267         canvas->restore();
    268 
    269         // 1on/1off 3x3 squares with phase of 0 - points fast path
    270         canvas->save();
    271             canvas->translate(2, 110);
    272             this->drawDashedLines(canvas, 100, 0, SkIntToScalar(3), 3, false);
    273         canvas->restore();
    274 
    275         // 1on/1off 3x3 squares with phase of 1.5 - rects fast path
    276         canvas->save();
    277             canvas->translate(112, 110);
    278             this->drawDashedLines(canvas, 100, 1.5f, SkIntToScalar(3), 3, false);
    279         canvas->restore();
    280 
    281         // 1on/1off 1x1 circles with phase of 1 - no fast path yet
    282         canvas->save();
    283             canvas->translate(2, 220);
    284             this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, true);
    285         canvas->restore();
    286 
    287         // 1on/1off 3x3 circles with phase of 1 - no fast path yet
    288         canvas->save();
    289             canvas->translate(112, 220);
    290             this->drawDashedLines(canvas, 100, 0, SkIntToScalar(3), 3, true);
    291         canvas->restore();
    292 
    293         // 1on/1off 1x1 squares with rotation - should break fast path
    294         canvas->save();
    295             canvas->translate(332+SK_ScalarRoot2Over2*100, 110+SK_ScalarRoot2Over2*100);
    296             canvas->rotate(45);
    297             canvas->translate(-50, -50);
    298 
    299             this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, false);
    300         canvas->restore();
    301 
    302         // 3on/3off 3x1 rects - should use rect fast path regardless of phase
    303         for (int phase = 0; phase <= 3; ++phase) {
    304             canvas->save();
    305                 canvas->translate(SkIntToScalar(phase*110+2),
    306                                   SkIntToScalar(330));
    307                 this->drawDashedLines(canvas, 100, SkIntToScalar(phase), SkIntToScalar(3), 1, false);
    308             canvas->restore();
    309         }
    310     }
    311 
    312 };
    313 
    314 //////////////////////////////////////////////////////////////////////////////
    315 
    316 class Dashing4GM : public skiagm::GM {
    317 public:
    318     Dashing4GM() {}
    319 
    320 protected:
    321     virtual uint32_t onGetFlags() const SK_OVERRIDE {
    322         return kSkipTiled_Flag;
    323     }
    324 
    325     SkString onShortName() {
    326         return SkString("dashing4");
    327     }
    328 
    329     SkISize onISize() { return SkISize::Make(640, 950); }
    330 
    331     virtual void onDraw(SkCanvas* canvas) {
    332         static const struct {
    333             int fOnInterval;
    334             int fOffInterval;
    335         } gData[] = {
    336             { 1, 1 },
    337             { 4, 2 },
    338             { 0, 4 }, // test for zero length on interval
    339         };
    340 
    341         SkPaint paint;
    342         paint.setStyle(SkPaint::kStroke_Style);
    343 
    344         canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
    345         canvas->translate(0, SK_ScalarHalf);
    346 
    347         for (int width = 0; width <= 2; ++width) {
    348             for (size_t data = 0; data < SK_ARRAY_COUNT(gData); ++data) {
    349                 for (int aa = 0; aa <= 1; ++aa) {
    350                     for (int cap = 0; cap <= 1; ++cap) {
    351                         int w = width * width * width;
    352                         paint.setAntiAlias(SkToBool(aa));
    353                         paint.setStrokeWidth(SkIntToScalar(w));
    354 
    355                         SkToBool(cap) ? paint.setStrokeCap(SkPaint::kSquare_Cap)
    356                             : paint.setStrokeCap(SkPaint::kRound_Cap);
    357 
    358                         int scale = w ? w : 1;
    359 
    360                         drawline(canvas, gData[data].fOnInterval * scale,
    361                                  gData[data].fOffInterval * scale,
    362                                  paint);
    363                         canvas->translate(0, SkIntToScalar(20));
    364                     }
    365                 }
    366             }
    367         }
    368 
    369         for (int aa = 0; aa <= 1; ++aa) {
    370             paint.setAntiAlias(SkToBool(aa));
    371             paint.setStrokeWidth(8.f);
    372             paint.setStrokeCap(SkPaint::kSquare_Cap);
    373             // Single dash element that is cut off at start and end
    374             drawline(canvas, 32, 16, paint, 20.f, 0, 5.f);
    375             canvas->translate(0, SkIntToScalar(20));
    376 
    377             // Two dash elements where each one is cut off at beginning and end respectively
    378             drawline(canvas, 32, 16, paint, 56.f, 0, 5.f);
    379             canvas->translate(0, SkIntToScalar(20));
    380 
    381             // Many dash elements where first and last are cut off at beginning and end respectively
    382             drawline(canvas, 32, 16, paint, 584.f, 0, 5.f);
    383             canvas->translate(0, SkIntToScalar(20));
    384 
    385             // Diagonal dash line where src pnts are not axis aligned (as apposed to being diagonal from
    386             // a canvas rotation)
    387             drawline(canvas, 32, 16, paint, 600.f, 30.f);
    388             canvas->translate(0, SkIntToScalar(20));
    389 
    390             // Case where only the off interval exists on the line. Thus nothing should be drawn
    391             drawline(canvas, 32, 16, paint, 8.f, 0.f, 40.f);
    392             canvas->translate(0, SkIntToScalar(20));
    393         }
    394     }
    395 };
    396 
    397 //////////////////////////////////////////////////////////////////////////////
    398 
    399 static skiagm::GM* F0(void*) { return new DashingGM; }
    400 static skiagm::GM* F1(void*) { return new Dashing2GM; }
    401 static skiagm::GM* F2(void*) { return new Dashing3GM; }
    402 static skiagm::GM* F3(void*) { return new Dashing4GM; }
    403 
    404 static skiagm::GMRegistry gR0(F0);
    405 static skiagm::GMRegistry gR1(F1);
    406 static skiagm::GMRegistry gR2(F2);
    407 static skiagm::GMRegistry gR3(F3);
    408