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