2016-01-19 16:07:49 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2016 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "gm/gm.h"
|
2019-05-01 21:28:53 +00:00
|
|
|
#include "include/core/SkCanvas.h"
|
|
|
|
#include "include/core/SkColor.h"
|
|
|
|
#include "include/core/SkMatrix.h"
|
|
|
|
#include "include/core/SkPaint.h"
|
2020-08-17 18:14:13 +00:00
|
|
|
#include "include/core/SkPathBuilder.h"
|
2019-05-01 21:28:53 +00:00
|
|
|
#include "include/core/SkPathEffect.h"
|
|
|
|
#include "include/core/SkRect.h"
|
|
|
|
#include "include/core/SkRefCnt.h"
|
|
|
|
#include "include/core/SkScalar.h"
|
|
|
|
#include "include/core/SkSize.h"
|
|
|
|
#include "include/core/SkString.h"
|
|
|
|
#include "include/core/SkTypes.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/effects/SkDashPathEffect.h"
|
2019-07-11 20:32:53 +00:00
|
|
|
#include "tools/timer/TimeUtils.h"
|
2016-01-19 16:07:49 +00:00
|
|
|
|
|
|
|
int dash1[] = { 1, 1 };
|
|
|
|
int dash2[] = { 1, 3 };
|
|
|
|
int dash3[] = { 1, 1, 3, 3 };
|
|
|
|
int dash4[] = { 1, 3, 2, 4 };
|
|
|
|
|
|
|
|
struct DashExample {
|
|
|
|
int* pattern;
|
|
|
|
int length;
|
|
|
|
} dashExamples[] = {
|
|
|
|
{ dash1, SK_ARRAY_COUNT(dash1) },
|
|
|
|
{ dash2, SK_ARRAY_COUNT(dash2) },
|
|
|
|
{ dash3, SK_ARRAY_COUNT(dash3) },
|
|
|
|
{ dash4, SK_ARRAY_COUNT(dash4) }
|
|
|
|
};
|
|
|
|
|
2016-04-08 20:35:14 +00:00
|
|
|
|
|
|
|
class DashCircleGM : public skiagm::GM {
|
|
|
|
public:
|
|
|
|
DashCircleGM() : fRotation(0) { }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
SkString onShortName() override { return SkString("dashcircle"); }
|
|
|
|
|
|
|
|
SkISize onISize() override { return SkISize::Make(900, 1200); }
|
|
|
|
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
|
|
SkPaint refPaint;
|
|
|
|
refPaint.setAntiAlias(true);
|
|
|
|
refPaint.setColor(0xFFbf3f7f);
|
2020-05-19 01:25:44 +00:00
|
|
|
refPaint.setStroke(true);
|
2016-04-08 20:35:14 +00:00
|
|
|
refPaint.setStrokeWidth(1);
|
|
|
|
const SkScalar radius = 125;
|
|
|
|
SkRect oval = SkRect::MakeLTRB(-radius - 20, -radius - 20, radius + 20, radius + 20);
|
2020-08-25 15:48:41 +00:00
|
|
|
SkPath circle = SkPath::Circle(0, 0, radius);
|
2016-04-08 20:35:14 +00:00
|
|
|
SkScalar circumference = radius * SK_ScalarPI * 2;
|
|
|
|
int wedges[] = { 6, 12, 36 };
|
|
|
|
canvas->translate(radius+20, radius+20);
|
|
|
|
for (int wedge : wedges) {
|
|
|
|
SkScalar arcLength = 360.f / wedge;
|
|
|
|
canvas->save();
|
|
|
|
for (const DashExample& dashExample : dashExamples) {
|
2020-08-17 18:14:13 +00:00
|
|
|
SkPathBuilder refPath;
|
2016-04-08 20:35:14 +00:00
|
|
|
int dashUnits = 0;
|
|
|
|
for (int index = 0; index < dashExample.length; ++index) {
|
|
|
|
dashUnits += dashExample.pattern[index];
|
2016-01-19 16:07:49 +00:00
|
|
|
}
|
2016-04-08 20:35:14 +00:00
|
|
|
SkScalar unitLength = arcLength / dashUnits;
|
|
|
|
SkScalar angle = 0;
|
|
|
|
for (int index = 0; index < wedge; ++index) {
|
|
|
|
for (int i2 = 0; i2 < dashExample.length; i2 += 2) {
|
|
|
|
SkScalar span = dashExample.pattern[i2] * unitLength;
|
|
|
|
refPath.moveTo(0, 0);
|
|
|
|
refPath.arcTo(oval, angle, span, false);
|
|
|
|
refPath.close();
|
|
|
|
angle += span + (dashExample.pattern[i2 + 1]) * unitLength;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
canvas->save();
|
|
|
|
canvas->rotate(fRotation);
|
2020-08-17 18:14:13 +00:00
|
|
|
canvas->drawPath(refPath.detach(), refPaint);
|
2016-04-08 20:35:14 +00:00
|
|
|
canvas->restore();
|
|
|
|
SkPaint p;
|
|
|
|
p.setAntiAlias(true);
|
2020-05-19 01:25:44 +00:00
|
|
|
p.setStroke(true);
|
2016-04-08 20:35:14 +00:00
|
|
|
p.setStrokeWidth(10);
|
|
|
|
SkScalar intervals[4];
|
|
|
|
int intervalCount = dashExample.length;
|
|
|
|
SkScalar dashLength = circumference / wedge / dashUnits;
|
|
|
|
for (int index = 0; index < dashExample.length; ++index) {
|
|
|
|
intervals[index] = dashExample.pattern[index] * dashLength;
|
|
|
|
}
|
|
|
|
p.setPathEffect(SkDashPathEffect::Make(intervals, intervalCount, 0));
|
|
|
|
canvas->save();
|
|
|
|
canvas->rotate(fRotation);
|
|
|
|
canvas->drawPath(circle, p);
|
|
|
|
canvas->restore();
|
|
|
|
canvas->translate(0, radius * 2 + 50);
|
2016-01-19 16:07:49 +00:00
|
|
|
}
|
2016-04-08 20:35:14 +00:00
|
|
|
canvas->restore();
|
|
|
|
canvas->translate(radius * 2 + 50, 0);
|
2016-01-19 16:07:49 +00:00
|
|
|
}
|
|
|
|
}
|
2016-04-08 20:35:14 +00:00
|
|
|
|
2019-07-11 20:32:53 +00:00
|
|
|
bool onAnimate(double nanos) override {
|
2016-09-01 18:24:54 +00:00
|
|
|
constexpr SkScalar kDesiredDurationSecs = 100.0f;
|
2016-04-08 20:35:14 +00:00
|
|
|
|
2019-07-11 20:32:53 +00:00
|
|
|
fRotation = TimeUtils::Scaled(1e-9 * nanos, 360.0f/kDesiredDurationSecs, 360.0f);
|
2016-04-08 20:35:14 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
SkScalar fRotation;
|
|
|
|
|
2020-09-03 02:42:33 +00:00
|
|
|
using INHERITED = GM;
|
2016-04-08 20:35:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
DEF_GM(return new DashCircleGM; )
|
2018-04-20 17:54:11 +00:00
|
|
|
|
|
|
|
class DashCircle2GM : public skiagm::GM {
|
|
|
|
public:
|
|
|
|
DashCircle2GM() {}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
SkString onShortName() override { return SkString("dashcircle2"); }
|
|
|
|
|
|
|
|
SkISize onISize() override { return SkISize::Make(635, 900); }
|
|
|
|
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
|
|
// These intervals are defined relative to tau.
|
|
|
|
static constexpr SkScalar kIntervals[][2]{
|
|
|
|
{0.333f, 0.333f},
|
|
|
|
{0.015f, 0.015f},
|
|
|
|
{0.01f , 0.09f },
|
|
|
|
{0.097f, 0.003f},
|
|
|
|
{0.02f , 0.04f },
|
|
|
|
{0.1f , 0.2f },
|
|
|
|
{0.25f , 0.25f },
|
|
|
|
{0.6f , 0.7f }, // adds to > 1
|
|
|
|
{1.2f , 0.8f }, // on is > 1
|
|
|
|
{0.1f , 1.1f }, // off is > 1*/
|
|
|
|
};
|
|
|
|
|
|
|
|
static constexpr int kN = SK_ARRAY_COUNT(kIntervals);
|
|
|
|
static constexpr SkScalar kRadius = 20.f;
|
|
|
|
static constexpr SkScalar kStrokeWidth = 15.f;
|
|
|
|
static constexpr SkScalar kPad = 5.f;
|
|
|
|
static constexpr SkRect kCircle = {-kRadius, -kRadius, kRadius, kRadius};
|
|
|
|
|
|
|
|
static constexpr SkScalar kThinRadius = kRadius * 1.5;
|
|
|
|
static constexpr SkRect kThinCircle = {-kThinRadius, -kThinRadius,
|
|
|
|
kThinRadius, kThinRadius};
|
|
|
|
static constexpr SkScalar kThinStrokeWidth = 0.4f;
|
|
|
|
|
|
|
|
sk_sp<SkPathEffect> deffects[SK_ARRAY_COUNT(kIntervals)];
|
|
|
|
sk_sp<SkPathEffect> thinDEffects[SK_ARRAY_COUNT(kIntervals)];
|
|
|
|
for (int i = 0; i < kN; ++i) {
|
|
|
|
static constexpr SkScalar kTau = 2 * SK_ScalarPI;
|
|
|
|
static constexpr SkScalar kCircumference = kRadius * kTau;
|
|
|
|
SkScalar scaledIntervals[2] = {kCircumference * kIntervals[i][0],
|
|
|
|
kCircumference * kIntervals[i][1]};
|
|
|
|
deffects[i] = SkDashPathEffect::Make(
|
|
|
|
scaledIntervals, 2, kCircumference * fPhaseDegrees * kTau / 360.f);
|
|
|
|
static constexpr SkScalar kThinCircumference = kThinRadius * kTau;
|
|
|
|
scaledIntervals[0] = kThinCircumference * kIntervals[i][0];
|
|
|
|
scaledIntervals[1] = kThinCircumference * kIntervals[i][1];
|
|
|
|
thinDEffects[i] = SkDashPathEffect::Make(
|
|
|
|
scaledIntervals, 2, kThinCircumference * fPhaseDegrees * kTau / 360.f);
|
|
|
|
}
|
|
|
|
|
|
|
|
SkMatrix rotate;
|
|
|
|
rotate.setRotate(25.f);
|
2021-03-01 19:31:18 +00:00
|
|
|
const SkMatrix kMatrices[]{
|
2018-04-20 17:54:11 +00:00
|
|
|
SkMatrix::I(),
|
2020-05-21 16:11:27 +00:00
|
|
|
SkMatrix::Scale(1.2f, 1.2f),
|
2018-04-20 17:54:11 +00:00
|
|
|
SkMatrix::MakeAll(1, 0, 0, 0, -1, 0, 0, 0, 1), // y flipper
|
|
|
|
SkMatrix::MakeAll(-1, 0, 0, 0, 1, 0, 0, 0, 1), // x flipper
|
2020-05-21 16:11:27 +00:00
|
|
|
SkMatrix::Scale(0.7f, 0.7f),
|
2018-04-20 17:54:11 +00:00
|
|
|
rotate,
|
|
|
|
SkMatrix::Concat(
|
|
|
|
SkMatrix::Concat(SkMatrix::MakeAll(-1, 0, 0, 0, 1, 0, 0, 0, 1), rotate),
|
|
|
|
rotate)
|
|
|
|
};
|
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setAntiAlias(true);
|
|
|
|
paint.setStrokeWidth(kStrokeWidth);
|
2020-05-19 01:25:44 +00:00
|
|
|
paint.setStroke(true);
|
2018-04-20 17:54:11 +00:00
|
|
|
|
|
|
|
// Compute the union of bounds of all of our test cases.
|
|
|
|
SkRect bounds = SkRect::MakeEmpty();
|
2021-03-01 19:31:18 +00:00
|
|
|
const SkRect kBounds = kThinCircle.makeOutset(kThinStrokeWidth / 2.f,
|
|
|
|
kThinStrokeWidth / 2.f);
|
2018-04-20 17:54:11 +00:00
|
|
|
for (const auto& m : kMatrices) {
|
|
|
|
SkRect devBounds;
|
|
|
|
m.mapRect(&devBounds, kBounds);
|
|
|
|
bounds.join(devBounds);
|
|
|
|
}
|
|
|
|
|
|
|
|
canvas->save();
|
|
|
|
canvas->translate(-bounds.fLeft + kPad, -bounds.fTop + kPad);
|
|
|
|
for (size_t i = 0; i < SK_ARRAY_COUNT(deffects); ++i) {
|
|
|
|
canvas->save();
|
|
|
|
for (const auto& m : kMatrices) {
|
|
|
|
canvas->save();
|
|
|
|
canvas->concat(m);
|
|
|
|
|
|
|
|
paint.setPathEffect(deffects[i]);
|
|
|
|
paint.setStrokeWidth(kStrokeWidth);
|
|
|
|
canvas->drawOval(kCircle, paint);
|
|
|
|
|
|
|
|
paint.setPathEffect(thinDEffects[i]);
|
|
|
|
paint.setStrokeWidth(kThinStrokeWidth);
|
|
|
|
canvas->drawOval(kThinCircle, paint);
|
|
|
|
|
|
|
|
canvas->restore();
|
|
|
|
canvas->translate(bounds.width() + kPad, 0);
|
|
|
|
}
|
|
|
|
canvas->restore();
|
|
|
|
canvas->translate(0, bounds.height() + kPad);
|
|
|
|
}
|
|
|
|
canvas->restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2019-07-11 20:32:53 +00:00
|
|
|
bool onAnimate(double nanos) override {
|
|
|
|
fPhaseDegrees = 1e-9 * nanos;
|
2018-04-20 17:54:11 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Init with a non-zero phase for when run as a non-animating GM.
|
|
|
|
SkScalar fPhaseDegrees = 12.f;
|
|
|
|
};
|
|
|
|
|
|
|
|
DEF_GM(return new DashCircle2GM;)
|
2018-12-04 19:52:40 +00:00
|
|
|
|
|
|
|
DEF_SIMPLE_GM(maddash, canvas, 1600, 1600) {
|
|
|
|
canvas->drawRect({0, 0, 1600, 1600}, SkPaint());
|
|
|
|
SkPaint p;
|
|
|
|
p.setColor(SK_ColorRED);
|
|
|
|
p.setAntiAlias(true);
|
2020-05-19 01:25:44 +00:00
|
|
|
p.setStroke(true);
|
2018-12-04 19:52:40 +00:00
|
|
|
p.setStrokeWidth(380);
|
|
|
|
|
|
|
|
SkScalar intvls[] = { 2.5, 10 /* 1200 */ };
|
|
|
|
p.setPathEffect(SkDashPathEffect::Make(intvls, 2, 0));
|
|
|
|
|
|
|
|
canvas->drawCircle(400, 400, 200, p);
|
|
|
|
|
2020-08-25 15:48:41 +00:00
|
|
|
SkPathBuilder path;
|
2018-12-04 19:52:40 +00:00
|
|
|
path.moveTo(800, 400);
|
|
|
|
path.quadTo(1000, 400, 1000, 600);
|
|
|
|
path.quadTo(1000, 800, 800, 800);
|
|
|
|
path.quadTo(600, 800, 600, 600);
|
|
|
|
path.quadTo(600, 400, 800, 400);
|
|
|
|
path.close();
|
|
|
|
canvas->translate(350, 150);
|
|
|
|
p.setStrokeWidth(320);
|
2020-08-25 15:48:41 +00:00
|
|
|
canvas->drawPath(path.detach(), p);
|
2018-12-04 19:52:40 +00:00
|
|
|
|
|
|
|
path.moveTo(800, 400);
|
|
|
|
path.cubicTo(900, 400, 1000, 500, 1000, 600);
|
|
|
|
path.cubicTo(1000, 700, 900, 800, 800, 800);
|
|
|
|
path.cubicTo(700, 800, 600, 700, 600, 600);
|
|
|
|
path.cubicTo(600, 500, 700, 400, 800, 400);
|
|
|
|
path.close();
|
|
|
|
canvas->translate(-550, 500);
|
|
|
|
p.setStrokeWidth(300);
|
2020-08-25 15:48:41 +00:00
|
|
|
canvas->drawPath(path.detach(), p);
|
2018-12-04 19:52:40 +00:00
|
|
|
}
|