• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
drawline(SkCanvas * canvas,int on,int off,const SkPaint & paint,SkScalar finalX=SkIntToScalar (600))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.
show_giant_dash(SkCanvas * canvas)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:
DashingGM()37     DashingGM() {}
38 
39 protected:
onShortName()40     SkString onShortName() {
41         return SkString("dashing");
42     }
43 
onISize()44     SkISize onISize() { return skiagm::make_isize(640, 300); }
45 
onDraw(SkCanvas * canvas)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 
make_unit_star(SkPath * path,int n)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 
make_path_line(SkPath * path,const SkRect & bounds)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 
make_path_rect(SkPath * path,const SkRect & bounds)102 static void make_path_rect(SkPath* path, const SkRect& bounds) {
103     path->addRect(bounds);
104 }
105 
make_path_oval(SkPath * path,const SkRect & bounds)106 static void make_path_oval(SkPath* path, const SkRect& bounds) {
107     path->addOval(bounds);
108 }
109 
make_path_star(SkPath * path,const SkRect & bounds)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:
Dashing2GM()119     Dashing2GM() {}
120 
121 protected:
onShortName()122     SkString onShortName() {
123         return SkString("dashing2");
124     }
125 
onISize()126     SkISize onISize() { return skiagm::make_isize(640, 480); }
127 
onDraw(SkCanvas * canvas)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:
Dashing3GM()177     Dashing3GM() {}
178 
179 protected:
onShortName()180     SkString onShortName() {
181         return SkString("dashing3");
182     }
183 
onISize()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.
drawDashedLines(SkCanvas * canvas,SkScalar lineLength,SkScalar phase,SkScalar dashLength,int strokeWidth,bool circles)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))->unref();
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 
onDraw(SkCanvas * canvas)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, 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 
F0(void *)304 static skiagm::GM* F0(void*) { return new DashingGM; }
F1(void *)305 static skiagm::GM* F1(void*) { return new Dashing2GM; }
F2(void *)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