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