blob: 7942b34bb11d33af03ed6b9a310ecb28d504ac08 [file] [log] [blame]
caryclarkb6474dd2016-01-19 08:07:49 -08001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -04009#include "include/core/SkCanvas.h"
10#include "include/core/SkColor.h"
11#include "include/core/SkMatrix.h"
12#include "include/core/SkPaint.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/core/SkPath.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040014#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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "include/effects/SkDashPathEffect.h"
Hal Canary41248072019-07-11 16:32:53 -040022#include "tools/timer/TimeUtils.h"
caryclarkb6474dd2016-01-19 08:07:49 -080023
24int dash1[] = { 1, 1 };
25int dash2[] = { 1, 3 };
26int dash3[] = { 1, 1, 3, 3 };
27int dash4[] = { 1, 3, 2, 4 };
28
29struct 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
robertphillips651bb5f2016-04-08 13:35:14 -070039
40class DashCircleGM : public skiagm::GM {
41public:
42 DashCircleGM() : fRotation(0) { }
43
44protected:
45 SkString onShortName() override { return SkString("dashcircle"); }
46
47 SkISize onISize() override { return SkISize::Make(900, 1200); }
48
49 void onDraw(SkCanvas* canvas) override {
50 SkPaint refPaint;
51 refPaint.setAntiAlias(true);
52 refPaint.setColor(0xFFbf3f7f);
Mike Reed19630092020-05-18 21:25:44 -040053 refPaint.setStroke(true);
robertphillips651bb5f2016-04-08 13:35:14 -070054 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];
caryclarkb6474dd2016-01-19 08:07:49 -080070 }
robertphillips651bb5f2016-04-08 13:35:14 -070071 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);
Mike Reed19630092020-05-18 21:25:44 -040088 p.setStroke(true);
robertphillips651bb5f2016-04-08 13:35:14 -070089 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);
caryclarkb6474dd2016-01-19 08:07:49 -0800102 }
robertphillips651bb5f2016-04-08 13:35:14 -0700103 canvas->restore();
104 canvas->translate(radius * 2 + 50, 0);
caryclarkb6474dd2016-01-19 08:07:49 -0800105 }
caryclarkb6474dd2016-01-19 08:07:49 -0800106 }
robertphillips651bb5f2016-04-08 13:35:14 -0700107
Hal Canary41248072019-07-11 16:32:53 -0400108 bool onAnimate(double nanos) override {
mtkleindbfd7ab2016-09-01 11:24:54 -0700109 constexpr SkScalar kDesiredDurationSecs = 100.0f;
robertphillips651bb5f2016-04-08 13:35:14 -0700110
Hal Canary41248072019-07-11 16:32:53 -0400111 fRotation = TimeUtils::Scaled(1e-9 * nanos, 360.0f/kDesiredDurationSecs, 360.0f);
robertphillips651bb5f2016-04-08 13:35:14 -0700112 return true;
113 }
114
115private:
116 SkScalar fRotation;
117
118 typedef GM INHERITED;
119};
120
121DEF_GM(return new DashCircleGM; )
Brian Salomon62e4f3d2018-04-20 13:54:11 -0400122
123class DashCircle2GM : public skiagm::GM {
124public:
125 DashCircle2GM() {}
126
127protected:
128 SkString onShortName() override { return SkString("dashcircle2"); }
129
130 SkISize onISize() override { return SkISize::Make(635, 900); }
131
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(),
Mike Reed1f607332020-05-21 12:11:27 -0400178 SkMatrix::Scale(1.2f, 1.2f),
Brian Salomon62e4f3d2018-04-20 13:54:11 -0400179 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
Mike Reed1f607332020-05-21 12:11:27 -0400181 SkMatrix::Scale(0.7f, 0.7f),
Brian Salomon62e4f3d2018-04-20 13:54:11 -0400182 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);
Mike Reed19630092020-05-18 21:25:44 -0400191 paint.setStroke(true);
Brian Salomon62e4f3d2018-04-20 13:54:11 -0400192
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
228protected:
Hal Canary41248072019-07-11 16:32:53 -0400229 bool onAnimate(double nanos) override {
230 fPhaseDegrees = 1e-9 * nanos;
Brian Salomon62e4f3d2018-04-20 13:54:11 -0400231 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
238DEF_GM(return new DashCircle2GM;)
Cary Clarkdbf2aec2018-12-04 14:52:40 -0500239
240DEF_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);
Mike Reed19630092020-05-18 21:25:44 -0400245 p.setStroke(true);
Cary Clarkdbf2aec2018-12-04 14:52:40 -0500246 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}