1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2011 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlendMode.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPicture.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPictureRecorder.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTileMode.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkGradientShader.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "tools/fonts/FontToolUtils.h"
31*c8dee2aaSAndroid Build Coastguard Worker
32*c8dee2aaSAndroid Build Coastguard Worker #include <initializer_list>
33*c8dee2aaSAndroid Build Coastguard Worker #include <math.h>
34*c8dee2aaSAndroid Build Coastguard Worker
35*c8dee2aaSAndroid Build Coastguard Worker namespace {
36*c8dee2aaSAndroid Build Coastguard Worker
37*c8dee2aaSAndroid Build Coastguard Worker struct GradData {
38*c8dee2aaSAndroid Build Coastguard Worker int fCount;
39*c8dee2aaSAndroid Build Coastguard Worker const SkColor* fColors;
40*c8dee2aaSAndroid Build Coastguard Worker const SkColor4f* fColors4f;
41*c8dee2aaSAndroid Build Coastguard Worker const SkScalar* fPos;
42*c8dee2aaSAndroid Build Coastguard Worker };
43*c8dee2aaSAndroid Build Coastguard Worker
44*c8dee2aaSAndroid Build Coastguard Worker constexpr SkColor gColors[] = {
45*c8dee2aaSAndroid Build Coastguard Worker SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
46*c8dee2aaSAndroid Build Coastguard Worker };
47*c8dee2aaSAndroid Build Coastguard Worker constexpr SkColor4f gColors4f[] ={
48*c8dee2aaSAndroid Build Coastguard Worker { 1.0f, 0.0f, 0.0f, 1.0f }, // Red
49*c8dee2aaSAndroid Build Coastguard Worker { 0.0f, 1.0f, 0.0f, 1.0f }, // Green
50*c8dee2aaSAndroid Build Coastguard Worker { 0.0f, 0.0f, 1.0f, 1.0f }, // Blue
51*c8dee2aaSAndroid Build Coastguard Worker { 1.0f, 1.0f, 1.0f, 1.0f }, // White
52*c8dee2aaSAndroid Build Coastguard Worker { 0.0f, 0.0f, 0.0f, 1.0f } // Black
53*c8dee2aaSAndroid Build Coastguard Worker };
54*c8dee2aaSAndroid Build Coastguard Worker constexpr SkScalar gPos0[] = { 0, SK_Scalar1 };
55*c8dee2aaSAndroid Build Coastguard Worker constexpr SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
56*c8dee2aaSAndroid Build Coastguard Worker constexpr SkScalar gPos2[] = {
57*c8dee2aaSAndroid Build Coastguard Worker 0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
58*c8dee2aaSAndroid Build Coastguard Worker };
59*c8dee2aaSAndroid Build Coastguard Worker
60*c8dee2aaSAndroid Build Coastguard Worker constexpr SkScalar gPosClamp[] = {0.0f, 0.0f, 1.0f, 1.0f};
61*c8dee2aaSAndroid Build Coastguard Worker constexpr SkColor gColorClamp[] = {
62*c8dee2aaSAndroid Build Coastguard Worker SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLUE
63*c8dee2aaSAndroid Build Coastguard Worker };
64*c8dee2aaSAndroid Build Coastguard Worker constexpr SkColor4f gColor4fClamp[] ={
65*c8dee2aaSAndroid Build Coastguard Worker { 1.0f, 0.0f, 0.0f, 1.0f }, // Red
66*c8dee2aaSAndroid Build Coastguard Worker { 0.0f, 1.0f, 0.0f, 1.0f }, // Green
67*c8dee2aaSAndroid Build Coastguard Worker { 0.0f, 1.0f, 0.0f, 1.0f }, // Green
68*c8dee2aaSAndroid Build Coastguard Worker { 0.0f, 0.0f, 1.0f, 1.0f } // Blue
69*c8dee2aaSAndroid Build Coastguard Worker };
70*c8dee2aaSAndroid Build Coastguard Worker constexpr GradData gGradData[] = {
71*c8dee2aaSAndroid Build Coastguard Worker { 2, gColors, gColors4f, nullptr },
72*c8dee2aaSAndroid Build Coastguard Worker { 2, gColors, gColors4f, gPos0 },
73*c8dee2aaSAndroid Build Coastguard Worker { 2, gColors, gColors4f, gPos1 },
74*c8dee2aaSAndroid Build Coastguard Worker { 5, gColors, gColors4f, nullptr },
75*c8dee2aaSAndroid Build Coastguard Worker { 5, gColors, gColors4f, gPos2 },
76*c8dee2aaSAndroid Build Coastguard Worker { 4, gColorClamp, gColor4fClamp, gPosClamp }
77*c8dee2aaSAndroid Build Coastguard Worker };
78*c8dee2aaSAndroid Build Coastguard Worker
MakeLinear(const SkPoint pts[2],const GradData & data,SkTileMode tm,const SkMatrix & localMatrix)79*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> MakeLinear(const SkPoint pts[2], const GradData& data,
80*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tm, const SkMatrix& localMatrix) {
81*c8dee2aaSAndroid Build Coastguard Worker return SkGradientShader::MakeLinear(pts, data.fColors, data.fPos, data.fCount, tm, 0,
82*c8dee2aaSAndroid Build Coastguard Worker &localMatrix);
83*c8dee2aaSAndroid Build Coastguard Worker }
84*c8dee2aaSAndroid Build Coastguard Worker
MakeLinear4f(const SkPoint pts[2],const GradData & data,SkTileMode tm,const SkMatrix & localMatrix)85*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> MakeLinear4f(const SkPoint pts[2], const GradData& data,
86*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tm, const SkMatrix& localMatrix) {
87*c8dee2aaSAndroid Build Coastguard Worker auto srgb = SkColorSpace::MakeSRGB();
88*c8dee2aaSAndroid Build Coastguard Worker return SkGradientShader::MakeLinear(pts, data.fColors4f, srgb, data.fPos, data.fCount, tm, 0,
89*c8dee2aaSAndroid Build Coastguard Worker &localMatrix);
90*c8dee2aaSAndroid Build Coastguard Worker }
91*c8dee2aaSAndroid Build Coastguard Worker
MakeRadial(const SkPoint pts[2],const GradData & data,SkTileMode tm,const SkMatrix & localMatrix)92*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> MakeRadial(const SkPoint pts[2], const GradData& data,
93*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tm, const SkMatrix& localMatrix) {
94*c8dee2aaSAndroid Build Coastguard Worker SkPoint center;
95*c8dee2aaSAndroid Build Coastguard Worker center.set(SkScalarAve(pts[0].fX, pts[1].fX),
96*c8dee2aaSAndroid Build Coastguard Worker SkScalarAve(pts[0].fY, pts[1].fY));
97*c8dee2aaSAndroid Build Coastguard Worker return SkGradientShader::MakeRadial(center, center.fX, data.fColors, data.fPos, data.fCount,
98*c8dee2aaSAndroid Build Coastguard Worker tm, 0, &localMatrix);
99*c8dee2aaSAndroid Build Coastguard Worker }
100*c8dee2aaSAndroid Build Coastguard Worker
MakeRadial4f(const SkPoint pts[2],const GradData & data,SkTileMode tm,const SkMatrix & localMatrix)101*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> MakeRadial4f(const SkPoint pts[2], const GradData& data,
102*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tm, const SkMatrix& localMatrix) {
103*c8dee2aaSAndroid Build Coastguard Worker SkPoint center;
104*c8dee2aaSAndroid Build Coastguard Worker center.set(SkScalarAve(pts[0].fX, pts[1].fX),
105*c8dee2aaSAndroid Build Coastguard Worker SkScalarAve(pts[0].fY, pts[1].fY));
106*c8dee2aaSAndroid Build Coastguard Worker auto srgb = SkColorSpace::MakeSRGB();
107*c8dee2aaSAndroid Build Coastguard Worker return SkGradientShader::MakeRadial(center, center.fX, data.fColors4f, srgb, data.fPos,
108*c8dee2aaSAndroid Build Coastguard Worker data.fCount, tm, 0, &localMatrix);
109*c8dee2aaSAndroid Build Coastguard Worker }
110*c8dee2aaSAndroid Build Coastguard Worker
MakeSweep(const SkPoint pts[2],const GradData & data,SkTileMode,const SkMatrix & localMatrix)111*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> MakeSweep(const SkPoint pts[2], const GradData& data,
112*c8dee2aaSAndroid Build Coastguard Worker SkTileMode, const SkMatrix& localMatrix) {
113*c8dee2aaSAndroid Build Coastguard Worker SkPoint center;
114*c8dee2aaSAndroid Build Coastguard Worker center.set(SkScalarAve(pts[0].fX, pts[1].fX),
115*c8dee2aaSAndroid Build Coastguard Worker SkScalarAve(pts[0].fY, pts[1].fY));
116*c8dee2aaSAndroid Build Coastguard Worker return SkGradientShader::MakeSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount,
117*c8dee2aaSAndroid Build Coastguard Worker 0, &localMatrix);
118*c8dee2aaSAndroid Build Coastguard Worker }
119*c8dee2aaSAndroid Build Coastguard Worker
MakeSweep4f(const SkPoint pts[2],const GradData & data,SkTileMode,const SkMatrix & localMatrix)120*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> MakeSweep4f(const SkPoint pts[2], const GradData& data,
121*c8dee2aaSAndroid Build Coastguard Worker SkTileMode, const SkMatrix& localMatrix) {
122*c8dee2aaSAndroid Build Coastguard Worker SkPoint center;
123*c8dee2aaSAndroid Build Coastguard Worker center.set(SkScalarAve(pts[0].fX, pts[1].fX),
124*c8dee2aaSAndroid Build Coastguard Worker SkScalarAve(pts[0].fY, pts[1].fY));
125*c8dee2aaSAndroid Build Coastguard Worker auto srgb = SkColorSpace::MakeSRGB();
126*c8dee2aaSAndroid Build Coastguard Worker return SkGradientShader::MakeSweep(center.fX, center.fY, data.fColors4f, srgb, data.fPos,
127*c8dee2aaSAndroid Build Coastguard Worker data.fCount, 0, &localMatrix);
128*c8dee2aaSAndroid Build Coastguard Worker }
129*c8dee2aaSAndroid Build Coastguard Worker
Make2Radial(const SkPoint pts[2],const GradData & data,SkTileMode tm,const SkMatrix & localMatrix)130*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> Make2Radial(const SkPoint pts[2], const GradData& data,
131*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tm, const SkMatrix& localMatrix) {
132*c8dee2aaSAndroid Build Coastguard Worker SkPoint center0, center1;
133*c8dee2aaSAndroid Build Coastguard Worker center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
134*c8dee2aaSAndroid Build Coastguard Worker SkScalarAve(pts[0].fY, pts[1].fY));
135*c8dee2aaSAndroid Build Coastguard Worker center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
136*c8dee2aaSAndroid Build Coastguard Worker SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
137*c8dee2aaSAndroid Build Coastguard Worker return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7,
138*c8dee2aaSAndroid Build Coastguard Worker center0, (pts[1].fX - pts[0].fX) / 2,
139*c8dee2aaSAndroid Build Coastguard Worker data.fColors, data.fPos, data.fCount, tm,
140*c8dee2aaSAndroid Build Coastguard Worker 0, &localMatrix);
141*c8dee2aaSAndroid Build Coastguard Worker }
142*c8dee2aaSAndroid Build Coastguard Worker
Make2Radial4f(const SkPoint pts[2],const GradData & data,SkTileMode tm,const SkMatrix & localMatrix)143*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> Make2Radial4f(const SkPoint pts[2], const GradData& data,
144*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tm, const SkMatrix& localMatrix) {
145*c8dee2aaSAndroid Build Coastguard Worker SkPoint center0, center1;
146*c8dee2aaSAndroid Build Coastguard Worker center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
147*c8dee2aaSAndroid Build Coastguard Worker SkScalarAve(pts[0].fY, pts[1].fY));
148*c8dee2aaSAndroid Build Coastguard Worker center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3) / 5),
149*c8dee2aaSAndroid Build Coastguard Worker SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1) / 4));
150*c8dee2aaSAndroid Build Coastguard Worker auto srgb = SkColorSpace::MakeSRGB();
151*c8dee2aaSAndroid Build Coastguard Worker return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7,
152*c8dee2aaSAndroid Build Coastguard Worker center0, (pts[1].fX - pts[0].fX) / 2,
153*c8dee2aaSAndroid Build Coastguard Worker data.fColors4f, srgb, data.fPos, data.fCount, tm,
154*c8dee2aaSAndroid Build Coastguard Worker 0, &localMatrix);
155*c8dee2aaSAndroid Build Coastguard Worker }
156*c8dee2aaSAndroid Build Coastguard Worker
Make2Conical(const SkPoint pts[2],const GradData & data,SkTileMode tm,const SkMatrix & localMatrix)157*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> Make2Conical(const SkPoint pts[2], const GradData& data,
158*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tm, const SkMatrix& localMatrix) {
159*c8dee2aaSAndroid Build Coastguard Worker SkPoint center0, center1;
160*c8dee2aaSAndroid Build Coastguard Worker SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
161*c8dee2aaSAndroid Build Coastguard Worker SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
162*c8dee2aaSAndroid Build Coastguard Worker center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
163*c8dee2aaSAndroid Build Coastguard Worker center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
164*c8dee2aaSAndroid Build Coastguard Worker return SkGradientShader::MakeTwoPointConical(center1, radius1, center0, radius0,
165*c8dee2aaSAndroid Build Coastguard Worker data.fColors, data.fPos,
166*c8dee2aaSAndroid Build Coastguard Worker data.fCount, tm, 0, &localMatrix);
167*c8dee2aaSAndroid Build Coastguard Worker }
168*c8dee2aaSAndroid Build Coastguard Worker
Make2Conical4f(const SkPoint pts[2],const GradData & data,SkTileMode tm,const SkMatrix & localMatrix)169*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> Make2Conical4f(const SkPoint pts[2], const GradData& data,
170*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tm, const SkMatrix& localMatrix) {
171*c8dee2aaSAndroid Build Coastguard Worker SkPoint center0, center1;
172*c8dee2aaSAndroid Build Coastguard Worker SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
173*c8dee2aaSAndroid Build Coastguard Worker SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
174*c8dee2aaSAndroid Build Coastguard Worker center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
175*c8dee2aaSAndroid Build Coastguard Worker center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
176*c8dee2aaSAndroid Build Coastguard Worker auto srgb = SkColorSpace::MakeSRGB();
177*c8dee2aaSAndroid Build Coastguard Worker return SkGradientShader::MakeTwoPointConical(center1, radius1, center0, radius0,
178*c8dee2aaSAndroid Build Coastguard Worker data.fColors4f, srgb, data.fPos,
179*c8dee2aaSAndroid Build Coastguard Worker data.fCount, tm, 0, &localMatrix);
180*c8dee2aaSAndroid Build Coastguard Worker }
181*c8dee2aaSAndroid Build Coastguard Worker
182*c8dee2aaSAndroid Build Coastguard Worker typedef sk_sp<SkShader> (*GradMaker)(const SkPoint pts[2], const GradData& data,
183*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tm, const SkMatrix& localMatrix);
184*c8dee2aaSAndroid Build Coastguard Worker constexpr GradMaker gGradMakers[] = {
185*c8dee2aaSAndroid Build Coastguard Worker MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2Conical
186*c8dee2aaSAndroid Build Coastguard Worker };
187*c8dee2aaSAndroid Build Coastguard Worker constexpr GradMaker gGradMakers4f[] ={
188*c8dee2aaSAndroid Build Coastguard Worker MakeLinear4f, MakeRadial4f, MakeSweep4f, Make2Radial4f, Make2Conical4f
189*c8dee2aaSAndroid Build Coastguard Worker };
190*c8dee2aaSAndroid Build Coastguard Worker
191*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
192*c8dee2aaSAndroid Build Coastguard Worker
193*c8dee2aaSAndroid Build Coastguard Worker class GradientsGM : public skiagm::GM {
194*c8dee2aaSAndroid Build Coastguard Worker public:
GradientsGM(bool dither)195*c8dee2aaSAndroid Build Coastguard Worker GradientsGM(bool dither) : fDither(dither) {}
196*c8dee2aaSAndroid Build Coastguard Worker
197*c8dee2aaSAndroid Build Coastguard Worker protected:
198*c8dee2aaSAndroid Build Coastguard Worker const bool fDither;
199*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)200*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
201*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[2] = {
202*c8dee2aaSAndroid Build Coastguard Worker { 0, 0 },
203*c8dee2aaSAndroid Build Coastguard Worker { SkIntToScalar(100), SkIntToScalar(100) }
204*c8dee2aaSAndroid Build Coastguard Worker };
205*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tm = SkTileMode::kClamp;
206*c8dee2aaSAndroid Build Coastguard Worker SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
207*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
208*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
209*c8dee2aaSAndroid Build Coastguard Worker paint.setDither(fDither);
210*c8dee2aaSAndroid Build Coastguard Worker
211*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
212*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(gGradData); i++) {
213*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
214*c8dee2aaSAndroid Build Coastguard Worker for (size_t j = 0; j < std::size(gGradMakers); j++) {
215*c8dee2aaSAndroid Build Coastguard Worker SkMatrix scale = SkMatrix::I();
216*c8dee2aaSAndroid Build Coastguard Worker
217*c8dee2aaSAndroid Build Coastguard Worker if (i == 5) { // if the clamp case
218*c8dee2aaSAndroid Build Coastguard Worker scale.setScale(0.5f, 0.5f);
219*c8dee2aaSAndroid Build Coastguard Worker scale.postTranslate(25.f, 25.f);
220*c8dee2aaSAndroid Build Coastguard Worker }
221*c8dee2aaSAndroid Build Coastguard Worker
222*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(gGradMakers[j](pts, gGradData[i], tm, scale));
223*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(r, paint);
224*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, SkIntToScalar(120));
225*c8dee2aaSAndroid Build Coastguard Worker }
226*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
227*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(SkIntToScalar(120), 0);
228*c8dee2aaSAndroid Build Coastguard Worker }
229*c8dee2aaSAndroid Build Coastguard Worker }
230*c8dee2aaSAndroid Build Coastguard Worker
231*c8dee2aaSAndroid Build Coastguard Worker private:
onOnceBeforeDraw()232*c8dee2aaSAndroid Build Coastguard Worker void onOnceBeforeDraw() override { this->setBGColor(0xFFDDDDDD); }
233*c8dee2aaSAndroid Build Coastguard Worker
getName() const234*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override {
235*c8dee2aaSAndroid Build Coastguard Worker return SkString(fDither ? "gradients" : "gradients_nodither");
236*c8dee2aaSAndroid Build Coastguard Worker }
237*c8dee2aaSAndroid Build Coastguard Worker
getISize()238*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return {840, 815}; }
239*c8dee2aaSAndroid Build Coastguard Worker };
240*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new GradientsGM(true); )
241*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new GradientsGM(false); )
242*c8dee2aaSAndroid Build Coastguard Worker
243*c8dee2aaSAndroid Build Coastguard Worker // Like the original gradients GM, but using the SkColor4f shader factories. Should be identical.
244*c8dee2aaSAndroid Build Coastguard Worker class Gradients4fGM : public skiagm::GM {
245*c8dee2aaSAndroid Build Coastguard Worker public:
Gradients4fGM(bool dither)246*c8dee2aaSAndroid Build Coastguard Worker Gradients4fGM(bool dither) : fDither(dither) {}
247*c8dee2aaSAndroid Build Coastguard Worker
248*c8dee2aaSAndroid Build Coastguard Worker private:
onOnceBeforeDraw()249*c8dee2aaSAndroid Build Coastguard Worker void onOnceBeforeDraw() override { this->setBGColor(0xFFDDDDDD); }
250*c8dee2aaSAndroid Build Coastguard Worker
getName() const251*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override {
252*c8dee2aaSAndroid Build Coastguard Worker return SkString(fDither ? "gradients4f" : "gradients4f_nodither");
253*c8dee2aaSAndroid Build Coastguard Worker }
254*c8dee2aaSAndroid Build Coastguard Worker
getISize()255*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return {840, 815}; }
256*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)257*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
258*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[2] ={
259*c8dee2aaSAndroid Build Coastguard Worker { 0, 0 },
260*c8dee2aaSAndroid Build Coastguard Worker { SkIntToScalar(100), SkIntToScalar(100) }
261*c8dee2aaSAndroid Build Coastguard Worker };
262*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tm = SkTileMode::kClamp;
263*c8dee2aaSAndroid Build Coastguard Worker SkRect r ={ 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
264*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
265*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
266*c8dee2aaSAndroid Build Coastguard Worker paint.setDither(fDither);
267*c8dee2aaSAndroid Build Coastguard Worker
268*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
269*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(gGradData); i++) {
270*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
271*c8dee2aaSAndroid Build Coastguard Worker for (size_t j = 0; j < std::size(gGradMakers4f); j++) {
272*c8dee2aaSAndroid Build Coastguard Worker SkMatrix scale = SkMatrix::I();
273*c8dee2aaSAndroid Build Coastguard Worker
274*c8dee2aaSAndroid Build Coastguard Worker if (i == 5) { // if the clamp case
275*c8dee2aaSAndroid Build Coastguard Worker scale.setScale(0.5f, 0.5f);
276*c8dee2aaSAndroid Build Coastguard Worker scale.postTranslate(25.f, 25.f);
277*c8dee2aaSAndroid Build Coastguard Worker }
278*c8dee2aaSAndroid Build Coastguard Worker
279*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(gGradMakers4f[j](pts, gGradData[i], tm, scale));
280*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(r, paint);
281*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, SkIntToScalar(120));
282*c8dee2aaSAndroid Build Coastguard Worker }
283*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
284*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(SkIntToScalar(120), 0);
285*c8dee2aaSAndroid Build Coastguard Worker }
286*c8dee2aaSAndroid Build Coastguard Worker }
287*c8dee2aaSAndroid Build Coastguard Worker
288*c8dee2aaSAndroid Build Coastguard Worker bool fDither;
289*c8dee2aaSAndroid Build Coastguard Worker };
290*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new Gradients4fGM(true); )
291*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new Gradients4fGM(false); )
292*c8dee2aaSAndroid Build Coastguard Worker
293*c8dee2aaSAndroid Build Coastguard Worker // Based on the original gradient slide, but with perspective applied to the
294*c8dee2aaSAndroid Build Coastguard Worker // gradient shaders' local matrices
295*c8dee2aaSAndroid Build Coastguard Worker class GradientsLocalPerspectiveGM : public skiagm::GM {
296*c8dee2aaSAndroid Build Coastguard Worker public:
GradientsLocalPerspectiveGM(bool dither)297*c8dee2aaSAndroid Build Coastguard Worker GradientsLocalPerspectiveGM(bool dither) : fDither(dither) {
298*c8dee2aaSAndroid Build Coastguard Worker this->setBGColor(0xFFDDDDDD);
299*c8dee2aaSAndroid Build Coastguard Worker }
300*c8dee2aaSAndroid Build Coastguard Worker
301*c8dee2aaSAndroid Build Coastguard Worker private:
getName() const302*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override {
303*c8dee2aaSAndroid Build Coastguard Worker return SkString(fDither ? "gradients_local_perspective" :
304*c8dee2aaSAndroid Build Coastguard Worker "gradients_local_perspective_nodither");
305*c8dee2aaSAndroid Build Coastguard Worker }
306*c8dee2aaSAndroid Build Coastguard Worker
getISize()307*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return {840, 815}; }
308*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)309*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
310*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[2] = {
311*c8dee2aaSAndroid Build Coastguard Worker { 0, 0 },
312*c8dee2aaSAndroid Build Coastguard Worker { SkIntToScalar(100), SkIntToScalar(100) }
313*c8dee2aaSAndroid Build Coastguard Worker };
314*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tm = SkTileMode::kClamp;
315*c8dee2aaSAndroid Build Coastguard Worker SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
316*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
317*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
318*c8dee2aaSAndroid Build Coastguard Worker paint.setDither(fDither);
319*c8dee2aaSAndroid Build Coastguard Worker
320*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
321*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(gGradData); i++) {
322*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
323*c8dee2aaSAndroid Build Coastguard Worker for (size_t j = 0; j < std::size(gGradMakers); j++) {
324*c8dee2aaSAndroid Build Coastguard Worker // apply an increasing y perspective as we move to the right
325*c8dee2aaSAndroid Build Coastguard Worker SkMatrix perspective;
326*c8dee2aaSAndroid Build Coastguard Worker perspective.setIdentity();
327*c8dee2aaSAndroid Build Coastguard Worker perspective.setPerspY(SkIntToScalar(i+1) / 500);
328*c8dee2aaSAndroid Build Coastguard Worker perspective.setSkewX(SkIntToScalar(i+1) / 10);
329*c8dee2aaSAndroid Build Coastguard Worker
330*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(gGradMakers[j](pts, gGradData[i], tm, perspective));
331*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(r, paint);
332*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, SkIntToScalar(120));
333*c8dee2aaSAndroid Build Coastguard Worker }
334*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
335*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(SkIntToScalar(120), 0);
336*c8dee2aaSAndroid Build Coastguard Worker }
337*c8dee2aaSAndroid Build Coastguard Worker }
338*c8dee2aaSAndroid Build Coastguard Worker
339*c8dee2aaSAndroid Build Coastguard Worker bool fDither;
340*c8dee2aaSAndroid Build Coastguard Worker };
341*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new GradientsLocalPerspectiveGM(true); )
342*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new GradientsLocalPerspectiveGM(false); )
343*c8dee2aaSAndroid Build Coastguard Worker
344*c8dee2aaSAndroid Build Coastguard Worker // Based on the original gradient slide, but with perspective applied to
345*c8dee2aaSAndroid Build Coastguard Worker // the view matrix
346*c8dee2aaSAndroid Build Coastguard Worker class GradientsViewPerspectiveGM : public GradientsGM {
347*c8dee2aaSAndroid Build Coastguard Worker public:
GradientsViewPerspectiveGM(bool dither)348*c8dee2aaSAndroid Build Coastguard Worker GradientsViewPerspectiveGM(bool dither) : INHERITED(dither) { }
349*c8dee2aaSAndroid Build Coastguard Worker
350*c8dee2aaSAndroid Build Coastguard Worker private:
getName() const351*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override {
352*c8dee2aaSAndroid Build Coastguard Worker return SkString(fDither ? "gradients_view_perspective" :
353*c8dee2aaSAndroid Build Coastguard Worker "gradients_view_perspective_nodither");
354*c8dee2aaSAndroid Build Coastguard Worker }
355*c8dee2aaSAndroid Build Coastguard Worker
getISize()356*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return {840, 500}; }
357*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)358*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
359*c8dee2aaSAndroid Build Coastguard Worker SkMatrix perspective;
360*c8dee2aaSAndroid Build Coastguard Worker perspective.setIdentity();
361*c8dee2aaSAndroid Build Coastguard Worker perspective.setPerspY(0.001f);
362*c8dee2aaSAndroid Build Coastguard Worker perspective.setSkewX(SkIntToScalar(8) / 25);
363*c8dee2aaSAndroid Build Coastguard Worker canvas->concat(perspective);
364*c8dee2aaSAndroid Build Coastguard Worker this->INHERITED::onDraw(canvas);
365*c8dee2aaSAndroid Build Coastguard Worker }
366*c8dee2aaSAndroid Build Coastguard Worker
367*c8dee2aaSAndroid Build Coastguard Worker private:
368*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = GradientsGM;
369*c8dee2aaSAndroid Build Coastguard Worker };
370*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new GradientsViewPerspectiveGM(true); )
371*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new GradientsViewPerspectiveGM(false); )
372*c8dee2aaSAndroid Build Coastguard Worker
373*c8dee2aaSAndroid Build Coastguard Worker /*
374*c8dee2aaSAndroid Build Coastguard Worker Inspired by this <canvas> javascript, where we need to detect that we are not
375*c8dee2aaSAndroid Build Coastguard Worker solving a quadratic equation, but must instead solve a linear (since our X^2
376*c8dee2aaSAndroid Build Coastguard Worker coefficient is 0)
377*c8dee2aaSAndroid Build Coastguard Worker
378*c8dee2aaSAndroid Build Coastguard Worker ctx.fillStyle = '#f00';
379*c8dee2aaSAndroid Build Coastguard Worker ctx.fillRect(0, 0, 100, 50);
380*c8dee2aaSAndroid Build Coastguard Worker
381*c8dee2aaSAndroid Build Coastguard Worker var g = ctx.createRadialGradient(-80, 25, 70, 0, 25, 150);
382*c8dee2aaSAndroid Build Coastguard Worker g.addColorStop(0, '#f00');
383*c8dee2aaSAndroid Build Coastguard Worker g.addColorStop(0.01, '#0f0');
384*c8dee2aaSAndroid Build Coastguard Worker g.addColorStop(0.99, '#0f0');
385*c8dee2aaSAndroid Build Coastguard Worker g.addColorStop(1, '#f00');
386*c8dee2aaSAndroid Build Coastguard Worker ctx.fillStyle = g;
387*c8dee2aaSAndroid Build Coastguard Worker ctx.fillRect(0, 0, 100, 50);
388*c8dee2aaSAndroid Build Coastguard Worker */
389*c8dee2aaSAndroid Build Coastguard Worker class GradientsDegenrate2PointGM : public skiagm::GM {
390*c8dee2aaSAndroid Build Coastguard Worker public:
GradientsDegenrate2PointGM(bool dither)391*c8dee2aaSAndroid Build Coastguard Worker GradientsDegenrate2PointGM(bool dither) : fDither(dither) {}
392*c8dee2aaSAndroid Build Coastguard Worker
393*c8dee2aaSAndroid Build Coastguard Worker private:
getName() const394*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override {
395*c8dee2aaSAndroid Build Coastguard Worker return SkString(fDither ? "gradients_degenerate_2pt" : "gradients_degenerate_2pt_nodither");
396*c8dee2aaSAndroid Build Coastguard Worker }
397*c8dee2aaSAndroid Build Coastguard Worker
getISize()398*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return {320, 320}; }
399*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)400*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
401*c8dee2aaSAndroid Build Coastguard Worker canvas->drawColor(SK_ColorBLUE);
402*c8dee2aaSAndroid Build Coastguard Worker
403*c8dee2aaSAndroid Build Coastguard Worker SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorRED };
404*c8dee2aaSAndroid Build Coastguard Worker SkScalar pos[] = { 0, 0.01f, 0.99f, SK_Scalar1 };
405*c8dee2aaSAndroid Build Coastguard Worker SkPoint c0;
406*c8dee2aaSAndroid Build Coastguard Worker c0.iset(-80, 25);
407*c8dee2aaSAndroid Build Coastguard Worker SkScalar r0 = SkIntToScalar(70);
408*c8dee2aaSAndroid Build Coastguard Worker SkPoint c1;
409*c8dee2aaSAndroid Build Coastguard Worker c1.iset(0, 25);
410*c8dee2aaSAndroid Build Coastguard Worker SkScalar r1 = SkIntToScalar(150);
411*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
412*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(SkGradientShader::MakeTwoPointConical(c0, r0, c1, r1, colors,
413*c8dee2aaSAndroid Build Coastguard Worker pos, std::size(pos),
414*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp));
415*c8dee2aaSAndroid Build Coastguard Worker paint.setDither(fDither);
416*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPaint(paint);
417*c8dee2aaSAndroid Build Coastguard Worker }
418*c8dee2aaSAndroid Build Coastguard Worker
419*c8dee2aaSAndroid Build Coastguard Worker bool fDither;
420*c8dee2aaSAndroid Build Coastguard Worker };
421*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new GradientsDegenrate2PointGM(true); )
DEF_GM(return new GradientsDegenrate2PointGM (false);)422*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new GradientsDegenrate2PointGM(false); )
423*c8dee2aaSAndroid Build Coastguard Worker
424*c8dee2aaSAndroid Build Coastguard Worker /* bug.skia.org/517
425*c8dee2aaSAndroid Build Coastguard Worker <canvas id="canvas"></canvas>
426*c8dee2aaSAndroid Build Coastguard Worker <script>
427*c8dee2aaSAndroid Build Coastguard Worker var c = document.getElementById("canvas");
428*c8dee2aaSAndroid Build Coastguard Worker var ctx = c.getContext("2d");
429*c8dee2aaSAndroid Build Coastguard Worker ctx.fillStyle = '#ff0';
430*c8dee2aaSAndroid Build Coastguard Worker ctx.fillRect(0, 0, 100, 50);
431*c8dee2aaSAndroid Build Coastguard Worker
432*c8dee2aaSAndroid Build Coastguard Worker var g = ctx.createRadialGradient(200, 25, 20, 200, 25, 10);
433*c8dee2aaSAndroid Build Coastguard Worker g.addColorStop(0, '#0f0');
434*c8dee2aaSAndroid Build Coastguard Worker g.addColorStop(0.003, '#f00'); // 0.004 makes this work
435*c8dee2aaSAndroid Build Coastguard Worker g.addColorStop(1, '#ff0');
436*c8dee2aaSAndroid Build Coastguard Worker ctx.fillStyle = g;
437*c8dee2aaSAndroid Build Coastguard Worker ctx.fillRect(0, 0, 100, 50);
438*c8dee2aaSAndroid Build Coastguard Worker </script>
439*c8dee2aaSAndroid Build Coastguard Worker */
440*c8dee2aaSAndroid Build Coastguard Worker
441*c8dee2aaSAndroid Build Coastguard Worker // should draw only green
442*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(small_color_stop, canvas, 100, 150) {
443*c8dee2aaSAndroid Build Coastguard Worker SkColor colors[] = { SK_ColorGREEN, SK_ColorRED, SK_ColorYELLOW };
444*c8dee2aaSAndroid Build Coastguard Worker SkScalar pos[] = { 0, 0.003f, SK_Scalar1 }; // 0.004f makes this work
445*c8dee2aaSAndroid Build Coastguard Worker SkPoint c0 = { 200, 25 };
446*c8dee2aaSAndroid Build Coastguard Worker SkScalar r0 = 20;
447*c8dee2aaSAndroid Build Coastguard Worker SkPoint c1 = { 200, 25 };
448*c8dee2aaSAndroid Build Coastguard Worker SkScalar r1 = 10;
449*c8dee2aaSAndroid Build Coastguard Worker
450*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
451*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(SK_ColorYELLOW);
452*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(SkRect::MakeWH(100, 150), paint);
453*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(SkGradientShader::MakeTwoPointConical(c0, r0, c1, r1, colors, pos,
454*c8dee2aaSAndroid Build Coastguard Worker std::size(pos),
455*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp));
456*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(SkRect::MakeWH(100, 150), paint);
457*c8dee2aaSAndroid Build Coastguard Worker }
458*c8dee2aaSAndroid Build Coastguard Worker
459*c8dee2aaSAndroid Build Coastguard Worker
460*c8dee2aaSAndroid Build Coastguard Worker /// Tests correctness of *optimized* codepaths in gradients.
461*c8dee2aaSAndroid Build Coastguard Worker
462*c8dee2aaSAndroid Build Coastguard Worker class ClampedGradientsGM : public skiagm::GM {
463*c8dee2aaSAndroid Build Coastguard Worker public:
ClampedGradientsGM(bool dither)464*c8dee2aaSAndroid Build Coastguard Worker ClampedGradientsGM(bool dither) : fDither(dither) {}
465*c8dee2aaSAndroid Build Coastguard Worker
466*c8dee2aaSAndroid Build Coastguard Worker private:
getName() const467*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override {
468*c8dee2aaSAndroid Build Coastguard Worker return SkString(fDither ? "clamped_gradients" : "clamped_gradients_nodither");
469*c8dee2aaSAndroid Build Coastguard Worker }
470*c8dee2aaSAndroid Build Coastguard Worker
getISize()471*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return {640, 510}; }
472*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)473*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
474*c8dee2aaSAndroid Build Coastguard Worker canvas->drawColor(0xFFDDDDDD);
475*c8dee2aaSAndroid Build Coastguard Worker
476*c8dee2aaSAndroid Build Coastguard Worker SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(300) };
477*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
478*c8dee2aaSAndroid Build Coastguard Worker paint.setDither(fDither);
479*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
480*c8dee2aaSAndroid Build Coastguard Worker
481*c8dee2aaSAndroid Build Coastguard Worker SkPoint center;
482*c8dee2aaSAndroid Build Coastguard Worker center.iset(0, 300);
483*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
484*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(SkGradientShader::MakeRadial(
485*c8dee2aaSAndroid Build Coastguard Worker SkPoint(center),
486*c8dee2aaSAndroid Build Coastguard Worker SkIntToScalar(200), gColors, nullptr, 5,
487*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp));
488*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(r, paint);
489*c8dee2aaSAndroid Build Coastguard Worker }
490*c8dee2aaSAndroid Build Coastguard Worker
491*c8dee2aaSAndroid Build Coastguard Worker bool fDither;
492*c8dee2aaSAndroid Build Coastguard Worker };
493*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new ClampedGradientsGM(true); )
494*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new ClampedGradientsGM(false); )
495*c8dee2aaSAndroid Build Coastguard Worker
496*c8dee2aaSAndroid Build Coastguard Worker /// Checks quality of large radial gradients, which may display
497*c8dee2aaSAndroid Build Coastguard Worker /// some banding.
498*c8dee2aaSAndroid Build Coastguard Worker
499*c8dee2aaSAndroid Build Coastguard Worker class RadialGradientGM : public skiagm::GM {
getName() const500*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override { return SkString("radial_gradient"); }
501*c8dee2aaSAndroid Build Coastguard Worker
getISize()502*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return {1280, 1280}; }
503*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)504*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
505*c8dee2aaSAndroid Build Coastguard Worker const SkISize dim = this->getISize();
506*c8dee2aaSAndroid Build Coastguard Worker
507*c8dee2aaSAndroid Build Coastguard Worker canvas->drawColor(0xFF000000);
508*c8dee2aaSAndroid Build Coastguard Worker
509*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
510*c8dee2aaSAndroid Build Coastguard Worker paint.setDither(true);
511*c8dee2aaSAndroid Build Coastguard Worker SkPoint center;
512*c8dee2aaSAndroid Build Coastguard Worker center.set(SkIntToScalar(dim.width())/2, SkIntToScalar(dim.height())/2);
513*c8dee2aaSAndroid Build Coastguard Worker SkScalar radius = SkIntToScalar(dim.width())/2;
514*c8dee2aaSAndroid Build Coastguard Worker const SkColor colors[] = { 0x7f7f7f7f, 0x7f7f7f7f, 0xb2000000 };
515*c8dee2aaSAndroid Build Coastguard Worker const SkScalar pos[] = { 0.0f,
516*c8dee2aaSAndroid Build Coastguard Worker 0.35f,
517*c8dee2aaSAndroid Build Coastguard Worker 1.0f };
518*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(SkGradientShader::MakeRadial(center, radius, colors, pos,
519*c8dee2aaSAndroid Build Coastguard Worker std::size(pos),
520*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp));
521*c8dee2aaSAndroid Build Coastguard Worker SkRect r = {
522*c8dee2aaSAndroid Build Coastguard Worker 0, 0, SkIntToScalar(dim.width()), SkIntToScalar(dim.height())
523*c8dee2aaSAndroid Build Coastguard Worker };
524*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(r, paint);
525*c8dee2aaSAndroid Build Coastguard Worker }
526*c8dee2aaSAndroid Build Coastguard Worker };
527*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new RadialGradientGM; )
528*c8dee2aaSAndroid Build Coastguard Worker
529*c8dee2aaSAndroid Build Coastguard Worker class RadialGradient2GM : public skiagm::GM {
530*c8dee2aaSAndroid Build Coastguard Worker public:
RadialGradient2GM(bool dither)531*c8dee2aaSAndroid Build Coastguard Worker RadialGradient2GM(bool dither) : fDither(dither) {}
532*c8dee2aaSAndroid Build Coastguard Worker
533*c8dee2aaSAndroid Build Coastguard Worker private:
getName() const534*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override {
535*c8dee2aaSAndroid Build Coastguard Worker return SkString(fDither ? "radial_gradient2" : "radial_gradient2_nodither");
536*c8dee2aaSAndroid Build Coastguard Worker }
537*c8dee2aaSAndroid Build Coastguard Worker
getISize()538*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return {800, 400}; }
539*c8dee2aaSAndroid Build Coastguard Worker
540*c8dee2aaSAndroid Build Coastguard Worker // Reproduces the example given in bug 7671058.
onDraw(SkCanvas * canvas)541*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
542*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint1, paint2, paint3;
543*c8dee2aaSAndroid Build Coastguard Worker paint1.setStyle(SkPaint::kFill_Style);
544*c8dee2aaSAndroid Build Coastguard Worker paint2.setStyle(SkPaint::kFill_Style);
545*c8dee2aaSAndroid Build Coastguard Worker paint3.setStyle(SkPaint::kFill_Style);
546*c8dee2aaSAndroid Build Coastguard Worker
547*c8dee2aaSAndroid Build Coastguard Worker const SkColor sweep_colors[] =
548*c8dee2aaSAndroid Build Coastguard Worker { 0xFFFF0000, 0xFFFFFF00, 0xFF00FF00, 0xFF00FFFF, 0xFF0000FF, 0xFFFF00FF, 0xFFFF0000 };
549*c8dee2aaSAndroid Build Coastguard Worker const SkColor colors1[] = { 0xFFFFFFFF, 0x00000000 };
550*c8dee2aaSAndroid Build Coastguard Worker const SkColor colors2[] = { 0xFF000000, 0x00000000 };
551*c8dee2aaSAndroid Build Coastguard Worker
552*c8dee2aaSAndroid Build Coastguard Worker const SkScalar cx = 200, cy = 200, radius = 150;
553*c8dee2aaSAndroid Build Coastguard Worker SkPoint center;
554*c8dee2aaSAndroid Build Coastguard Worker center.set(cx, cy);
555*c8dee2aaSAndroid Build Coastguard Worker
556*c8dee2aaSAndroid Build Coastguard Worker // We can either interpolate endpoints and premultiply each point (default, more precision),
557*c8dee2aaSAndroid Build Coastguard Worker // or premultiply the endpoints first, avoiding the need to premultiply each point (cheap).
558*c8dee2aaSAndroid Build Coastguard Worker const uint32_t flags[] = { 0, SkGradientShader::kInterpolateColorsInPremul_Flag };
559*c8dee2aaSAndroid Build Coastguard Worker
560*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(flags); i++) {
561*c8dee2aaSAndroid Build Coastguard Worker paint1.setShader(SkGradientShader::MakeSweep(cx, cy, sweep_colors,
562*c8dee2aaSAndroid Build Coastguard Worker nullptr, std::size(sweep_colors),
563*c8dee2aaSAndroid Build Coastguard Worker flags[i], nullptr));
564*c8dee2aaSAndroid Build Coastguard Worker paint2.setShader(SkGradientShader::MakeRadial(center, radius, colors1,
565*c8dee2aaSAndroid Build Coastguard Worker nullptr, std::size(colors1),
566*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp,
567*c8dee2aaSAndroid Build Coastguard Worker flags[i], nullptr));
568*c8dee2aaSAndroid Build Coastguard Worker paint3.setShader(SkGradientShader::MakeRadial(center, radius, colors2,
569*c8dee2aaSAndroid Build Coastguard Worker nullptr, std::size(colors2),
570*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp,
571*c8dee2aaSAndroid Build Coastguard Worker flags[i], nullptr));
572*c8dee2aaSAndroid Build Coastguard Worker paint1.setDither(fDither);
573*c8dee2aaSAndroid Build Coastguard Worker paint2.setDither(fDither);
574*c8dee2aaSAndroid Build Coastguard Worker paint3.setDither(fDither);
575*c8dee2aaSAndroid Build Coastguard Worker
576*c8dee2aaSAndroid Build Coastguard Worker canvas->drawCircle(cx, cy, radius, paint1);
577*c8dee2aaSAndroid Build Coastguard Worker canvas->drawCircle(cx, cy, radius, paint3);
578*c8dee2aaSAndroid Build Coastguard Worker canvas->drawCircle(cx, cy, radius, paint2);
579*c8dee2aaSAndroid Build Coastguard Worker
580*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(400, 0);
581*c8dee2aaSAndroid Build Coastguard Worker }
582*c8dee2aaSAndroid Build Coastguard Worker }
583*c8dee2aaSAndroid Build Coastguard Worker
584*c8dee2aaSAndroid Build Coastguard Worker private:
585*c8dee2aaSAndroid Build Coastguard Worker bool fDither;
586*c8dee2aaSAndroid Build Coastguard Worker
587*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = GM;
588*c8dee2aaSAndroid Build Coastguard Worker };
589*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new RadialGradient2GM(true); )
590*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new RadialGradient2GM(false); )
591*c8dee2aaSAndroid Build Coastguard Worker
592*c8dee2aaSAndroid Build Coastguard Worker // Shallow radial (shows banding on raster)
593*c8dee2aaSAndroid Build Coastguard Worker class RadialGradient3GM : public skiagm::GM {
594*c8dee2aaSAndroid Build Coastguard Worker public:
RadialGradient3GM(bool dither)595*c8dee2aaSAndroid Build Coastguard Worker RadialGradient3GM(bool dither) : fDither(dither) { }
596*c8dee2aaSAndroid Build Coastguard Worker
597*c8dee2aaSAndroid Build Coastguard Worker private:
getName() const598*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override {
599*c8dee2aaSAndroid Build Coastguard Worker return SkString(fDither ? "radial_gradient3" : "radial_gradient3_nodither");
600*c8dee2aaSAndroid Build Coastguard Worker }
601*c8dee2aaSAndroid Build Coastguard Worker
getISize()602*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return {500, 500}; }
603*c8dee2aaSAndroid Build Coastguard Worker
runAsBench() const604*c8dee2aaSAndroid Build Coastguard Worker bool runAsBench() const override { return true; }
605*c8dee2aaSAndroid Build Coastguard Worker
onOnceBeforeDraw()606*c8dee2aaSAndroid Build Coastguard Worker void onOnceBeforeDraw() override {
607*c8dee2aaSAndroid Build Coastguard Worker const SkPoint center = { 0, 0 };
608*c8dee2aaSAndroid Build Coastguard Worker const SkScalar kRadius = 3000;
609*c8dee2aaSAndroid Build Coastguard Worker const SkColor kColors[] = { 0xFFFFFFFF, 0xFF000000 };
610*c8dee2aaSAndroid Build Coastguard Worker fShader = SkGradientShader::MakeRadial(center, kRadius, kColors, nullptr, 2,
611*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp);
612*c8dee2aaSAndroid Build Coastguard Worker }
613*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)614*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
615*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
616*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(fShader);
617*c8dee2aaSAndroid Build Coastguard Worker paint.setDither(fDither);
618*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(SkRect::MakeWH(500, 500), paint);
619*c8dee2aaSAndroid Build Coastguard Worker }
620*c8dee2aaSAndroid Build Coastguard Worker
621*c8dee2aaSAndroid Build Coastguard Worker private:
622*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> fShader;
623*c8dee2aaSAndroid Build Coastguard Worker bool fDither;
624*c8dee2aaSAndroid Build Coastguard Worker
625*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = GM;
626*c8dee2aaSAndroid Build Coastguard Worker };
627*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new RadialGradient3GM(true); )
628*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new RadialGradient3GM(false); )
629*c8dee2aaSAndroid Build Coastguard Worker
630*c8dee2aaSAndroid Build Coastguard Worker class RadialGradient4GM : public skiagm::GM {
631*c8dee2aaSAndroid Build Coastguard Worker public:
RadialGradient4GM(bool dither)632*c8dee2aaSAndroid Build Coastguard Worker RadialGradient4GM(bool dither) : fDither(dither) { }
633*c8dee2aaSAndroid Build Coastguard Worker
634*c8dee2aaSAndroid Build Coastguard Worker private:
getName() const635*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override {
636*c8dee2aaSAndroid Build Coastguard Worker return SkString(fDither ? "radial_gradient4" : "radial_gradient4_nodither");
637*c8dee2aaSAndroid Build Coastguard Worker }
638*c8dee2aaSAndroid Build Coastguard Worker
getISize()639*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return {500, 500}; }
640*c8dee2aaSAndroid Build Coastguard Worker
onOnceBeforeDraw()641*c8dee2aaSAndroid Build Coastguard Worker void onOnceBeforeDraw() override {
642*c8dee2aaSAndroid Build Coastguard Worker const SkPoint center = { 250, 250 };
643*c8dee2aaSAndroid Build Coastguard Worker const SkScalar kRadius = 250;
644*c8dee2aaSAndroid Build Coastguard Worker const SkColor colors[] = { SK_ColorRED, SK_ColorRED, SK_ColorWHITE, SK_ColorWHITE,
645*c8dee2aaSAndroid Build Coastguard Worker SK_ColorRED };
646*c8dee2aaSAndroid Build Coastguard Worker const SkScalar pos[] = { 0, .4f, .4f, .8f, .8f, 1 };
647*c8dee2aaSAndroid Build Coastguard Worker fShader = SkGradientShader::MakeRadial(center, kRadius, colors, pos,
648*c8dee2aaSAndroid Build Coastguard Worker std::size(gColors), SkTileMode::kClamp);
649*c8dee2aaSAndroid Build Coastguard Worker }
650*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)651*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
652*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
653*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
654*c8dee2aaSAndroid Build Coastguard Worker paint.setDither(fDither);
655*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(fShader);
656*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(SkRect::MakeWH(500, 500), paint);
657*c8dee2aaSAndroid Build Coastguard Worker }
658*c8dee2aaSAndroid Build Coastguard Worker
659*c8dee2aaSAndroid Build Coastguard Worker private:
660*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> fShader;
661*c8dee2aaSAndroid Build Coastguard Worker bool fDither;
662*c8dee2aaSAndroid Build Coastguard Worker
663*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = GM;
664*c8dee2aaSAndroid Build Coastguard Worker };
665*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new RadialGradient4GM(true); )
666*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new RadialGradient4GM(false); )
667*c8dee2aaSAndroid Build Coastguard Worker
668*c8dee2aaSAndroid Build Coastguard Worker class LinearGradientGM : public skiagm::GM {
669*c8dee2aaSAndroid Build Coastguard Worker public:
LinearGradientGM(bool dither)670*c8dee2aaSAndroid Build Coastguard Worker LinearGradientGM(bool dither) : fDither(dither) { }
671*c8dee2aaSAndroid Build Coastguard Worker
672*c8dee2aaSAndroid Build Coastguard Worker private:
getName() const673*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override {
674*c8dee2aaSAndroid Build Coastguard Worker return SkString(fDither ? "linear_gradient" : "linear_gradient_nodither");
675*c8dee2aaSAndroid Build Coastguard Worker }
676*c8dee2aaSAndroid Build Coastguard Worker
677*c8dee2aaSAndroid Build Coastguard Worker const SkScalar kWidthBump = 30.f;
678*c8dee2aaSAndroid Build Coastguard Worker const SkScalar kHeight = 5.f;
679*c8dee2aaSAndroid Build Coastguard Worker const SkScalar kMinWidth = 540.f;
680*c8dee2aaSAndroid Build Coastguard Worker
getISize()681*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return {500, 500}; }
682*c8dee2aaSAndroid Build Coastguard Worker
onOnceBeforeDraw()683*c8dee2aaSAndroid Build Coastguard Worker void onOnceBeforeDraw() override {
684*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[2] = { {0, 0}, {0, 0} };
685*c8dee2aaSAndroid Build Coastguard Worker const SkColor colors[] = { SK_ColorWHITE, SK_ColorWHITE, 0xFF008200, 0xFF008200,
686*c8dee2aaSAndroid Build Coastguard Worker SK_ColorWHITE, SK_ColorWHITE };
687*c8dee2aaSAndroid Build Coastguard Worker const SkScalar unitPos[] = { 0, 50, 70, 500, 540 };
688*c8dee2aaSAndroid Build Coastguard Worker SkScalar pos[6];
689*c8dee2aaSAndroid Build Coastguard Worker pos[5] = 1;
690*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < (int) std::size(fShader); ++index) {
691*c8dee2aaSAndroid Build Coastguard Worker pts[1].fX = 500.f + index * kWidthBump;
692*c8dee2aaSAndroid Build Coastguard Worker for (int inner = 0; inner < (int) std::size(unitPos); ++inner) {
693*c8dee2aaSAndroid Build Coastguard Worker pos[inner] = unitPos[inner] / (kMinWidth + index * kWidthBump);
694*c8dee2aaSAndroid Build Coastguard Worker }
695*c8dee2aaSAndroid Build Coastguard Worker fShader[index] = SkGradientShader::MakeLinear(pts, colors, pos,
696*c8dee2aaSAndroid Build Coastguard Worker std::size(gColors), SkTileMode::kClamp);
697*c8dee2aaSAndroid Build Coastguard Worker }
698*c8dee2aaSAndroid Build Coastguard Worker }
699*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)700*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
701*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
702*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
703*c8dee2aaSAndroid Build Coastguard Worker paint.setDither(fDither);
704*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < (int) std::size(fShader); ++index) {
705*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(fShader[index]);
706*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(SkRect::MakeLTRB(0, index * kHeight, kMinWidth + index * kWidthBump,
707*c8dee2aaSAndroid Build Coastguard Worker (index + 1) * kHeight), paint);
708*c8dee2aaSAndroid Build Coastguard Worker }
709*c8dee2aaSAndroid Build Coastguard Worker }
710*c8dee2aaSAndroid Build Coastguard Worker
711*c8dee2aaSAndroid Build Coastguard Worker private:
712*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> fShader[100];
713*c8dee2aaSAndroid Build Coastguard Worker bool fDither;
714*c8dee2aaSAndroid Build Coastguard Worker
715*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = GM;
716*c8dee2aaSAndroid Build Coastguard Worker };
717*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new LinearGradientGM(true); )
718*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new LinearGradientGM(false); )
719*c8dee2aaSAndroid Build Coastguard Worker
720*c8dee2aaSAndroid Build Coastguard Worker class LinearGradientTinyGM : public skiagm::GM {
721*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr uint32_t kFlags = 0;
722*c8dee2aaSAndroid Build Coastguard Worker
getName() const723*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override { return SkString("linear_gradient_tiny"); }
724*c8dee2aaSAndroid Build Coastguard Worker
getISize()725*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return {600, 500}; }
726*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)727*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
728*c8dee2aaSAndroid Build Coastguard Worker const SkScalar kRectSize = 100;
729*c8dee2aaSAndroid Build Coastguard Worker const unsigned kStopCount = 3;
730*c8dee2aaSAndroid Build Coastguard Worker const SkColor colors[kStopCount] = { SK_ColorGREEN, SK_ColorRED, SK_ColorGREEN };
731*c8dee2aaSAndroid Build Coastguard Worker const struct {
732*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[2];
733*c8dee2aaSAndroid Build Coastguard Worker SkScalar pos[kStopCount];
734*c8dee2aaSAndroid Build Coastguard Worker } configs[] = {
735*c8dee2aaSAndroid Build Coastguard Worker { { SkPoint::Make(0, 0), SkPoint::Make(10, 0) }, { 0, 0.999999f, 1 }},
736*c8dee2aaSAndroid Build Coastguard Worker { { SkPoint::Make(0, 0), SkPoint::Make(10, 0) }, { 0, 0.000001f, 1 }},
737*c8dee2aaSAndroid Build Coastguard Worker { { SkPoint::Make(0, 0), SkPoint::Make(10, 0) }, { 0, 0.999999999f, 1 }},
738*c8dee2aaSAndroid Build Coastguard Worker { { SkPoint::Make(0, 0), SkPoint::Make(10, 0) }, { 0, 0.000000001f, 1 }},
739*c8dee2aaSAndroid Build Coastguard Worker
740*c8dee2aaSAndroid Build Coastguard Worker { { SkPoint::Make(0, 0), SkPoint::Make(0, 10) }, { 0, 0.999999f, 1 }},
741*c8dee2aaSAndroid Build Coastguard Worker { { SkPoint::Make(0, 0), SkPoint::Make(0, 10) }, { 0, 0.000001f, 1 }},
742*c8dee2aaSAndroid Build Coastguard Worker { { SkPoint::Make(0, 0), SkPoint::Make(0, 10) }, { 0, 0.999999999f, 1 }},
743*c8dee2aaSAndroid Build Coastguard Worker { { SkPoint::Make(0, 0), SkPoint::Make(0, 10) }, { 0, 0.000000001f, 1 }},
744*c8dee2aaSAndroid Build Coastguard Worker
745*c8dee2aaSAndroid Build Coastguard Worker { { SkPoint::Make(0, 0), SkPoint::Make(0.00001f, 0) }, { 0, 0.5f, 1 }},
746*c8dee2aaSAndroid Build Coastguard Worker { { SkPoint::Make(9.99999f, 0), SkPoint::Make(10, 0) }, { 0, 0.5f, 1 }},
747*c8dee2aaSAndroid Build Coastguard Worker { { SkPoint::Make(0, 0), SkPoint::Make(0, 0.00001f) }, { 0, 0.5f, 1 }},
748*c8dee2aaSAndroid Build Coastguard Worker { { SkPoint::Make(0, 9.99999f), SkPoint::Make(0, 10) }, { 0, 0.5f, 1 }},
749*c8dee2aaSAndroid Build Coastguard Worker };
750*c8dee2aaSAndroid Build Coastguard Worker
751*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
752*c8dee2aaSAndroid Build Coastguard Worker for (unsigned i = 0; i < std::size(configs); ++i) {
753*c8dee2aaSAndroid Build Coastguard Worker SkAutoCanvasRestore acr(canvas, true);
754*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(SkGradientShader::MakeLinear(configs[i].pts, colors, configs[i].pos,
755*c8dee2aaSAndroid Build Coastguard Worker kStopCount, SkTileMode::kClamp,
756*c8dee2aaSAndroid Build Coastguard Worker kFlags, nullptr));
757*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(kRectSize * ((i % 4) * 1.5f + 0.25f),
758*c8dee2aaSAndroid Build Coastguard Worker kRectSize * ((i / 4) * 1.5f + 0.25f));
759*c8dee2aaSAndroid Build Coastguard Worker
760*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(SkRect::MakeWH(kRectSize, kRectSize), paint);
761*c8dee2aaSAndroid Build Coastguard Worker }
762*c8dee2aaSAndroid Build Coastguard Worker }
763*c8dee2aaSAndroid Build Coastguard Worker };
764*c8dee2aaSAndroid Build Coastguard Worker
765*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new LinearGradientTinyGM; )
766*c8dee2aaSAndroid Build Coastguard Worker } // namespace
767*c8dee2aaSAndroid Build Coastguard Worker
768*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
769*c8dee2aaSAndroid Build Coastguard Worker
770*c8dee2aaSAndroid Build Coastguard Worker struct GradRun {
771*c8dee2aaSAndroid Build Coastguard Worker SkColor fColors[4];
772*c8dee2aaSAndroid Build Coastguard Worker SkScalar fPos[4];
773*c8dee2aaSAndroid Build Coastguard Worker int fCount;
774*c8dee2aaSAndroid Build Coastguard Worker };
775*c8dee2aaSAndroid Build Coastguard Worker
776*c8dee2aaSAndroid Build Coastguard Worker #define SIZE 121
777*c8dee2aaSAndroid Build Coastguard Worker
make_linear(const GradRun & run,SkTileMode mode)778*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> make_linear(const GradRun& run, SkTileMode mode) {
779*c8dee2aaSAndroid Build Coastguard Worker const SkPoint pts[] { { 30, 30 }, { SIZE - 30, SIZE - 30 } };
780*c8dee2aaSAndroid Build Coastguard Worker return SkGradientShader::MakeLinear(pts, run.fColors, run.fPos, run.fCount, mode);
781*c8dee2aaSAndroid Build Coastguard Worker }
782*c8dee2aaSAndroid Build Coastguard Worker
make_radial(const GradRun & run,SkTileMode mode)783*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> make_radial(const GradRun& run, SkTileMode mode) {
784*c8dee2aaSAndroid Build Coastguard Worker const SkScalar half = SIZE * 0.5f;
785*c8dee2aaSAndroid Build Coastguard Worker return SkGradientShader::MakeRadial({half,half}, half - 10, run.fColors, run.fPos,
786*c8dee2aaSAndroid Build Coastguard Worker run.fCount, mode);
787*c8dee2aaSAndroid Build Coastguard Worker }
788*c8dee2aaSAndroid Build Coastguard Worker
make_conical(const GradRun & run,SkTileMode mode)789*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> make_conical(const GradRun& run, SkTileMode mode) {
790*c8dee2aaSAndroid Build Coastguard Worker const SkScalar half = SIZE * 0.5f;
791*c8dee2aaSAndroid Build Coastguard Worker const SkPoint center { half, half };
792*c8dee2aaSAndroid Build Coastguard Worker return SkGradientShader::MakeTwoPointConical(center, 20, center, half - 10,
793*c8dee2aaSAndroid Build Coastguard Worker run.fColors, run.fPos, run.fCount, mode);
794*c8dee2aaSAndroid Build Coastguard Worker }
795*c8dee2aaSAndroid Build Coastguard Worker
make_sweep(const GradRun & run,SkTileMode)796*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkShader> make_sweep(const GradRun& run, SkTileMode) {
797*c8dee2aaSAndroid Build Coastguard Worker const SkScalar half = SIZE * 0.5f;
798*c8dee2aaSAndroid Build Coastguard Worker return SkGradientShader::MakeSweep(half, half, run.fColors, run.fPos, run.fCount);
799*c8dee2aaSAndroid Build Coastguard Worker }
800*c8dee2aaSAndroid Build Coastguard Worker
801*c8dee2aaSAndroid Build Coastguard Worker /*
802*c8dee2aaSAndroid Build Coastguard Worker * Exercise duplicate color-stops, at the ends, and in the middle
803*c8dee2aaSAndroid Build Coastguard Worker *
804*c8dee2aaSAndroid Build Coastguard Worker * At the time of this writing, only Linear correctly deals with duplicates at the ends,
805*c8dee2aaSAndroid Build Coastguard Worker * and then only correctly on CPU backend.
806*c8dee2aaSAndroid Build Coastguard Worker */
807*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(gradients_dup_color_stops, canvas, 704, 564) {
808*c8dee2aaSAndroid Build Coastguard Worker const SkColor preColor = 0xFFFF0000; // clamp color before start
809*c8dee2aaSAndroid Build Coastguard Worker const SkColor postColor = 0xFF0000FF; // clamp color after end
810*c8dee2aaSAndroid Build Coastguard Worker const SkColor color0 = 0xFF000000;
811*c8dee2aaSAndroid Build Coastguard Worker const SkColor color1 = 0xFF00FF00;
812*c8dee2aaSAndroid Build Coastguard Worker const SkColor badColor = 0xFF3388BB; // should never be seen, fills out fixed-size array
813*c8dee2aaSAndroid Build Coastguard Worker
814*c8dee2aaSAndroid Build Coastguard Worker const GradRun runs[] = {
815*c8dee2aaSAndroid Build Coastguard Worker { { color0, color1, badColor, badColor },
816*c8dee2aaSAndroid Build Coastguard Worker { 0, 1, -1, -1 },
817*c8dee2aaSAndroid Build Coastguard Worker 2,
818*c8dee2aaSAndroid Build Coastguard Worker },
819*c8dee2aaSAndroid Build Coastguard Worker { { preColor, color0, color1, badColor },
820*c8dee2aaSAndroid Build Coastguard Worker { 0, 0, 1, -1 },
821*c8dee2aaSAndroid Build Coastguard Worker 3,
822*c8dee2aaSAndroid Build Coastguard Worker },
823*c8dee2aaSAndroid Build Coastguard Worker { { color0, color1, postColor, badColor },
824*c8dee2aaSAndroid Build Coastguard Worker { 0, 1, 1, -1 },
825*c8dee2aaSAndroid Build Coastguard Worker 3,
826*c8dee2aaSAndroid Build Coastguard Worker },
827*c8dee2aaSAndroid Build Coastguard Worker { { preColor, color0, color1, postColor },
828*c8dee2aaSAndroid Build Coastguard Worker { 0, 0, 1, 1 },
829*c8dee2aaSAndroid Build Coastguard Worker 4,
830*c8dee2aaSAndroid Build Coastguard Worker },
831*c8dee2aaSAndroid Build Coastguard Worker { { color0, color0, color1, color1 },
832*c8dee2aaSAndroid Build Coastguard Worker { 0, 0.5f, 0.5f, 1 },
833*c8dee2aaSAndroid Build Coastguard Worker 4,
834*c8dee2aaSAndroid Build Coastguard Worker },
835*c8dee2aaSAndroid Build Coastguard Worker };
836*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> (*factories[])(const GradRun&, SkTileMode) {
837*c8dee2aaSAndroid Build Coastguard Worker make_linear, make_radial, make_conical, make_sweep
838*c8dee2aaSAndroid Build Coastguard Worker };
839*c8dee2aaSAndroid Build Coastguard Worker
840*c8dee2aaSAndroid Build Coastguard Worker const SkRect rect = SkRect::MakeWH(SIZE, SIZE);
841*c8dee2aaSAndroid Build Coastguard Worker const SkScalar dx = SIZE + 20;
842*c8dee2aaSAndroid Build Coastguard Worker const SkScalar dy = SIZE + 20;
843*c8dee2aaSAndroid Build Coastguard Worker const SkTileMode mode = SkTileMode::kClamp;
844*c8dee2aaSAndroid Build Coastguard Worker
845*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
846*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(10, 10 - dy);
847*c8dee2aaSAndroid Build Coastguard Worker for (auto factory : factories) {
848*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, dy);
849*c8dee2aaSAndroid Build Coastguard Worker SkAutoCanvasRestore acr(canvas, true);
850*c8dee2aaSAndroid Build Coastguard Worker for (const auto& run : runs) {
851*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(factory(run, mode));
852*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(rect, paint);
853*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(dx, 0);
854*c8dee2aaSAndroid Build Coastguard Worker }
855*c8dee2aaSAndroid Build Coastguard Worker }
856*c8dee2aaSAndroid Build Coastguard Worker }
857*c8dee2aaSAndroid Build Coastguard Worker
draw_many_stops(SkCanvas * canvas)858*c8dee2aaSAndroid Build Coastguard Worker static void draw_many_stops(SkCanvas* canvas) {
859*c8dee2aaSAndroid Build Coastguard Worker const unsigned kStopCount = 200;
860*c8dee2aaSAndroid Build Coastguard Worker const SkPoint pts[] = { {50, 50}, {450, 450}};
861*c8dee2aaSAndroid Build Coastguard Worker
862*c8dee2aaSAndroid Build Coastguard Worker SkColor colors[kStopCount];
863*c8dee2aaSAndroid Build Coastguard Worker for (unsigned i = 0; i < kStopCount; i++) {
864*c8dee2aaSAndroid Build Coastguard Worker switch (i % 5) {
865*c8dee2aaSAndroid Build Coastguard Worker case 0: colors[i] = SK_ColorRED; break;
866*c8dee2aaSAndroid Build Coastguard Worker case 1: colors[i] = SK_ColorGREEN; break;
867*c8dee2aaSAndroid Build Coastguard Worker case 2: colors[i] = SK_ColorGREEN; break;
868*c8dee2aaSAndroid Build Coastguard Worker case 3: colors[i] = SK_ColorBLUE; break;
869*c8dee2aaSAndroid Build Coastguard Worker case 4: colors[i] = SK_ColorRED; break;
870*c8dee2aaSAndroid Build Coastguard Worker }
871*c8dee2aaSAndroid Build Coastguard Worker }
872*c8dee2aaSAndroid Build Coastguard Worker
873*c8dee2aaSAndroid Build Coastguard Worker SkPaint p;
874*c8dee2aaSAndroid Build Coastguard Worker p.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, std::size(colors),
875*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp));
876*c8dee2aaSAndroid Build Coastguard Worker
877*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(SkRect::MakeXYWH(0, 0, 500, 500), p);
878*c8dee2aaSAndroid Build Coastguard Worker }
879*c8dee2aaSAndroid Build Coastguard Worker
880*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(gradient_many_stops, canvas, 500, 500) {
881*c8dee2aaSAndroid Build Coastguard Worker draw_many_stops(canvas);
882*c8dee2aaSAndroid Build Coastguard Worker }
883*c8dee2aaSAndroid Build Coastguard Worker
draw_many_hard_stops(SkCanvas * canvas)884*c8dee2aaSAndroid Build Coastguard Worker static void draw_many_hard_stops(SkCanvas* canvas) {
885*c8dee2aaSAndroid Build Coastguard Worker const unsigned kStopCount = 300;
886*c8dee2aaSAndroid Build Coastguard Worker const SkPoint pts[] = {{50, 50}, {450, 450}};
887*c8dee2aaSAndroid Build Coastguard Worker
888*c8dee2aaSAndroid Build Coastguard Worker SkColor colors[kStopCount];
889*c8dee2aaSAndroid Build Coastguard Worker SkScalar pos[kStopCount];
890*c8dee2aaSAndroid Build Coastguard Worker for (unsigned i = 0; i < kStopCount; i++) {
891*c8dee2aaSAndroid Build Coastguard Worker switch (i % 6) {
892*c8dee2aaSAndroid Build Coastguard Worker case 0: colors[i] = SK_ColorRED; break;
893*c8dee2aaSAndroid Build Coastguard Worker case 1: colors[i] = SK_ColorGREEN; break;
894*c8dee2aaSAndroid Build Coastguard Worker case 2: colors[i] = SK_ColorGREEN; break;
895*c8dee2aaSAndroid Build Coastguard Worker case 3: colors[i] = SK_ColorBLUE; break;
896*c8dee2aaSAndroid Build Coastguard Worker case 4: colors[i] = SK_ColorBLUE; break;
897*c8dee2aaSAndroid Build Coastguard Worker case 5: colors[i] = SK_ColorRED; break;
898*c8dee2aaSAndroid Build Coastguard Worker }
899*c8dee2aaSAndroid Build Coastguard Worker pos[i] = (2.0f * (i / 2)) / kStopCount;
900*c8dee2aaSAndroid Build Coastguard Worker }
901*c8dee2aaSAndroid Build Coastguard Worker
902*c8dee2aaSAndroid Build Coastguard Worker SkPaint p;
903*c8dee2aaSAndroid Build Coastguard Worker p.setShader(SkGradientShader::MakeLinear(pts, colors, pos, std::size(colors),
904*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp));
905*c8dee2aaSAndroid Build Coastguard Worker
906*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(SkRect::MakeXYWH(0, 0, 500, 500), p);
907*c8dee2aaSAndroid Build Coastguard Worker }
908*c8dee2aaSAndroid Build Coastguard Worker
909*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(gradient_many_hard_stops, canvas, 500, 500) {
910*c8dee2aaSAndroid Build Coastguard Worker draw_many_hard_stops(canvas);
911*c8dee2aaSAndroid Build Coastguard Worker }
912*c8dee2aaSAndroid Build Coastguard Worker
draw_circle_shader(SkCanvas * canvas,SkScalar cx,SkScalar cy,SkScalar r,sk_sp<SkShader> (* shaderFunc)())913*c8dee2aaSAndroid Build Coastguard Worker static void draw_circle_shader(SkCanvas* canvas, SkScalar cx, SkScalar cy, SkScalar r,
914*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> (*shaderFunc)()) {
915*c8dee2aaSAndroid Build Coastguard Worker SkPaint p;
916*c8dee2aaSAndroid Build Coastguard Worker p.setAntiAlias(true);
917*c8dee2aaSAndroid Build Coastguard Worker p.setShader(shaderFunc());
918*c8dee2aaSAndroid Build Coastguard Worker canvas->drawCircle(cx, cy, r, p);
919*c8dee2aaSAndroid Build Coastguard Worker
920*c8dee2aaSAndroid Build Coastguard Worker p.setShader(nullptr);
921*c8dee2aaSAndroid Build Coastguard Worker p.setColor(SK_ColorGRAY);
922*c8dee2aaSAndroid Build Coastguard Worker p.setStyle(SkPaint::kStroke_Style);
923*c8dee2aaSAndroid Build Coastguard Worker p.setStrokeWidth(2);
924*c8dee2aaSAndroid Build Coastguard Worker canvas->drawCircle(cx, cy, r, p);
925*c8dee2aaSAndroid Build Coastguard Worker }
926*c8dee2aaSAndroid Build Coastguard Worker
927*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(fancy_gradients, canvas, 800, 300) {
__anon463408530302() 928*c8dee2aaSAndroid Build Coastguard Worker draw_circle_shader(canvas, 150, 150, 100, []() -> sk_sp<SkShader> {
929*c8dee2aaSAndroid Build Coastguard Worker // Checkerboard using two linear gradients + picture shader.
930*c8dee2aaSAndroid Build Coastguard Worker SkScalar kTileSize = 80 / sqrtf(2);
931*c8dee2aaSAndroid Build Coastguard Worker SkColor colors1[] = { 0xff000000, 0xff000000,
932*c8dee2aaSAndroid Build Coastguard Worker 0xffffffff, 0xffffffff,
933*c8dee2aaSAndroid Build Coastguard Worker 0xff000000, 0xff000000 };
934*c8dee2aaSAndroid Build Coastguard Worker SkColor colors2[] = { 0xff000000, 0xff000000,
935*c8dee2aaSAndroid Build Coastguard Worker 0x00000000, 0x00000000,
936*c8dee2aaSAndroid Build Coastguard Worker 0xff000000, 0xff000000 };
937*c8dee2aaSAndroid Build Coastguard Worker SkScalar pos[] = { 0, .25f, .25f, .75f, .75f, 1 };
938*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::size(colors1) == std::size(pos), "color/pos size mismatch");
939*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::size(colors2) == std::size(pos), "color/pos size mismatch");
940*c8dee2aaSAndroid Build Coastguard Worker
941*c8dee2aaSAndroid Build Coastguard Worker SkPictureRecorder recorder;
942*c8dee2aaSAndroid Build Coastguard Worker recorder.beginRecording(SkRect::MakeWH(kTileSize, kTileSize));
943*c8dee2aaSAndroid Build Coastguard Worker
944*c8dee2aaSAndroid Build Coastguard Worker SkPaint p;
945*c8dee2aaSAndroid Build Coastguard Worker
946*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts1[] = { { 0, 0 }, { kTileSize, kTileSize }};
947*c8dee2aaSAndroid Build Coastguard Worker p.setShader(SkGradientShader::MakeLinear(pts1, colors1, pos, std::size(colors1),
948*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp, 0, nullptr));
949*c8dee2aaSAndroid Build Coastguard Worker recorder.getRecordingCanvas()->drawPaint(p);
950*c8dee2aaSAndroid Build Coastguard Worker
951*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts2[] = { { 0, kTileSize }, { kTileSize, 0 }};
952*c8dee2aaSAndroid Build Coastguard Worker p.setShader(SkGradientShader::MakeLinear(pts2, colors2, pos, std::size(colors2),
953*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp, 0, nullptr));
954*c8dee2aaSAndroid Build Coastguard Worker recorder.getRecordingCanvas()->drawPaint(p);
955*c8dee2aaSAndroid Build Coastguard Worker
956*c8dee2aaSAndroid Build Coastguard Worker SkMatrix m = SkMatrix::I();
957*c8dee2aaSAndroid Build Coastguard Worker m.preRotate(45);
958*c8dee2aaSAndroid Build Coastguard Worker return recorder.finishRecordingAsPicture()->makeShader(
959*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kRepeat, SkTileMode::kRepeat,
960*c8dee2aaSAndroid Build Coastguard Worker SkFilterMode::kNearest, &m, nullptr);
961*c8dee2aaSAndroid Build Coastguard Worker });
962*c8dee2aaSAndroid Build Coastguard Worker
__anon463408530402() 963*c8dee2aaSAndroid Build Coastguard Worker draw_circle_shader(canvas, 400, 150, 100, []() -> sk_sp<SkShader> {
964*c8dee2aaSAndroid Build Coastguard Worker // Checkerboard using a sweep gradient + picture shader.
965*c8dee2aaSAndroid Build Coastguard Worker SkScalar kTileSize = 80;
966*c8dee2aaSAndroid Build Coastguard Worker SkColor colors[] = { 0xff000000, 0xff000000,
967*c8dee2aaSAndroid Build Coastguard Worker 0xffffffff, 0xffffffff,
968*c8dee2aaSAndroid Build Coastguard Worker 0xff000000, 0xff000000,
969*c8dee2aaSAndroid Build Coastguard Worker 0xffffffff, 0xffffffff };
970*c8dee2aaSAndroid Build Coastguard Worker SkScalar pos[] = { 0, .25f, .25f, .5f, .5f, .75f, .75f, 1 };
971*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::size(colors) == std::size(pos), "color/pos size mismatch");
972*c8dee2aaSAndroid Build Coastguard Worker
973*c8dee2aaSAndroid Build Coastguard Worker SkPaint p;
974*c8dee2aaSAndroid Build Coastguard Worker p.setShader(SkGradientShader::MakeSweep(kTileSize / 2, kTileSize / 2,
975*c8dee2aaSAndroid Build Coastguard Worker colors, pos, std::size(colors), 0, nullptr));
976*c8dee2aaSAndroid Build Coastguard Worker SkPictureRecorder recorder;
977*c8dee2aaSAndroid Build Coastguard Worker recorder.beginRecording(SkRect::MakeWH(kTileSize, kTileSize))->drawPaint(p);
978*c8dee2aaSAndroid Build Coastguard Worker
979*c8dee2aaSAndroid Build Coastguard Worker return recorder.finishRecordingAsPicture()->makeShader(
980*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kRepeat,
981*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kRepeat, SkFilterMode::kNearest);
982*c8dee2aaSAndroid Build Coastguard Worker });
983*c8dee2aaSAndroid Build Coastguard Worker
__anon463408530502() 984*c8dee2aaSAndroid Build Coastguard Worker draw_circle_shader(canvas, 650, 150, 100, []() -> sk_sp<SkShader> {
985*c8dee2aaSAndroid Build Coastguard Worker // Dartboard using sweep + radial.
986*c8dee2aaSAndroid Build Coastguard Worker const SkColor a = 0xffffffff;
987*c8dee2aaSAndroid Build Coastguard Worker const SkColor b = 0xff000000;
988*c8dee2aaSAndroid Build Coastguard Worker SkColor colors[] = { a, a, b, b, a, a, b, b, a, a, b, b, a, a, b, b};
989*c8dee2aaSAndroid Build Coastguard Worker SkScalar pos[] = { 0, .125f, .125f, .25f, .25f, .375f, .375f, .5f, .5f,
990*c8dee2aaSAndroid Build Coastguard Worker .625f, .625f, .75f, .75f, .875f, .875f, 1};
991*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::size(colors) == std::size(pos), "color/pos size mismatch");
992*c8dee2aaSAndroid Build Coastguard Worker
993*c8dee2aaSAndroid Build Coastguard Worker SkPoint center = { 650, 150 };
994*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> sweep1 = SkGradientShader::MakeSweep(center.x(), center.y(), colors, pos,
995*c8dee2aaSAndroid Build Coastguard Worker std::size(colors), 0, nullptr);
996*c8dee2aaSAndroid Build Coastguard Worker SkMatrix m = SkMatrix::I();
997*c8dee2aaSAndroid Build Coastguard Worker m.preRotate(22.5f, center.x(), center.y());
998*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> sweep2 = SkGradientShader::MakeSweep(center.x(), center.y(), colors, pos,
999*c8dee2aaSAndroid Build Coastguard Worker std::size(colors), 0, &m);
1000*c8dee2aaSAndroid Build Coastguard Worker
1001*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> sweep(SkShaders::Blend(SkBlendMode::kExclusion, sweep1, sweep2));
1002*c8dee2aaSAndroid Build Coastguard Worker
1003*c8dee2aaSAndroid Build Coastguard Worker SkScalar radialPos[] = { 0, .02f, .02f, .04f, .04f, .08f, .08f, .16f, .16f, .31f, .31f,
1004*c8dee2aaSAndroid Build Coastguard Worker .62f, .62f, 1, 1, 1 };
1005*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::size(colors) == std::size(radialPos),
1006*c8dee2aaSAndroid Build Coastguard Worker "color/pos size mismatch");
1007*c8dee2aaSAndroid Build Coastguard Worker
1008*c8dee2aaSAndroid Build Coastguard Worker return SkShaders::Blend(SkBlendMode::kExclusion, sweep,
1009*c8dee2aaSAndroid Build Coastguard Worker SkGradientShader::MakeRadial(center, 100, colors,
1010*c8dee2aaSAndroid Build Coastguard Worker radialPos,
1011*c8dee2aaSAndroid Build Coastguard Worker std::size(radialPos),
1012*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp));
1013*c8dee2aaSAndroid Build Coastguard Worker });
1014*c8dee2aaSAndroid Build Coastguard Worker }
1015*c8dee2aaSAndroid Build Coastguard Worker
1016*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(sweep_tiling, canvas, 690, 512) {
1017*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar size = 160;
1018*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkColor colors[] = { SK_ColorBLUE, SK_ColorYELLOW, SK_ColorGREEN };
1019*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar pos[] = { 0, .25f, .50f };
1020*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::size(colors) == std::size(pos), "size mismatch");
1021*c8dee2aaSAndroid Build Coastguard Worker
1022*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkTileMode modes[] = { SkTileMode::kClamp,
1023*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kRepeat,
1024*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kMirror };
1025*c8dee2aaSAndroid Build Coastguard Worker
1026*c8dee2aaSAndroid Build Coastguard Worker static const struct {
1027*c8dee2aaSAndroid Build Coastguard Worker SkScalar start, end;
1028*c8dee2aaSAndroid Build Coastguard Worker } angles[] = {
1029*c8dee2aaSAndroid Build Coastguard Worker { -330, -270 },
1030*c8dee2aaSAndroid Build Coastguard Worker { 30, 90 },
1031*c8dee2aaSAndroid Build Coastguard Worker { 390, 450 },
1032*c8dee2aaSAndroid Build Coastguard Worker { -30, 800 },
1033*c8dee2aaSAndroid Build Coastguard Worker };
1034*c8dee2aaSAndroid Build Coastguard Worker
1035*c8dee2aaSAndroid Build Coastguard Worker SkPaint p;
1036*c8dee2aaSAndroid Build Coastguard Worker const SkRect r = SkRect::MakeWH(size, size);
1037*c8dee2aaSAndroid Build Coastguard Worker
1038*c8dee2aaSAndroid Build Coastguard Worker for (auto mode : modes) {
1039*c8dee2aaSAndroid Build Coastguard Worker {
1040*c8dee2aaSAndroid Build Coastguard Worker SkAutoCanvasRestore acr(canvas, true);
1041*c8dee2aaSAndroid Build Coastguard Worker
1042*c8dee2aaSAndroid Build Coastguard Worker for (auto angle : angles) {
1043*c8dee2aaSAndroid Build Coastguard Worker p.setShader(SkGradientShader::MakeSweep(size / 2, size / 2, colors, pos,
1044*c8dee2aaSAndroid Build Coastguard Worker std::size(colors), mode,
1045*c8dee2aaSAndroid Build Coastguard Worker angle.start, angle.end, 0, nullptr));
1046*c8dee2aaSAndroid Build Coastguard Worker
1047*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(r, p);
1048*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(size * 1.1f, 0);
1049*c8dee2aaSAndroid Build Coastguard Worker }
1050*c8dee2aaSAndroid Build Coastguard Worker }
1051*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, size * 1.1f);
1052*c8dee2aaSAndroid Build Coastguard Worker }
1053*c8dee2aaSAndroid Build Coastguard Worker }
1054*c8dee2aaSAndroid Build Coastguard Worker
1055*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(rgbw_sweep_gradient, canvas, 100, 100) {
1056*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar size = 100;
1057*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkColor colors[] = {SK_ColorWHITE, SK_ColorWHITE,
1058*c8dee2aaSAndroid Build Coastguard Worker SK_ColorBLUE, SK_ColorBLUE,
1059*c8dee2aaSAndroid Build Coastguard Worker SK_ColorRED, SK_ColorRED,
1060*c8dee2aaSAndroid Build Coastguard Worker SK_ColorGREEN, SK_ColorGREEN};
1061*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar pos[] = { 0, .25f, .25f, .50f, .50f, .75, .75, 1 };
1062*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::size(colors) == std::size(pos), "size mismatch");
1063*c8dee2aaSAndroid Build Coastguard Worker
1064*c8dee2aaSAndroid Build Coastguard Worker SkPaint p;
1065*c8dee2aaSAndroid Build Coastguard Worker p.setShader(SkGradientShader::MakeSweep(size / 2, size / 2, colors, pos, std::size(colors)));
1066*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(SkRect::MakeWH(size, size), p);
1067*c8dee2aaSAndroid Build Coastguard Worker }
1068*c8dee2aaSAndroid Build Coastguard Worker
1069*c8dee2aaSAndroid Build Coastguard Worker // Exercises the special-case Ganesh gradient effects.
1070*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(gradients_interesting, canvas, 640, 1300) {
1071*c8dee2aaSAndroid Build Coastguard Worker static const SkColor colors2[] = { SK_ColorRED, SK_ColorBLUE };
1072*c8dee2aaSAndroid Build Coastguard Worker static const SkColor colors3[] = { SK_ColorRED, SK_ColorYELLOW, SK_ColorBLUE };
1073*c8dee2aaSAndroid Build Coastguard Worker static const SkColor colors4[] = { SK_ColorRED, SK_ColorYELLOW, SK_ColorYELLOW, SK_ColorBLUE };
1074*c8dee2aaSAndroid Build Coastguard Worker
1075*c8dee2aaSAndroid Build Coastguard Worker static const SkScalar softRight[] = { 0, .999f, 1 }; // Based on Android launcher "clipping"
1076*c8dee2aaSAndroid Build Coastguard Worker static const SkScalar hardLeft[] = { 0, 0, 1 };
1077*c8dee2aaSAndroid Build Coastguard Worker static const SkScalar hardRight[] = { 0, 1, 1 };
1078*c8dee2aaSAndroid Build Coastguard Worker static const SkScalar hardCenter[] = { 0, .5f, .5f, 1 };
1079*c8dee2aaSAndroid Build Coastguard Worker
1080*c8dee2aaSAndroid Build Coastguard Worker static const struct {
1081*c8dee2aaSAndroid Build Coastguard Worker const SkColor* colors;
1082*c8dee2aaSAndroid Build Coastguard Worker const SkScalar* pos;
1083*c8dee2aaSAndroid Build Coastguard Worker int count;
1084*c8dee2aaSAndroid Build Coastguard Worker } configs[] = {
1085*c8dee2aaSAndroid Build Coastguard Worker { colors2, nullptr, 2 }, // kTwo_ColorType
1086*c8dee2aaSAndroid Build Coastguard Worker { colors3, nullptr, 3 }, // kThree_ColorType (simple)
1087*c8dee2aaSAndroid Build Coastguard Worker { colors3, softRight, 3 }, // kThree_ColorType (tricky)
1088*c8dee2aaSAndroid Build Coastguard Worker { colors3, hardLeft, 3 }, // kHardStopLeftEdged_ColorType
1089*c8dee2aaSAndroid Build Coastguard Worker { colors3, hardRight, 3 }, // kHardStopRightEdged_ColorType
1090*c8dee2aaSAndroid Build Coastguard Worker { colors4, hardCenter, 4 }, // kSingleHardStop_ColorType
1091*c8dee2aaSAndroid Build Coastguard Worker };
1092*c8dee2aaSAndroid Build Coastguard Worker
1093*c8dee2aaSAndroid Build Coastguard Worker static const SkTileMode modes[] = {
1094*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp,
1095*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kRepeat,
1096*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kMirror,
1097*c8dee2aaSAndroid Build Coastguard Worker };
1098*c8dee2aaSAndroid Build Coastguard Worker
1099*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar size = 200;
1100*c8dee2aaSAndroid Build Coastguard Worker static const SkPoint pts[] = { { size / 3, size / 3 }, { size * 2 / 3, size * 2 / 3} };
1101*c8dee2aaSAndroid Build Coastguard Worker
1102*c8dee2aaSAndroid Build Coastguard Worker SkPaint p;
1103*c8dee2aaSAndroid Build Coastguard Worker for (const auto& cfg : configs) {
1104*c8dee2aaSAndroid Build Coastguard Worker {
1105*c8dee2aaSAndroid Build Coastguard Worker SkAutoCanvasRestore acr(canvas, true);
1106*c8dee2aaSAndroid Build Coastguard Worker for (auto mode : modes) {
1107*c8dee2aaSAndroid Build Coastguard Worker p.setShader(SkGradientShader::MakeLinear(pts, cfg.colors, cfg.pos, cfg.count,
1108*c8dee2aaSAndroid Build Coastguard Worker mode));
1109*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(SkRect::MakeWH(size, size), p);
1110*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(size * 1.1f, 0);
1111*c8dee2aaSAndroid Build Coastguard Worker }
1112*c8dee2aaSAndroid Build Coastguard Worker }
1113*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, size * 1.1f);
1114*c8dee2aaSAndroid Build Coastguard Worker }
1115*c8dee2aaSAndroid Build Coastguard Worker }
1116*c8dee2aaSAndroid Build Coastguard Worker
1117*c8dee2aaSAndroid Build Coastguard Worker // TODO(skia:13774): Still need to test degenerate gradients in strange color spaces
1118*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM_BG(gradients_color_space, canvas, 265, 255, SK_ColorGRAY) {
1119*c8dee2aaSAndroid Build Coastguard Worker using CS = SkGradientShader::Interpolation::ColorSpace;
1120*c8dee2aaSAndroid Build Coastguard Worker
1121*c8dee2aaSAndroid Build Coastguard Worker struct Config {
1122*c8dee2aaSAndroid Build Coastguard Worker CS fColorSpace;
1123*c8dee2aaSAndroid Build Coastguard Worker const char* fLabel;
1124*c8dee2aaSAndroid Build Coastguard Worker };
1125*c8dee2aaSAndroid Build Coastguard Worker static const Config kConfigs[] = {
1126*c8dee2aaSAndroid Build Coastguard Worker { CS::kSRGB, "sRGB" },
1127*c8dee2aaSAndroid Build Coastguard Worker { CS::kSRGBLinear, "Linear" },
1128*c8dee2aaSAndroid Build Coastguard Worker { CS::kLab, "Lab" },
1129*c8dee2aaSAndroid Build Coastguard Worker { CS::kOKLab, "OKLab" },
1130*c8dee2aaSAndroid Build Coastguard Worker { CS::kOKLabGamutMap, "OKLabGamutMap" },
1131*c8dee2aaSAndroid Build Coastguard Worker { CS::kLCH, "LCH" },
1132*c8dee2aaSAndroid Build Coastguard Worker { CS::kOKLCH, "OKLCH" },
1133*c8dee2aaSAndroid Build Coastguard Worker { CS::kOKLCHGamutMap, "OKLCHGamutMap" },
1134*c8dee2aaSAndroid Build Coastguard Worker { CS::kHSL, "HSL" },
1135*c8dee2aaSAndroid Build Coastguard Worker { CS::kHWB, "HWB" },
1136*c8dee2aaSAndroid Build Coastguard Worker };
1137*c8dee2aaSAndroid Build Coastguard Worker
1138*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[] = {{0, 0}, {200, 0}};
1139*c8dee2aaSAndroid Build Coastguard Worker SkColor4f colors[] = {SkColors::kBlue, SkColors::kYellow};
1140*c8dee2aaSAndroid Build Coastguard Worker
1141*c8dee2aaSAndroid Build Coastguard Worker SkPaint labelPaint;
1142*c8dee2aaSAndroid Build Coastguard Worker SkPaint p;
1143*c8dee2aaSAndroid Build Coastguard Worker SkGradientShader::Interpolation interpolation;
1144*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(5, 5);
1145*c8dee2aaSAndroid Build Coastguard Worker SkFont font = ToolUtils::DefaultPortableFont();
1146*c8dee2aaSAndroid Build Coastguard Worker
1147*c8dee2aaSAndroid Build Coastguard Worker for (const Config& config : kConfigs) {
1148*c8dee2aaSAndroid Build Coastguard Worker interpolation.fColorSpace = config.fColorSpace;
1149*c8dee2aaSAndroid Build Coastguard Worker p.setShader(SkGradientShader::MakeLinear(pts, colors, SkColorSpace::MakeSRGB(), nullptr, 2,
1150*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp, interpolation, nullptr));
1151*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect({0, 0, 200, 20}, p);
1152*c8dee2aaSAndroid Build Coastguard Worker canvas->drawSimpleText(config.fLabel, strlen(config.fLabel), SkTextEncoding::kUTF8, 210, 15,
1153*c8dee2aaSAndroid Build Coastguard Worker font, labelPaint);
1154*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, 25);
1155*c8dee2aaSAndroid Build Coastguard Worker }
1156*c8dee2aaSAndroid Build Coastguard Worker }
1157*c8dee2aaSAndroid Build Coastguard Worker
1158*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM_BG(gradients_hue_method, canvas, 285, 155, SK_ColorGRAY) {
1159*c8dee2aaSAndroid Build Coastguard Worker using HM = SkGradientShader::Interpolation::HueMethod;
1160*c8dee2aaSAndroid Build Coastguard Worker
1161*c8dee2aaSAndroid Build Coastguard Worker struct Config {
1162*c8dee2aaSAndroid Build Coastguard Worker HM fHueMethod;
1163*c8dee2aaSAndroid Build Coastguard Worker const char* fLabel;
1164*c8dee2aaSAndroid Build Coastguard Worker };
1165*c8dee2aaSAndroid Build Coastguard Worker static const Config kConfigs[] = {
1166*c8dee2aaSAndroid Build Coastguard Worker { HM::kShorter, "Shorter" },
1167*c8dee2aaSAndroid Build Coastguard Worker { HM::kLonger, "Longer" },
1168*c8dee2aaSAndroid Build Coastguard Worker { HM::kIncreasing, "Increasing" },
1169*c8dee2aaSAndroid Build Coastguard Worker { HM::kDecreasing, "Decreasing" },
1170*c8dee2aaSAndroid Build Coastguard Worker };
1171*c8dee2aaSAndroid Build Coastguard Worker
1172*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[] = {{0, 0}, {200, 0}};
1173*c8dee2aaSAndroid Build Coastguard Worker SkColor4f colors[] = {SkColors::kRed, SkColors::kGreen, SkColors::kRed, SkColors::kRed };
1174*c8dee2aaSAndroid Build Coastguard Worker
1175*c8dee2aaSAndroid Build Coastguard Worker SkPaint labelPaint;
1176*c8dee2aaSAndroid Build Coastguard Worker SkPaint p;
1177*c8dee2aaSAndroid Build Coastguard Worker SkGradientShader::Interpolation interpolation;
1178*c8dee2aaSAndroid Build Coastguard Worker interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kHSL;
1179*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(5, 5);
1180*c8dee2aaSAndroid Build Coastguard Worker SkFont font = ToolUtils::DefaultPortableFont();
1181*c8dee2aaSAndroid Build Coastguard Worker
1182*c8dee2aaSAndroid Build Coastguard Worker for (const Config& config : kConfigs) {
1183*c8dee2aaSAndroid Build Coastguard Worker interpolation.fHueMethod = config.fHueMethod;
1184*c8dee2aaSAndroid Build Coastguard Worker p.setShader(SkGradientShader::MakeLinear(pts, colors, SkColorSpace::MakeSRGB(), nullptr, 4,
1185*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp, interpolation, nullptr));
1186*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect({0, 0, 200, 20}, p);
1187*c8dee2aaSAndroid Build Coastguard Worker canvas->drawSimpleText(config.fLabel, strlen(config.fLabel), SkTextEncoding::kUTF8, 210, 15,
1188*c8dee2aaSAndroid Build Coastguard Worker font, labelPaint);
1189*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, 25);
1190*c8dee2aaSAndroid Build Coastguard Worker }
1191*c8dee2aaSAndroid Build Coastguard Worker
1192*c8dee2aaSAndroid Build Coastguard Worker // Test a bug (skia:13941) with how gradient shaders handle explicit positions.
1193*c8dee2aaSAndroid Build Coastguard Worker // If there are no explicit positions at 0 or 1, those are automatically added, with copies of
1194*c8dee2aaSAndroid Build Coastguard Worker // the first/last color. When using kLonger, this can produce extra gradient that should
1195*c8dee2aaSAndroid Build Coastguard Worker // actually be solid. This gradient *should* be:
1196*c8dee2aaSAndroid Build Coastguard Worker // |- solid red -|- red to green, the long way -|- solid green -|
1197*c8dee2aaSAndroid Build Coastguard Worker interpolation.fHueMethod = HM::kLonger;
1198*c8dee2aaSAndroid Build Coastguard Worker SkScalar middlePos[] = { 0.3f, 0.7f };
1199*c8dee2aaSAndroid Build Coastguard Worker p.setShader(SkGradientShader::MakeLinear(pts, colors, SkColorSpace::MakeSRGB(), middlePos, 2,
1200*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp, interpolation, nullptr));
1201*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect({0, 0, 200, 20}, p);
1202*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, 25);
1203*c8dee2aaSAndroid Build Coastguard Worker
1204*c8dee2aaSAndroid Build Coastguard Worker // However... if the user explicitly includes those duplicate color stops in kLonger mode,
1205*c8dee2aaSAndroid Build Coastguard Worker // we expect the gradient to do a full rotation in those regions:
1206*c8dee2aaSAndroid Build Coastguard Worker // |- full circle, red to red -|- red to green -|- full circle, green to green -|
1207*c8dee2aaSAndroid Build Coastguard Worker colors[0] = colors[1] = SkColors::kRed;
1208*c8dee2aaSAndroid Build Coastguard Worker colors[2] = colors[3] = SkColors::kGreen;
1209*c8dee2aaSAndroid Build Coastguard Worker SkScalar allPos[] = { 0.0f, 0.3f, 0.7f, 1.0f };
1210*c8dee2aaSAndroid Build Coastguard Worker p.setShader(SkGradientShader::MakeLinear(pts, colors, SkColorSpace::MakeSRGB(), allPos, 4,
1211*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp, interpolation, nullptr));
1212*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect({0, 0, 200, 20}, p);
1213*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, 25);
1214*c8dee2aaSAndroid Build Coastguard Worker }
1215*c8dee2aaSAndroid Build Coastguard Worker
1216*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM_BG(gradients_color_space_tilemode, canvas, 360, 105, SK_ColorGRAY) {
1217*c8dee2aaSAndroid Build Coastguard Worker // Test exotic (CSS) gradient color spaces in conjunction with tile modes. Rather than test
1218*c8dee2aaSAndroid Build Coastguard Worker // every combination, we pick one color space that has a sufficiently strange interpolated
1219*c8dee2aaSAndroid Build Coastguard Worker // representation (OKLCH) and just use that. We're mostly interested in making sure that things
1220*c8dee2aaSAndroid Build Coastguard Worker // like decal mode are implemented at the correct time in the pipeline, relative to hue
1221*c8dee2aaSAndroid Build Coastguard Worker // conversion, re-premultiplication, etc.
1222*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[] = {{20, 0}, {120, 0}};
1223*c8dee2aaSAndroid Build Coastguard Worker SkColor4f colors[] = {SkColors::kBlue, SkColors::kYellow};
1224*c8dee2aaSAndroid Build Coastguard Worker
1225*c8dee2aaSAndroid Build Coastguard Worker SkPaint p;
1226*c8dee2aaSAndroid Build Coastguard Worker SkGradientShader::Interpolation interpolation;
1227*c8dee2aaSAndroid Build Coastguard Worker interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kOKLCH;
1228*c8dee2aaSAndroid Build Coastguard Worker
1229*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(5, 5);
1230*c8dee2aaSAndroid Build Coastguard Worker
1231*c8dee2aaSAndroid Build Coastguard Worker for (int tm = 0; tm < kSkTileModeCount; ++tm) {
1232*c8dee2aaSAndroid Build Coastguard Worker p.setShader(SkGradientShader::MakeLinear(pts, colors, SkColorSpace::MakeSRGB(), nullptr, 2,
1233*c8dee2aaSAndroid Build Coastguard Worker static_cast<SkTileMode>(tm), interpolation,
1234*c8dee2aaSAndroid Build Coastguard Worker nullptr));
1235*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect({0, 0, 350, 20}, p);
1236*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, 25);
1237*c8dee2aaSAndroid Build Coastguard Worker }
1238*c8dee2aaSAndroid Build Coastguard Worker }
1239*c8dee2aaSAndroid Build Coastguard Worker
1240*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM_BG(gradients_color_space_many_stops, canvas, 500, 500, SK_ColorGRAY) {
1241*c8dee2aaSAndroid Build Coastguard Worker // Test exotic (CSS) gradient color spaces with many stops. Rather than test every combination,
1242*c8dee2aaSAndroid Build Coastguard Worker // we pick one color space that has a sufficiently strange interpolated representation (OKLCH)
1243*c8dee2aaSAndroid Build Coastguard Worker // and just use that. We're mostly interested in making sure that the texture fallback on GPU
1244*c8dee2aaSAndroid Build Coastguard Worker // works correctly.
1245*c8dee2aaSAndroid Build Coastguard Worker const SkPoint pts[] = { {50, 50}, {450, 465}};
1246*c8dee2aaSAndroid Build Coastguard Worker
1247*c8dee2aaSAndroid Build Coastguard Worker const unsigned kStopCount = 200;
1248*c8dee2aaSAndroid Build Coastguard Worker SkColor4f colors[kStopCount];
1249*c8dee2aaSAndroid Build Coastguard Worker for (unsigned i = 0; i < kStopCount; i++) {
1250*c8dee2aaSAndroid Build Coastguard Worker switch (i % 5) {
1251*c8dee2aaSAndroid Build Coastguard Worker case 0: colors[i] = SkColors::kRed; break;
1252*c8dee2aaSAndroid Build Coastguard Worker case 1: colors[i] = SkColors::kGreen; break;
1253*c8dee2aaSAndroid Build Coastguard Worker case 2: colors[i] = SkColors::kGreen; break;
1254*c8dee2aaSAndroid Build Coastguard Worker case 3: colors[i] = SkColors::kBlue; break;
1255*c8dee2aaSAndroid Build Coastguard Worker case 4: colors[i] = SkColors::kRed; break;
1256*c8dee2aaSAndroid Build Coastguard Worker }
1257*c8dee2aaSAndroid Build Coastguard Worker }
1258*c8dee2aaSAndroid Build Coastguard Worker
1259*c8dee2aaSAndroid Build Coastguard Worker SkPaint p;
1260*c8dee2aaSAndroid Build Coastguard Worker
1261*c8dee2aaSAndroid Build Coastguard Worker SkGradientShader::Interpolation interpolation;
1262*c8dee2aaSAndroid Build Coastguard Worker interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kOKLCH;
1263*c8dee2aaSAndroid Build Coastguard Worker p.setShader(SkGradientShader::MakeLinear(pts, colors, SkColorSpace::MakeSRGB(), nullptr,
1264*c8dee2aaSAndroid Build Coastguard Worker std::size(colors), SkTileMode::kClamp, interpolation,
1265*c8dee2aaSAndroid Build Coastguard Worker nullptr));
1266*c8dee2aaSAndroid Build Coastguard Worker
1267*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(SkRect::MakeXYWH(0, 0, 500, 500), p);
1268*c8dee2aaSAndroid Build Coastguard Worker }
1269*c8dee2aaSAndroid Build Coastguard Worker
draw_powerless_hue_gradients(SkCanvas * canvas,SkGradientShader::Interpolation::ColorSpace colorSpace)1270*c8dee2aaSAndroid Build Coastguard Worker static void draw_powerless_hue_gradients(SkCanvas* canvas,
1271*c8dee2aaSAndroid Build Coastguard Worker SkGradientShader::Interpolation::ColorSpace colorSpace) {
1272*c8dee2aaSAndroid Build Coastguard Worker ToolUtils::draw_checkerboard(canvas);
1273*c8dee2aaSAndroid Build Coastguard Worker
1274*c8dee2aaSAndroid Build Coastguard Worker auto nextRow = [=]() {
1275*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
1276*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, 25);
1277*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
1278*c8dee2aaSAndroid Build Coastguard Worker };
1279*c8dee2aaSAndroid Build Coastguard Worker
1280*c8dee2aaSAndroid Build Coastguard Worker auto gradient = [&](std::initializer_list<SkColor4f> colors,
1281*c8dee2aaSAndroid Build Coastguard Worker std::initializer_list<float> pos,
1282*c8dee2aaSAndroid Build Coastguard Worker bool inPremul = false) {
1283*c8dee2aaSAndroid Build Coastguard Worker using Interpolation = SkGradientShader::Interpolation;
1284*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(pos.size() == 0 || pos.size() == colors.size());
1285*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
1286*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[] = {{0, 0}, {200, 0}};
1287*c8dee2aaSAndroid Build Coastguard Worker Interpolation interpolation;
1288*c8dee2aaSAndroid Build Coastguard Worker interpolation.fColorSpace = colorSpace;
1289*c8dee2aaSAndroid Build Coastguard Worker interpolation.fInPremul = static_cast<Interpolation::InPremul>(inPremul);
1290*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(SkGradientShader::MakeLinear(pts,
1291*c8dee2aaSAndroid Build Coastguard Worker colors.begin(),
1292*c8dee2aaSAndroid Build Coastguard Worker SkColorSpace::MakeSRGB(),
1293*c8dee2aaSAndroid Build Coastguard Worker pos.size() == 0 ? nullptr : pos.begin(),
1294*c8dee2aaSAndroid Build Coastguard Worker colors.size(),
1295*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp,
1296*c8dee2aaSAndroid Build Coastguard Worker interpolation,
1297*c8dee2aaSAndroid Build Coastguard Worker nullptr));
1298*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect({0, 0, 200, 20}, paint);
1299*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(205, 0); // next column
1300*c8dee2aaSAndroid Build Coastguard Worker };
1301*c8dee2aaSAndroid Build Coastguard Worker
1302*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(5, 5);
1303*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
1304*c8dee2aaSAndroid Build Coastguard Worker
1305*c8dee2aaSAndroid Build Coastguard Worker // For each test case, the first gradient (first column) has an under-specified result due to a
1306*c8dee2aaSAndroid Build Coastguard Worker // powerless component after conversion to LCH. The second gradient (second column) "hints" the
1307*c8dee2aaSAndroid Build Coastguard Worker // correct result, by slightly tinting the otherwise powerless color.
1308*c8dee2aaSAndroid Build Coastguard Worker
1309*c8dee2aaSAndroid Build Coastguard Worker gradient({SkColors::kWhite, SkColors::kBlue}, {});
1310*c8dee2aaSAndroid Build Coastguard Worker gradient({{0.99f, 0.99f, 1.00f, 1.0f}, SkColors::kBlue}, {}); // white, with blue hue
1311*c8dee2aaSAndroid Build Coastguard Worker nextRow();
1312*c8dee2aaSAndroid Build Coastguard Worker
1313*c8dee2aaSAndroid Build Coastguard Worker gradient({SkColors::kBlack, SkColors::kBlue}, {});
1314*c8dee2aaSAndroid Build Coastguard Worker gradient({{0.00f, 0.00f, 0.01f, 1.0f}, SkColors::kBlue}, {}); // black, with blue hue
1315*c8dee2aaSAndroid Build Coastguard Worker nextRow();
1316*c8dee2aaSAndroid Build Coastguard Worker
1317*c8dee2aaSAndroid Build Coastguard Worker // Transparent cases are done in both premul and unpremul interpolation:
1318*c8dee2aaSAndroid Build Coastguard Worker
1319*c8dee2aaSAndroid Build Coastguard Worker gradient({SkColors::kTransparent, SkColors::kBlue}, {}, /*inPremul=*/false);
1320*c8dee2aaSAndroid Build Coastguard Worker gradient({{0.00f, 0.00f, 0.01f, 0.0f}, SkColors::kBlue}, {}, /*inPremul=*/false);
1321*c8dee2aaSAndroid Build Coastguard Worker nextRow();
1322*c8dee2aaSAndroid Build Coastguard Worker
1323*c8dee2aaSAndroid Build Coastguard Worker gradient({SkColors::kTransparent, SkColors::kBlue}, {}, /*inPremul=*/true);
1324*c8dee2aaSAndroid Build Coastguard Worker gradient({{0.00f, 0.00f, 0.01f, 0.0f}, SkColors::kBlue}, {}, /*inPremul=*/true);
1325*c8dee2aaSAndroid Build Coastguard Worker nextRow();
1326*c8dee2aaSAndroid Build Coastguard Worker
1327*c8dee2aaSAndroid Build Coastguard Worker gradient({{1.00f, 1.00f, 1.00f, 0.0f}, SkColors::kBlue}, {}, /*inPremul=*/false);
1328*c8dee2aaSAndroid Build Coastguard Worker gradient({{0.99f, 0.99f, 1.00f, 0.0f}, SkColors::kBlue}, {}, /*inPremul=*/false);
1329*c8dee2aaSAndroid Build Coastguard Worker nextRow();
1330*c8dee2aaSAndroid Build Coastguard Worker
1331*c8dee2aaSAndroid Build Coastguard Worker gradient({{1.00f, 1.00f, 1.00f, 0.0f}, SkColors::kBlue}, {}, /*inPremul=*/true);
1332*c8dee2aaSAndroid Build Coastguard Worker gradient({{0.99f, 0.99f, 1.00f, 0.0f}, SkColors::kBlue}, {}, /*inPremul=*/true);
1333*c8dee2aaSAndroid Build Coastguard Worker nextRow();
1334*c8dee2aaSAndroid Build Coastguard Worker
1335*c8dee2aaSAndroid Build Coastguard Worker // Now we test three-stop gradients, where the middle stop needs to be "split" to handle the
1336*c8dee2aaSAndroid Build Coastguard Worker // different hues on either side. Again, the second column explicitly injects those to produce
1337*c8dee2aaSAndroid Build Coastguard Worker // a reference result. See: https://github.com/w3c/csswg-drafts/issues/9295
1338*c8dee2aaSAndroid Build Coastguard Worker
1339*c8dee2aaSAndroid Build Coastguard Worker gradient({SkColors::kRed, SkColors::kWhite, SkColors::kBlue}, {});
1340*c8dee2aaSAndroid Build Coastguard Worker gradient({SkColors::kRed,
1341*c8dee2aaSAndroid Build Coastguard Worker {1.00f, 0.99f, 0.99f, 1.0f},
1342*c8dee2aaSAndroid Build Coastguard Worker {0.99f, 0.99f, 1.00f, 1.0f},
1343*c8dee2aaSAndroid Build Coastguard Worker SkColors::kBlue},
1344*c8dee2aaSAndroid Build Coastguard Worker {0.0f, 0.5f, 0.5f, 1.0f});
1345*c8dee2aaSAndroid Build Coastguard Worker nextRow();
1346*c8dee2aaSAndroid Build Coastguard Worker
1347*c8dee2aaSAndroid Build Coastguard Worker gradient({SkColors::kRed, SkColors::kBlack, SkColors::kBlue}, {});
1348*c8dee2aaSAndroid Build Coastguard Worker gradient({SkColors::kRed,
1349*c8dee2aaSAndroid Build Coastguard Worker {0.01f, 0.00f, 0.00f, 1.0f},
1350*c8dee2aaSAndroid Build Coastguard Worker {0.00f, 0.00f, 0.01f, 1.0f},
1351*c8dee2aaSAndroid Build Coastguard Worker SkColors::kBlue},
1352*c8dee2aaSAndroid Build Coastguard Worker {0.0f, 0.5f, 0.5f, 1.0f});
1353*c8dee2aaSAndroid Build Coastguard Worker nextRow();
1354*c8dee2aaSAndroid Build Coastguard Worker
1355*c8dee2aaSAndroid Build Coastguard Worker gradient({SkColors::kRed, SkColors::kTransparent, SkColors::kBlue}, {});
1356*c8dee2aaSAndroid Build Coastguard Worker gradient({SkColors::kRed,
1357*c8dee2aaSAndroid Build Coastguard Worker {0.01f, 0.00f, 0.00f, 0.0f},
1358*c8dee2aaSAndroid Build Coastguard Worker {0.00f, 0.00f, 0.01f, 0.0f},
1359*c8dee2aaSAndroid Build Coastguard Worker SkColors::kBlue},
1360*c8dee2aaSAndroid Build Coastguard Worker {0.0f, 0.5f, 0.5f, 1.0f});
1361*c8dee2aaSAndroid Build Coastguard Worker nextRow();
1362*c8dee2aaSAndroid Build Coastguard Worker
1363*c8dee2aaSAndroid Build Coastguard Worker // Now do a few black-white tests, to ensure that the hue propagation works correctly, even
1364*c8dee2aaSAndroid Build Coastguard Worker // when there isn't any hue in the adjacent stops.
1365*c8dee2aaSAndroid Build Coastguard Worker using HueMethod = SkGradientShader::Interpolation::HueMethod;
1366*c8dee2aaSAndroid Build Coastguard Worker auto blackWhiteGradient = [&](HueMethod hm) {
1367*c8dee2aaSAndroid Build Coastguard Worker using Interpolation = SkGradientShader::Interpolation;
1368*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
1369*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[] = {{0, 0}, {405, 0}};
1370*c8dee2aaSAndroid Build Coastguard Worker Interpolation interpolation;
1371*c8dee2aaSAndroid Build Coastguard Worker interpolation.fColorSpace = colorSpace;
1372*c8dee2aaSAndroid Build Coastguard Worker interpolation.fHueMethod = hm;
1373*c8dee2aaSAndroid Build Coastguard Worker const SkColor4f colors[] = {SkColors::kWhite, SkColors::kGray,
1374*c8dee2aaSAndroid Build Coastguard Worker SkColors::kWhite, SkColors::kDkGray,
1375*c8dee2aaSAndroid Build Coastguard Worker SkColors::kWhite, SkColors::kBlack};
1376*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(SkGradientShader::MakeLinear(pts,
1377*c8dee2aaSAndroid Build Coastguard Worker colors,
1378*c8dee2aaSAndroid Build Coastguard Worker SkColorSpace::MakeSRGB(),
1379*c8dee2aaSAndroid Build Coastguard Worker nullptr,
1380*c8dee2aaSAndroid Build Coastguard Worker std::size(colors),
1381*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp,
1382*c8dee2aaSAndroid Build Coastguard Worker interpolation,
1383*c8dee2aaSAndroid Build Coastguard Worker nullptr));
1384*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect({0, 0, 405, 20}, paint);
1385*c8dee2aaSAndroid Build Coastguard Worker nextRow();
1386*c8dee2aaSAndroid Build Coastguard Worker };
1387*c8dee2aaSAndroid Build Coastguard Worker
1388*c8dee2aaSAndroid Build Coastguard Worker blackWhiteGradient(HueMethod::kShorter);
1389*c8dee2aaSAndroid Build Coastguard Worker blackWhiteGradient(HueMethod::kIncreasing);
1390*c8dee2aaSAndroid Build Coastguard Worker blackWhiteGradient(HueMethod::kDecreasing);
1391*c8dee2aaSAndroid Build Coastguard Worker blackWhiteGradient(HueMethod::kLonger);
1392*c8dee2aaSAndroid Build Coastguard Worker }
1393*c8dee2aaSAndroid Build Coastguard Worker
1394*c8dee2aaSAndroid Build Coastguard Worker #define DEF_POWERLESS_HUE_GM(colorSpace) \
1395*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(gradients_powerless_hue_##colorSpace, canvas, 415, 330) { \
1396*c8dee2aaSAndroid Build Coastguard Worker draw_powerless_hue_gradients(canvas, \
1397*c8dee2aaSAndroid Build Coastguard Worker SkGradientShader::Interpolation::ColorSpace::k##colorSpace); \
1398*c8dee2aaSAndroid Build Coastguard Worker }
1399*c8dee2aaSAndroid Build Coastguard Worker
1400*c8dee2aaSAndroid Build Coastguard Worker DEF_POWERLESS_HUE_GM(LCH)
1401*c8dee2aaSAndroid Build Coastguard Worker DEF_POWERLESS_HUE_GM(OKLCH)
1402*c8dee2aaSAndroid Build Coastguard Worker DEF_POWERLESS_HUE_GM(HSL)
1403*c8dee2aaSAndroid Build Coastguard Worker DEF_POWERLESS_HUE_GM(HWB)
1404