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)) {
     15     SkPaint p(paint);
     16 
     17     const SkScalar intervals[] = {
     18         SkIntToScalar(on),
     19         SkIntToScalar(off),
     20     };
     21 
     22     p.setPathEffect(new SkDashPathEffect(intervals, 2, 0))->unref();
     23     canvas->drawLine(0, 0, finalX, 0, p);
     24 }
     25 
     26 // earlier bug stopped us from drawing very long single-segment dashes, because
     27 // SkPathMeasure was skipping very small delta-T values (nearlyzero). This is
     28 // now fixes, so this giant dash should appear.
     29 static void show_giant_dash(SkCanvas* canvas) {
     30     SkPaint paint;
     31 
     32     drawline(canvas, 1, 1, paint, SkIntToScalar(20 * 1000));
     33 }
     34 
     35 class DashingGM : public skiagm::GM {
     36 public:
     37     DashingGM() {}
     38 
     39 protected:
     40     SkString onShortName() {
     41         return SkString("dashing");
     42     }
     43 
     44     SkISize onISize() { return skiagm::make_isize(640, 300); }
     45 
     46     virtual void onDraw(SkCanvas* canvas) {
     47         static const struct {
     48             int fOnInterval;
     49             int fOffInterval;
     50         } gData[] = {
     51             { 1, 1 },
     52             { 4, 1 },
     53         };
     54 
     55         SkPaint paint;
     56         paint.setStyle(SkPaint::kStroke_Style);
     57 
     58         canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
     59         canvas->translate(0, SK_ScalarHalf);
     60 
     61         for (int width = 0; width <= 2; ++width) {
     62             for (size_t data = 0; data < SK_ARRAY_COUNT(gData); ++data) {
     63                 for (int aa = 0; aa <= 1; ++aa) {
     64                     int w = width * width * width;
     65                     paint.setAntiAlias(SkToBool(aa));
     66                     paint.setStrokeWidth(SkIntToScalar(w));
     67 
     68                     int scale = w ? w : 1;
     69 
     70                     drawline(canvas, gData[data].fOnInterval * scale,
     71                              gData[data].fOffInterval * scale,
     72                              paint);
     73                     canvas->translate(0, SkIntToScalar(20));
     74                 }
     75             }
     76         }
     77 
     78         show_giant_dash(canvas);
     79     }
     80 };
     81 
     82 ///////////////////////////////////////////////////////////////////////////////
     83 
     84 static void make_unit_star(SkPath* path, int n) {
     85     SkScalar rad = -SK_ScalarPI / 2;
     86     const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;
     87 
     88     path->moveTo(0, -SK_Scalar1);
     89     for (int i = 1; i < n; i++) {
     90         rad += drad;
     91         SkScalar cosV, sinV = SkScalarSinCos(rad, &cosV);
     92         path->lineTo(cosV, sinV);
     93     }
     94     path->close();
     95 }
     96 
     97 static void make_path_line(SkPath* path, const SkRect& bounds) {
     98     path->moveTo(bounds.left(), bounds.top());
     99     path->lineTo(bounds.right(), bounds.bottom());
    100 }
    101 
    102 static void make_path_rect(SkPath* path, const SkRect& bounds) {
    103     path->addRect(bounds);
    104 }
    105 
    106 static void make_path_oval(SkPath* path, const SkRect& bounds) {
    107     path->addOval(bounds);
    108 }
    109 
    110 static void make_path_star(SkPath* path, const SkRect& bounds) {
    111     make_unit_star(path, 5);
    112     SkMatrix matrix;
    113     matrix.setRectToRect(path->getBounds(), bounds, SkMatrix::kCenter_ScaleToFit);
    114     path->transform(matrix);
    115 }
    116 
    117 class Dashing2GM : public skiagm::GM {
    118 public:
    119     Dashing2GM() {}
    120 
    121 protected:
    122     SkString onShortName() {
    123         return SkString("dashing2");
    124     }
    125 
    126     SkISize onISize() { return skiagm::make_isize(640, 480); }
    127 
    128     virtual void onDraw(SkCanvas* canvas) {
    129         static const int gIntervals[] = {
    130             3,  // 3 dashes: each count [0] followed by intervals [1..count]
    131             2,  10, 10,
    132             4,  20, 5, 5, 5,
    133             2,  2, 2
    134         };
    135 
    136         void (*gProc[])(SkPath*, const SkRect&) = {
    137             make_path_line, make_path_rect, make_path_oval, make_path_star,
    138         };
    139 
    140         SkPaint paint;
    141         paint.setAntiAlias(true);
    142         paint.setStyle(SkPaint::kStroke_Style);
    143         paint.setStrokeWidth(SkIntToScalar(6));
    144 
    145         SkRect bounds = SkRect::MakeWH(SkIntToScalar(120), SkIntToScalar(120));
    146         bounds.offset(SkIntToScalar(20), SkIntToScalar(20));
    147         SkScalar dx = bounds.width() * 4 / 3;
    148         SkScalar dy = bounds.height() * 4 / 3;
    149 
    150         const int* intervals = &gIntervals[1];
    151         for (int y = 0; y < gIntervals[0]; ++y) {
    152             SkScalar vals[SK_ARRAY_COUNT(gIntervals)];  // more than enough
    153             int count = *intervals++;
    154             for (int i = 0; i < count; ++i) {
    155                 vals[i] = SkIntToScalar(*intervals++);
    156             }
    157             SkScalar phase = vals[0] / 2;
    158             paint.setPathEffect(new SkDashPathEffect(vals, count, phase))->unref();
    159 
    160             for (size_t x = 0; x < SK_ARRAY_COUNT(gProc); ++x) {
    161                 SkPath path;
    162                 SkRect r = bounds;
    163                 r.offset(x * dx, y * dy);
    164                 gProc[x](&path, r);
    165 
    166                 canvas->drawPath(path, paint);
    167             }
    168         }
    169     }
    170 };
    171 
    172 //////////////////////////////////////////////////////////////////////////////
    173 
    174 // Test out the on/off line dashing Chrome if fond of
    175 class Dashing3GM : public skiagm::GM {
    176 public:
    177     Dashing3GM() {}
    178 
    179 protected:
    180     SkString onShortName() {
    181         return SkString("dashing3");
    182     }
    183 
    184     SkISize onISize() { return skiagm::make_isize(640, 480); }
    185 
    186     // Draw a 100x100 block of dashed lines. The horizontal ones are BW
    187     // while the vertical ones are AA.
    188     void drawDashedLines(SkCanvas* canvas,
    189                          SkScalar lineLength,
    190                          SkScalar phase,
    191                          SkScalar dashLength,
    192                          int strokeWidth,
    193                          bool circles) {
    194         SkPaint p;
    195         p.setColor(SK_ColorBLACK);
    196         p.setStyle(SkPaint::kStroke_Style);
    197         p.setStrokeWidth(SkIntToScalar(strokeWidth));
    198 
    199         if (circles) {
    200             p.setStrokeCap(SkPaint::kRound_Cap);
    201         }
    202 
    203         SkScalar intervals[2] = { dashLength, dashLength };
    204 
    205         p.setPathEffect(new SkDashPathEffect(intervals, 2, phase, false));
    206 
    207         SkPoint pts[2];
    208 
    209         for (int y = 0; y < 100; y += 10*strokeWidth) {
    210             pts[0].set(0, SkIntToScalar(y));
    211             pts[1].set(lineLength, SkIntToScalar(y));
    212 
    213             canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
    214         }
    215 
    216         p.setAntiAlias(true);
    217 
    218         for (int x = 0; x < 100; x += 14*strokeWidth) {
    219             pts[0].set(SkIntToScalar(x), 0);
    220             pts[1].set(SkIntToScalar(x), lineLength);
    221 
    222             canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
    223         }
    224     }
    225 
    226     virtual void onDraw(SkCanvas* canvas) {
    227         // 1on/1off 1x1 squares with phase of 0 - points fastpath
    228         canvas->save();
    229             canvas->translate(2, 0);
    230             this->drawDashedLines(canvas, 100, 0, SK_Scalar1, 1, false);
    231         canvas->restore();
    232 
    233         // 1on/1off 1x1 squares with phase of .5 - rects fastpath (due to partial squares)
    234         canvas->save();
    235             canvas->translate(112, 0);
    236             this->drawDashedLines(canvas, 100, SK_ScalarHalf, SK_Scalar1, 1, false);
    237         canvas->restore();
    238 
    239         // 1on/1off 1x1 squares with phase of 1 - points fastpath
    240         canvas->save();
    241             canvas->translate(222, 0);
    242             this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, false);
    243         canvas->restore();
    244 
    245         // 1on/1off 1x1 squares with phase of 1 and non-integer length - rects fastpath
    246         canvas->save();
    247             canvas->translate(332, 0);
    248             this->drawDashedLines(canvas, 99.5f, SK_ScalarHalf, SK_Scalar1, 1, false);
    249         canvas->restore();
    250 
    251         // 255on/255off 1x1 squares with phase of 0 - rects fast path
    252         canvas->save();
    253             canvas->translate(446, 0);
    254             this->drawDashedLines(canvas, 100, 0, SkIntToScalar(255), 1, false);
    255         canvas->restore();
    256 
    257         // 1on/1off 3x3 squares with phase of 0 - points fast path
    258         canvas->save();
    259             canvas->translate(2, 110);
    260             this->drawDashedLines(canvas, 100, 0, SkIntToScalar(3), 3, false);
    261         canvas->restore();
    262 
    263         // 1on/1off 3x3 squares with phase of 1.5 - rects fast path
    264         canvas->save();
    265             canvas->translate(112, 110);
    266             this->drawDashedLines(canvas, 100, SkFloatToScalar(1.5f), SkIntToScalar(3), 3, false);
    267         canvas->restore();
    268 
    269         // 1on/1off 1x1 circles with phase of 1 - no fast path yet
    270         canvas->save();
    271             canvas->translate(2, 220);
    272             this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, true);
    273         canvas->restore();
    274 
    275         // 1on/1off 3x3 circles with phase of 1 - no fast path yet
    276         canvas->save();
    277             canvas->translate(112, 220);
    278             this->drawDashedLines(canvas, 100, 0, SkIntToScalar(3), 3, true);
    279         canvas->restore();
    280 
    281         // 1on/1off 1x1 squares with rotation - should break fast path
    282         canvas->save();
    283             canvas->translate(332+SK_ScalarRoot2Over2*100, 110+SK_ScalarRoot2Over2*100);
    284             canvas->rotate(45);
    285             canvas->translate(-50, -50);
    286 
    287             this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, false);
    288         canvas->restore();
    289 
    290         // 3on/3off 3x1 rects - should use rect fast path regardless of phase
    291         for (int phase = 0; phase <= 3; ++phase) {
    292             canvas->save();
    293                 canvas->translate(SkIntToScalar(phase*110+2),
    294                                   SkIntToScalar(330));
    295                 this->drawDashedLines(canvas, 100, SkIntToScalar(phase), SkIntToScalar(3), 1, false);
    296             canvas->restore();
    297         }
    298     }
    299 
    300 };
    301 
    302 //////////////////////////////////////////////////////////////////////////////
    303 
    304 static skiagm::GM* F0(void*) { return new DashingGM; }
    305 static skiagm::GM* F1(void*) { return new Dashing2GM; }
    306 static skiagm::GM* F2(void*) { return new Dashing3GM; }
    307 
    308 static skiagm::GMRegistry gR0(F0);
    309 static skiagm::GMRegistry gR1(F1);
    310 static skiagm::GMRegistry gR2(F2);
    311