• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 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 "SkPath.h"
10 #include "SkRandom.h"
11 #include "SkDashPathEffect.h"
12 #include "SkParsePath.h"
13 
14 #define W   400
15 #define H   400
16 #define N   50
17 
18 static const SkScalar SW = SkIntToScalar(W);
19 static const SkScalar SH = SkIntToScalar(H);
20 
rnd_rect(SkRect * r,SkPaint * paint,SkRandom & rand)21 static void rnd_rect(SkRect* r, SkPaint* paint, SkRandom& rand) {
22     SkScalar x = rand.nextUScalar1() * W;
23     SkScalar y = rand.nextUScalar1() * H;
24     SkScalar w = rand.nextUScalar1() * (W >> 2);
25     SkScalar h = rand.nextUScalar1() * (H >> 2);
26     SkScalar hoffset = rand.nextSScalar1();
27     SkScalar woffset = rand.nextSScalar1();
28 
29     r->set(x, y, x + w, y + h);
30     r->offset(-w/2 + woffset, -h/2 + hoffset);
31 
32     paint->setColor(rand.nextU());
33     paint->setAlpha(0xFF);
34 }
35 
36 
37 class StrokesGM : public skiagm::GM {
38 public:
StrokesGM()39     StrokesGM() {}
40 
41 protected:
42 
onShortName()43     SkString onShortName() override {
44         return SkString("strokes_round");
45     }
46 
onISize()47     SkISize onISize() override {
48         return SkISize::Make(W, H*2);
49     }
50 
onDraw(SkCanvas * canvas)51     void onDraw(SkCanvas* canvas) override {
52         SkPaint paint;
53         paint.setStyle(SkPaint::kStroke_Style);
54         paint.setStrokeWidth(SkIntToScalar(9)/2);
55 
56         for (int y = 0; y < 2; y++) {
57             paint.setAntiAlias(!!y);
58             SkAutoCanvasRestore acr(canvas, true);
59             canvas->translate(0, SH * y);
60             canvas->clipRect(SkRect::MakeLTRB(
61                                               SkIntToScalar(2), SkIntToScalar(2)
62                                               , SW - SkIntToScalar(2), SH - SkIntToScalar(2)
63                                               ));
64 
65             SkRandom rand;
66             for (int i = 0; i < N; i++) {
67                 SkRect r;
68                 rnd_rect(&r, &paint, rand);
69                 canvas->drawOval(r, paint);
70                 rnd_rect(&r, &paint, rand);
71                 canvas->drawRoundRect(r, r.width()/4, r.height()/4, paint);
72                 rnd_rect(&r, &paint, rand);
73             }
74         }
75     }
76 
77 private:
78     typedef skiagm::GM INHERITED;
79 };
80 
81 /* See
82    https://code.google.com/p/chromium/issues/detail?id=422974          and
83    http://jsfiddle.net/1xnku3sg/2/
84  */
85 class ZeroLenStrokesGM : public skiagm::GM {
86     SkPath fMoveHfPath, fMoveZfPath, fDashedfPath, fRefPath[4];
87     SkPath fCubicPath, fQuadPath, fLinePath;
88 protected:
onOnceBeforeDraw()89     void onOnceBeforeDraw() override {
90 
91         SkAssertResult(SkParsePath::FromSVGString("M0,0h0M10,0h0M20,0h0", &fMoveHfPath));
92         SkAssertResult(SkParsePath::FromSVGString("M0,0zM10,0zM20,0z", &fMoveZfPath));
93         SkAssertResult(SkParsePath::FromSVGString("M0,0h25", &fDashedfPath));
94         SkAssertResult(SkParsePath::FromSVGString("M 0 0 C 0 0 0 0 0 0", &fCubicPath));
95         SkAssertResult(SkParsePath::FromSVGString("M 0 0 Q 0 0 0 0", &fQuadPath));
96         SkAssertResult(SkParsePath::FromSVGString("M 0 0 L 0 0", &fLinePath));
97 
98         for (int i = 0; i < 3; ++i) {
99             fRefPath[0].addCircle(i * 10.f, 0, 5);
100             fRefPath[1].addCircle(i * 10.f, 0, 10);
101             fRefPath[2].addRect(i * 10.f - 4, -2, i * 10.f + 4, 6);
102             fRefPath[3].addRect(i * 10.f - 10, -10, i * 10.f + 10, 10);
103         }
104     }
105 
onShortName()106     SkString onShortName() override {
107         return SkString("zeroPath");
108     }
109 
onISize()110     SkISize onISize() override {
111         return SkISize::Make(W, H*2);
112     }
113 
onDraw(SkCanvas * canvas)114     void onDraw(SkCanvas* canvas) override {
115         SkPaint fillPaint, strokePaint, dashPaint;
116         fillPaint.setAntiAlias(true);
117         strokePaint = fillPaint;
118         strokePaint.setStyle(SkPaint::kStroke_Style);
119         for (int i = 0; i < 2; ++i) {
120             fillPaint.setAlpha(255);
121             strokePaint.setAlpha(255);
122             strokePaint.setStrokeWidth(i ? 8.f : 10.f);
123             strokePaint.setStrokeCap(i ? SkPaint::kSquare_Cap : SkPaint::kRound_Cap);
124             canvas->save();
125             canvas->translate(10 + i * 100.f, 10);
126             canvas->drawPath(fMoveHfPath, strokePaint);
127             canvas->translate(0, 20);
128             canvas->drawPath(fMoveZfPath, strokePaint);
129             dashPaint = strokePaint;
130             const SkScalar intervals[] = { 0, 10 };
131             dashPaint.setPathEffect(SkDashPathEffect::Create(intervals, 2, 0))->unref();
132             SkPath fillPath;
133             dashPaint.getFillPath(fDashedfPath, &fillPath);
134             canvas->translate(0, 20);
135             canvas->drawPath(fDashedfPath, dashPaint);
136             canvas->translate(0, 20);
137             canvas->drawPath(fRefPath[i * 2], fillPaint);
138             strokePaint.setStrokeWidth(20);
139             strokePaint.setAlpha(127);
140             canvas->translate(0, 50);
141             canvas->drawPath(fMoveHfPath, strokePaint);
142             canvas->translate(0, 30);
143             canvas->drawPath(fMoveZfPath, strokePaint);
144             canvas->translate(0, 30);
145             fillPaint.setAlpha(127);
146             canvas->drawPath(fRefPath[1 + i * 2], fillPaint);
147             canvas->translate(0, 30);
148             canvas->drawPath(fCubicPath, strokePaint);
149             canvas->translate(0, 30);
150             canvas->drawPath(fQuadPath, strokePaint);
151             canvas->translate(0, 30);
152             canvas->drawPath(fLinePath, strokePaint);
153             canvas->restore();
154         }
155     }
156 
157 private:
158     typedef skiagm::GM INHERITED;
159 };
160 
161 class TeenyStrokesGM : public skiagm::GM {
162 
onShortName()163     SkString onShortName() override {
164         return SkString("teenyStrokes");
165     }
166 
onISize()167     SkISize onISize() override {
168         return SkISize::Make(W, H*2);
169     }
170 
line(SkScalar scale,SkCanvas * canvas,SkColor color)171     static void line(SkScalar scale, SkCanvas* canvas, SkColor color) {
172         SkPaint p;
173         p.setAntiAlias(true);
174         p.setStyle(SkPaint::kStroke_Style);
175         p.setColor(color);
176         canvas->translate(50, 0);
177 	    canvas->save();
178         p.setStrokeWidth(scale * 5);
179 	    canvas->scale(1 / scale, 1 / scale);
180         canvas->drawLine(20 * scale, 20 * scale, 20 * scale, 100 * scale, p);
181         canvas->drawLine(20 * scale, 20 * scale, 100 * scale, 100 * scale, p);
182         canvas->restore();
183     }
184 
onDraw(SkCanvas * canvas)185     void onDraw(SkCanvas* canvas) override {
186         line(0.00005f, canvas, SK_ColorBLACK);
187         line(0.000045f, canvas, SK_ColorRED);
188         line(0.0000035f, canvas, SK_ColorGREEN);
189         line(0.000003f, canvas, SK_ColorBLUE);
190         line(0.000002f, canvas, SK_ColorBLACK);
191     }
192 private:
193     typedef skiagm::GM INHERITED;
194 };
195 
196 DEF_SIMPLE_GM(CubicStroke, canvas, 384, 384) {
197     SkPaint p;
198     p.setAntiAlias(true);
199     p.setStyle(SkPaint::kStroke_Style);
200     p.setStrokeWidth(1.0720f);
201 	SkPath path;
202     path.moveTo(-6000,-6000);
203     path.cubicTo(-3500,5500,-500,5500,2500,-6500);
204     canvas->drawPath(path, p);
205     p.setStrokeWidth(1.0721f);
206     canvas->translate(10, 10);
207     canvas->drawPath(path, p);
208     p.setStrokeWidth(1.0722f);
209     canvas->translate(10, 10);
210     canvas->drawPath(path, p);
211 }
212 
213 DEF_SIMPLE_GM(zerolinestroke, canvas, 90, 120) {
214     SkPaint paint;
215     paint.setStyle(SkPaint::kStroke_Style);
216     paint.setStrokeWidth(20);
217     paint.setAntiAlias(true);
218     paint.setStrokeCap(SkPaint::kRound_Cap);
219 
220     SkPath path;
221     path.moveTo(30, 90);
222     path.lineTo(30, 90);
223     path.lineTo(60, 90);
224     path.lineTo(60, 90);
225     canvas->drawPath(path, paint);
226 
227     path.reset();
228     path.moveTo(30, 30);
229     path.lineTo(60, 30);
230     canvas->drawPath(path, paint);
231 
232     path.reset();
233     path.moveTo(30, 60);
234     path.lineTo(30, 60);
235     path.lineTo(60, 60);
236     canvas->drawPath(path, paint);
237 }
238 
239 DEF_SIMPLE_GM(quadcap, canvas, 200, 200) {
240     SkPaint p;
241     p.setAntiAlias(true);
242     p.setStyle(SkPaint::kStroke_Style);
243     p.setStrokeWidth(0);
244     SkPath path;
245     SkPoint pts[] = {{105.738571f,13.126318f},
246             {105.738571f,13.126318f},
247             {123.753784f,1.f}};
248     SkVector tangent = pts[1] - pts[2];
249     tangent.normalize();
250     SkPoint pts2[3];
251     memcpy(pts2, pts, sizeof(pts));
252     const SkScalar capOutset = SK_ScalarPI / 8;
253     pts2[0].fX += tangent.fX * capOutset;
254     pts2[0].fY += tangent.fY * capOutset;
255     pts2[1].fX += tangent.fX * capOutset;
256     pts2[1].fY += tangent.fY * capOutset;
257     pts2[2].fX += -tangent.fX * capOutset;
258     pts2[2].fY += -tangent.fY * capOutset;
259     path.moveTo(pts2[0]);
260     path.quadTo(pts2[1], pts2[2]);
261     canvas->drawPath(path, p);
262 
263     path.reset();
264     path.moveTo(pts[0]);
265     path.quadTo(pts[1], pts[2]);
266     p.setStrokeCap(SkPaint::kRound_Cap);
267     canvas->translate(30, 0);
268     canvas->drawPath(path, p);
269 }
270 
271 class Strokes2GM : public skiagm::GM {
272     SkPath fPath;
273 protected:
onOnceBeforeDraw()274     void onOnceBeforeDraw() override {
275         SkRandom rand;
276         fPath.moveTo(0, 0);
277         for (int i = 0; i < 13; i++) {
278             SkScalar x = rand.nextUScalar1() * (W >> 1);
279             SkScalar y = rand.nextUScalar1() * (H >> 1);
280             fPath.lineTo(x, y);
281         }
282     }
283 
284 
onShortName()285     SkString onShortName() override {
286         return SkString("strokes_poly");
287     }
288 
onISize()289     SkISize onISize() override {
290         return SkISize::Make(W, H*2);
291     }
292 
rotate(SkScalar angle,SkScalar px,SkScalar py,SkCanvas * canvas)293     static void rotate(SkScalar angle, SkScalar px, SkScalar py, SkCanvas* canvas) {
294         SkMatrix matrix;
295         matrix.setRotate(angle, px, py);
296         canvas->concat(matrix);
297     }
298 
onDraw(SkCanvas * canvas)299     void onDraw(SkCanvas* canvas) override {
300         canvas->drawColor(SK_ColorWHITE);
301 
302         SkPaint paint;
303         paint.setStyle(SkPaint::kStroke_Style);
304         paint.setStrokeWidth(SkIntToScalar(9)/2);
305 
306         for (int y = 0; y < 2; y++) {
307             paint.setAntiAlias(!!y);
308             SkAutoCanvasRestore acr(canvas, true);
309             canvas->translate(0, SH * y);
310             canvas->clipRect(SkRect::MakeLTRB(SkIntToScalar(2),
311                                               SkIntToScalar(2),
312                                               SW - SkIntToScalar(2),
313                                               SH - SkIntToScalar(2)));
314 
315             SkRandom rand;
316             for (int i = 0; i < N/2; i++) {
317                 SkRect r;
318                 rnd_rect(&r, &paint, rand);
319                 rotate(SkIntToScalar(15), SW/2, SH/2, canvas);
320                 canvas->drawPath(fPath, paint);
321             }
322         }
323     }
324 
325 private:
326     typedef skiagm::GM INHERITED;
327 };
328 
329 //////////////////////////////////////////////////////////////////////////////
330 
inset(const SkRect & r)331 static SkRect inset(const SkRect& r) {
332     SkRect rr(r);
333     rr.inset(r.width()/10, r.height()/10);
334     return rr;
335 }
336 
337 class Strokes3GM : public skiagm::GM {
make0(SkPath * path,const SkRect & bounds,SkString * title)338     static void make0(SkPath* path, const SkRect& bounds, SkString* title) {
339         path->addRect(bounds, SkPath::kCW_Direction);
340         path->addRect(inset(bounds), SkPath::kCW_Direction);
341         title->set("CW CW");
342     }
343 
make1(SkPath * path,const SkRect & bounds,SkString * title)344     static void make1(SkPath* path, const SkRect& bounds, SkString* title) {
345         path->addRect(bounds, SkPath::kCW_Direction);
346         path->addRect(inset(bounds), SkPath::kCCW_Direction);
347         title->set("CW CCW");
348     }
349 
make2(SkPath * path,const SkRect & bounds,SkString * title)350     static void make2(SkPath* path, const SkRect& bounds, SkString* title) {
351         path->addOval(bounds, SkPath::kCW_Direction);
352         path->addOval(inset(bounds), SkPath::kCW_Direction);
353         title->set("CW CW");
354     }
355 
make3(SkPath * path,const SkRect & bounds,SkString * title)356     static void make3(SkPath* path, const SkRect& bounds, SkString* title) {
357         path->addOval(bounds, SkPath::kCW_Direction);
358         path->addOval(inset(bounds), SkPath::kCCW_Direction);
359         title->set("CW CCW");
360     }
361 
make4(SkPath * path,const SkRect & bounds,SkString * title)362     static void make4(SkPath* path, const SkRect& bounds, SkString* title) {
363         path->addRect(bounds, SkPath::kCW_Direction);
364         SkRect r = bounds;
365         r.inset(bounds.width() / 10, -bounds.height() / 10);
366         path->addOval(r, SkPath::kCW_Direction);
367         title->set("CW CW");
368     }
369 
make5(SkPath * path,const SkRect & bounds,SkString * title)370     static void make5(SkPath* path, const SkRect& bounds, SkString* title) {
371         path->addRect(bounds, SkPath::kCW_Direction);
372         SkRect r = bounds;
373         r.inset(bounds.width() / 10, -bounds.height() / 10);
374         path->addOval(r, SkPath::kCCW_Direction);
375         title->set("CW CCW");
376     }
377 
378 public:
Strokes3GM()379     Strokes3GM() {}
380 
381 protected:
382 
onShortName()383     SkString onShortName() override {
384         return SkString("strokes3");
385     }
386 
onISize()387     SkISize onISize() override {
388         return SkISize::Make(1500, 1500);
389     }
390 
onDraw(SkCanvas * canvas)391     void onDraw(SkCanvas* canvas) override {
392         SkPaint origPaint;
393         origPaint.setAntiAlias(true);
394         origPaint.setStyle(SkPaint::kStroke_Style);
395         SkPaint fillPaint(origPaint);
396         fillPaint.setColor(SK_ColorRED);
397         SkPaint strokePaint(origPaint);
398         strokePaint.setColor(sk_tool_utils::color_to_565(0xFF4444FF));
399 
400         void (*procs[])(SkPath*, const SkRect&, SkString*) = {
401             make0, make1, make2, make3, make4, make5
402         };
403 
404         canvas->translate(SkIntToScalar(20), SkIntToScalar(80));
405 
406         SkRect bounds = SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(50));
407         SkScalar dx = bounds.width() * 4/3;
408         SkScalar dy = bounds.height() * 5;
409 
410         for (size_t i = 0; i < SK_ARRAY_COUNT(procs); ++i) {
411             SkPath orig;
412             SkString str;
413             procs[i](&orig, bounds, &str);
414 
415             canvas->save();
416             for (int j = 0; j < 13; ++j) {
417                 strokePaint.setStrokeWidth(SK_Scalar1 * j * j);
418                 canvas->drawPath(orig, strokePaint);
419                 canvas->drawPath(orig, origPaint);
420                 SkPath fill;
421                 strokePaint.getFillPath(orig, &fill);
422                 canvas->drawPath(fill, fillPaint);
423                 canvas->translate(dx + strokePaint.getStrokeWidth(), 0);
424             }
425             canvas->restore();
426             canvas->translate(0, dy);
427         }
428     }
429 
430 private:
431     typedef skiagm::GM INHERITED;
432 };
433 
434 class Strokes4GM : public skiagm::GM {
435 public:
Strokes4GM()436     Strokes4GM() {}
437 
438 protected:
439 
onShortName()440     SkString onShortName() override {
441         return SkString("strokes_zoomed");
442     }
443 
onISize()444     SkISize onISize() override {
445         return SkISize::Make(W, H*2);
446     }
447 
onDraw(SkCanvas * canvas)448     void onDraw(SkCanvas* canvas) override {
449         SkPaint paint;
450         paint.setStyle(SkPaint::kStroke_Style);
451         paint.setStrokeWidth(0.055f);
452 
453         canvas->scale(1000, 1000);
454         canvas->drawCircle(0, 2, 1.97f, paint);
455     }
456 
457 private:
458     typedef skiagm::GM INHERITED;
459 };
460 
461 // Test stroking for curves that produce degenerate tangents when t is 0 or 1 (see bug 4191)
462 class Strokes5GM : public skiagm::GM {
463 public:
Strokes5GM()464     Strokes5GM() {}
465 
466 protected:
467 
onShortName()468     SkString onShortName() override {
469         return SkString("zero_control_stroke");
470     }
471 
onISize()472     SkISize onISize() override {
473         return SkISize::Make(W, H*2);
474     }
475 
onDraw(SkCanvas * canvas)476     void onDraw(SkCanvas* canvas) override {
477         SkPaint p;
478         p.setColor(SK_ColorRED);
479         p.setAntiAlias(true);
480         p.setStyle(SkPaint::kStroke_Style);
481         p.setStrokeWidth(40);
482         p.setStrokeCap(SkPaint::kButt_Cap);
483 
484         SkPath path;
485         path.moveTo(157.474f,111.753f);
486         path.cubicTo(128.5f,111.5f,35.5f,29.5f,35.5f,29.5f);
487         canvas->drawPath(path, p);
488         path.reset();
489         path.moveTo(250, 50);
490         path.quadTo(280, 80, 280, 80);
491         canvas->drawPath(path, p);
492         path.reset();
493         path.moveTo(150, 50);
494         path.conicTo(180, 80, 180, 80, 0.707f);
495         canvas->drawPath(path, p);
496 
497         path.reset();
498         path.moveTo(157.474f,311.753f);
499         path.cubicTo(157.474f,311.753f,85.5f,229.5f,35.5f,229.5f);
500         canvas->drawPath(path, p);
501         path.reset();
502         path.moveTo(280, 250);
503         path.quadTo(280, 250, 310, 280);
504         canvas->drawPath(path, p);
505         path.reset();
506         path.moveTo(180, 250);
507         path.conicTo(180, 250, 210, 280, 0.707f);
508         canvas->drawPath(path, p);
509     }
510 
511 private:
512     typedef skiagm::GM INHERITED;
513 };
514 
515 
516 //////////////////////////////////////////////////////////////////////////////
517 
518 DEF_GM( return new StrokesGM; )
519 DEF_GM( return new Strokes2GM; )
520 DEF_GM( return new Strokes3GM; )
521 DEF_GM( return new Strokes4GM; )
522 DEF_GM( return new Strokes5GM; )
523 
524 DEF_GM( return new ZeroLenStrokesGM; )
525 DEF_GM( return new TeenyStrokesGM; )
526