• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 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/SkMatrix.h"
12 #include "include/core/SkPaint.h"
13 #include "include/core/SkPath.h"
14 #include "include/core/SkPathEffect.h"
15 #include "include/core/SkRect.h"
16 #include "include/core/SkRefCnt.h"
17 #include "include/core/SkScalar.h"
18 #include "include/core/SkSize.h"
19 #include "include/core/SkString.h"
20 #include "include/core/SkTypes.h"
21 #include "include/effects/SkDashPathEffect.h"
22 #include "tools/timer/TimeUtils.h"
23 
24 int dash1[] = { 1, 1 };
25 int dash2[] = { 1, 3 };
26 int dash3[] = { 1, 1, 3, 3 };
27 int dash4[] = { 1, 3, 2, 4 };
28 
29 struct DashExample {
30     int* pattern;
31     int length;
32 } dashExamples[] = {
33     { dash1, SK_ARRAY_COUNT(dash1) },
34     { dash2, SK_ARRAY_COUNT(dash2) },
35     { dash3, SK_ARRAY_COUNT(dash3) },
36     { dash4, SK_ARRAY_COUNT(dash4) }
37 };
38 
39 
40 class DashCircleGM : public skiagm::GM {
41 public:
DashCircleGM()42     DashCircleGM() : fRotation(0) { }
43 
44 protected:
onShortName()45     SkString onShortName() override { return SkString("dashcircle"); }
46 
onISize()47     SkISize onISize() override { return SkISize::Make(900, 1200); }
48 
onDraw(SkCanvas * canvas)49     void onDraw(SkCanvas* canvas) override {
50         SkPaint refPaint;
51         refPaint.setAntiAlias(true);
52         refPaint.setColor(0xFFbf3f7f);
53         refPaint.setStyle(SkPaint::kStroke_Style);
54         refPaint.setStrokeWidth(1);
55         const SkScalar radius = 125;
56         SkRect oval = SkRect::MakeLTRB(-radius - 20, -radius - 20, radius + 20, radius + 20);
57         SkPath circle;
58         circle.addCircle(0, 0, radius);
59         SkScalar circumference = radius * SK_ScalarPI * 2;
60         int wedges[] = { 6, 12, 36 };
61         canvas->translate(radius+20, radius+20);
62         for (int wedge : wedges) {
63             SkScalar arcLength = 360.f / wedge;
64             canvas->save();
65             for (const DashExample& dashExample : dashExamples) {
66                 SkPath refPath;
67                 int dashUnits = 0;
68                 for (int index = 0; index < dashExample.length; ++index) {
69                     dashUnits += dashExample.pattern[index];
70                 }
71                 SkScalar unitLength = arcLength / dashUnits;
72                 SkScalar angle = 0;
73                 for (int index = 0; index < wedge; ++index) {
74                     for (int i2 = 0; i2 < dashExample.length; i2 += 2) {
75                         SkScalar span = dashExample.pattern[i2] * unitLength;
76                         refPath.moveTo(0, 0);
77                         refPath.arcTo(oval, angle, span, false);
78                         refPath.close();
79                         angle += span + (dashExample.pattern[i2 + 1]) * unitLength;
80                     }
81                 }
82                 canvas->save();
83                 canvas->rotate(fRotation);
84                 canvas->drawPath(refPath, refPaint);
85                 canvas->restore();
86                 SkPaint p;
87                 p.setAntiAlias(true);
88                 p.setStyle(SkPaint::kStroke_Style);
89                 p.setStrokeWidth(10);
90                 SkScalar intervals[4];
91                 int intervalCount = dashExample.length;
92                 SkScalar dashLength = circumference / wedge / dashUnits;
93                 for (int index = 0; index < dashExample.length; ++index) {
94                     intervals[index] = dashExample.pattern[index] * dashLength;
95                 }
96                 p.setPathEffect(SkDashPathEffect::Make(intervals, intervalCount, 0));
97                 canvas->save();
98                 canvas->rotate(fRotation);
99                 canvas->drawPath(circle, p);
100                 canvas->restore();
101                 canvas->translate(0, radius * 2 + 50);
102             }
103             canvas->restore();
104             canvas->translate(radius * 2 + 50, 0);
105         }
106     }
107 
onAnimate(double nanos)108     bool onAnimate(double nanos) override {
109         constexpr SkScalar kDesiredDurationSecs = 100.0f;
110 
111         fRotation = TimeUtils::Scaled(1e-9 * nanos, 360.0f/kDesiredDurationSecs, 360.0f);
112         return true;
113     }
114 
115 private:
116     SkScalar fRotation;
117 
118     typedef GM INHERITED;
119 };
120 
121 DEF_GM(return new DashCircleGM; )
122 
123 class DashCircle2GM : public skiagm::GM {
124 public:
DashCircle2GM()125     DashCircle2GM() {}
126 
127 protected:
onShortName()128     SkString onShortName() override { return SkString("dashcircle2"); }
129 
onISize()130     SkISize onISize() override { return SkISize::Make(635, 900); }
131 
onDraw(SkCanvas * canvas)132     void onDraw(SkCanvas* canvas) override {
133         // These intervals are defined relative to tau.
134         static constexpr SkScalar kIntervals[][2]{
135                 {0.333f, 0.333f},
136                 {0.015f, 0.015f},
137                 {0.01f , 0.09f },
138                 {0.097f, 0.003f},
139                 {0.02f , 0.04f },
140                 {0.1f  , 0.2f  },
141                 {0.25f , 0.25f },
142                 {0.6f  , 0.7f  }, // adds to > 1
143                 {1.2f  , 0.8f  }, // on is > 1
144                 {0.1f  , 1.1f  }, // off is > 1*/
145         };
146 
147         static constexpr int kN = SK_ARRAY_COUNT(kIntervals);
148         static constexpr SkScalar kRadius = 20.f;
149         static constexpr SkScalar kStrokeWidth = 15.f;
150         static constexpr SkScalar kPad = 5.f;
151         static constexpr SkRect kCircle = {-kRadius, -kRadius, kRadius, kRadius};
152 
153         static constexpr SkScalar kThinRadius = kRadius * 1.5;
154         static constexpr SkRect kThinCircle = {-kThinRadius, -kThinRadius,
155                                                 kThinRadius,  kThinRadius};
156         static constexpr SkScalar kThinStrokeWidth = 0.4f;
157 
158         sk_sp<SkPathEffect> deffects[SK_ARRAY_COUNT(kIntervals)];
159         sk_sp<SkPathEffect> thinDEffects[SK_ARRAY_COUNT(kIntervals)];
160         for (int i = 0; i < kN; ++i) {
161             static constexpr SkScalar kTau = 2 * SK_ScalarPI;
162             static constexpr SkScalar kCircumference = kRadius * kTau;
163             SkScalar scaledIntervals[2] = {kCircumference * kIntervals[i][0],
164                                            kCircumference * kIntervals[i][1]};
165             deffects[i] = SkDashPathEffect::Make(
166                     scaledIntervals, 2, kCircumference * fPhaseDegrees * kTau / 360.f);
167             static constexpr SkScalar kThinCircumference = kThinRadius * kTau;
168             scaledIntervals[0] = kThinCircumference * kIntervals[i][0];
169             scaledIntervals[1] = kThinCircumference * kIntervals[i][1];
170             thinDEffects[i] = SkDashPathEffect::Make(
171                     scaledIntervals, 2, kThinCircumference * fPhaseDegrees * kTau / 360.f);
172         }
173 
174         SkMatrix rotate;
175         rotate.setRotate(25.f);
176         static const SkMatrix kMatrices[]{
177                 SkMatrix::I(),
178                 SkMatrix::MakeScale(1.2f),
179                 SkMatrix::MakeAll(1, 0, 0, 0, -1, 0, 0, 0, 1),  // y flipper
180                 SkMatrix::MakeAll(-1, 0, 0, 0, 1, 0, 0, 0, 1),  // x flipper
181                 SkMatrix::MakeScale(0.7f),
182                 rotate,
183                 SkMatrix::Concat(
184                         SkMatrix::Concat(SkMatrix::MakeAll(-1, 0, 0, 0, 1, 0, 0, 0, 1), rotate),
185                         rotate)
186         };
187 
188         SkPaint paint;
189         paint.setAntiAlias(true);
190         paint.setStrokeWidth(kStrokeWidth);
191         paint.setStyle(SkPaint::kStroke_Style);
192 
193         // Compute the union of bounds of all of our test cases.
194         SkRect bounds = SkRect::MakeEmpty();
195         static const SkRect kBounds = kThinCircle.makeOutset(kThinStrokeWidth / 2.f,
196                                                              kThinStrokeWidth / 2.f);
197         for (const auto& m : kMatrices) {
198             SkRect devBounds;
199             m.mapRect(&devBounds, kBounds);
200             bounds.join(devBounds);
201         }
202 
203         canvas->save();
204         canvas->translate(-bounds.fLeft + kPad, -bounds.fTop + kPad);
205         for (size_t i = 0; i < SK_ARRAY_COUNT(deffects); ++i) {
206             canvas->save();
207             for (const auto& m : kMatrices) {
208                 canvas->save();
209                 canvas->concat(m);
210 
211                 paint.setPathEffect(deffects[i]);
212                 paint.setStrokeWidth(kStrokeWidth);
213                 canvas->drawOval(kCircle, paint);
214 
215                 paint.setPathEffect(thinDEffects[i]);
216                 paint.setStrokeWidth(kThinStrokeWidth);
217                 canvas->drawOval(kThinCircle, paint);
218 
219                 canvas->restore();
220                 canvas->translate(bounds.width() + kPad, 0);
221             }
222             canvas->restore();
223             canvas->translate(0, bounds.height() + kPad);
224         }
225         canvas->restore();
226     }
227 
228 protected:
onAnimate(double nanos)229     bool onAnimate(double nanos) override {
230         fPhaseDegrees = 1e-9 * nanos;
231         return true;
232     }
233 
234     // Init with a non-zero phase for when run as a non-animating GM.
235     SkScalar fPhaseDegrees = 12.f;
236 };
237 
238 DEF_GM(return new DashCircle2GM;)
239 
240 DEF_SIMPLE_GM(maddash, canvas, 1600, 1600) {
241     canvas->drawRect({0, 0, 1600, 1600}, SkPaint());
242     SkPaint p;
243     p.setColor(SK_ColorRED);
244     p.setAntiAlias(true);
245     p.setStyle(SkPaint::kStroke_Style);
246     p.setStrokeWidth(380);
247 
248     SkScalar intvls[] = { 2.5, 10 /* 1200 */ };
249     p.setPathEffect(SkDashPathEffect::Make(intvls, 2, 0));
250 
251     canvas->drawCircle(400, 400, 200, p);
252 
253     SkPath path;
254     path.moveTo(800, 400);
255     path.quadTo(1000, 400, 1000, 600);
256     path.quadTo(1000, 800, 800, 800);
257     path.quadTo(600, 800, 600, 600);
258     path.quadTo(600, 400, 800, 400);
259     path.close();
260     canvas->translate(350, 150);
261     p.setStrokeWidth(320);
262     canvas->drawPath(path, p);
263 
264     path.reset();
265     path.moveTo(800, 400);
266     path.cubicTo(900, 400, 1000, 500, 1000, 600);
267     path.cubicTo(1000, 700, 900, 800, 800, 800);
268     path.cubicTo(700, 800, 600, 700, 600, 600);
269     path.cubicTo(600, 500, 700, 400, 800, 400);
270     path.close();
271     canvas->translate(-550, 500);
272     p.setStrokeWidth(300);
273     canvas->drawPath(path, p);
274 }
275