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