xref: /aosp_15_r20/external/skia/tests/GradientTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkAlphaType.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkColorPriv.h"
13 #include "include/core/SkColorSpace.h"
14 #include "include/core/SkColorType.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkMatrix.h"
17 #include "include/core/SkPaint.h"
18 #include "include/core/SkPixmap.h"
19 #include "include/core/SkPoint.h"
20 #include "include/core/SkRect.h"
21 #include "include/core/SkRefCnt.h"
22 #include "include/core/SkScalar.h"
23 #include "include/core/SkShader.h"
24 #include "include/core/SkSize.h"
25 #include "include/core/SkSurface.h"
26 #include "include/core/SkSurfaceProps.h"
27 #include "include/core/SkTileMode.h"
28 #include "include/core/SkTypes.h"
29 #include "include/effects/SkGradientShader.h"
30 #include "include/gpu/GpuTypes.h"
31 #include "include/gpu/ganesh/GrDirectContext.h"
32 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
33 #include "include/gpu/ganesh/mock/GrMockTypes.h"
34 #include "include/private/base/SkTemplates.h"
35 #include "include/private/base/SkTo.h"
36 #include "include/private/gpu/ganesh/GrTypesPriv.h"
37 #include "src/base/SkTLazy.h"
38 #include "src/gpu/ganesh/GrColorInfo.h"
39 #include "src/gpu/ganesh/GrFPArgs.h"
40 #include "src/gpu/ganesh/GrFragmentProcessors.h"
41 #include "src/shaders/SkShaderBase.h"
42 #include "tests/CtsEnforcement.h"
43 #include "tests/Test.h"
44 
45 #include <cstdint>
46 #include <cstring>
47 #include <string>
48 
49 // #if defined(SK_GRAPHITE)
50 // #include "include/gpu/graphite/Context.h"
51 // #include "include/gpu/graphite/Surface.h"
52 // #endif
53 
54 struct GrContextOptions;
55 
56 using namespace skia_private;
57 
58 // https://code.google.com/p/chromium/issues/detail?id=448299
59 // Giant (inverse) matrix causes overflow when converting/computing using 32.32
60 // Before the fix, we would assert (and then crash).
test_big_grad(skiatest::Reporter * reporter)61 static void test_big_grad(skiatest::Reporter* reporter) {
62     const SkColor colors[] = { SK_ColorRED, SK_ColorBLUE };
63     const SkPoint pts[] = {{ 15, 14.7112684f }, { 0.709064007f, 12.6108112f }};
64     SkPaint paint;
65     paint.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp));
66 
67     SkBitmap bm;
68     bm.allocN32Pixels(2000, 1);
69     SkCanvas c(bm);
70 
71     const SkScalar affine[] = {
72         1.06608627e-06f, 4.26434525e-07f, 6.2855f, 2.6611f, 273.4393f, 244.0046f
73     };
74     SkMatrix matrix;
75     matrix.setAffine(affine);
76     c.concat(matrix);
77 
78     c.drawPaint(paint);
79 }
80 
81 struct GradRec {
82     int             fColorCount;
83     const SkColor*  fColors;
84     const SkScalar* fPos;
85     const SkPoint*  fPoint;   // 2
86     const SkScalar* fRadius; // 2
87     SkTileMode      fTileMode;
88 
gradCheckGradRec89     void gradCheck(skiatest::Reporter* reporter,
90                    const sk_sp<SkShader>& shader,
91                    SkShaderBase::GradientInfo* info,
92                    SkShaderBase::GradientType gt,
93                    const SkMatrix& localMatrix = SkMatrix::I()) const {
94         AutoTMalloc<SkColor> colorStorage(fColorCount);
95         AutoTMalloc<SkScalar> posStorage(fColorCount);
96 
97         info->fColorCount = fColorCount;
98         info->fColors = colorStorage;
99         info->fColorOffsets = posStorage.get();
100         SkMatrix shaderLocalMatrix;
101         REPORTER_ASSERT(reporter, as_SB(shader)->asGradient(info, &shaderLocalMatrix) == gt);
102         REPORTER_ASSERT(reporter, shaderLocalMatrix == localMatrix);
103 
104         REPORTER_ASSERT(reporter, info->fColorCount == fColorCount);
105         REPORTER_ASSERT(reporter,
106                         !memcmp(info->fColors, fColors, fColorCount * sizeof(SkColor)));
107         REPORTER_ASSERT(reporter,
108                         !memcmp(info->fColorOffsets, fPos, fColorCount * sizeof(SkScalar)));
109         REPORTER_ASSERT(reporter, fTileMode == (SkTileMode)info->fTileMode);
110     }
111 };
112 
113 
none_gradproc(skiatest::Reporter * reporter,const GradRec &,const GradRec &)114 static void none_gradproc(skiatest::Reporter* reporter, const GradRec&, const GradRec&) {
115     sk_sp<SkShader> s(SkShaders::Empty());
116     REPORTER_ASSERT(reporter, SkShaderBase::GradientType::kNone == as_SB(s)->asGradient());
117 }
118 
color_gradproc(skiatest::Reporter * reporter,const GradRec & rec,const GradRec &)119 static void color_gradproc(skiatest::Reporter* reporter, const GradRec& rec, const GradRec&) {
120     sk_sp<SkShader> s(SkShaders::Color(rec.fColors[0]));
121     REPORTER_ASSERT(reporter, SkShaderBase::GradientType::kNone == as_SB(s)->asGradient());
122 }
123 
linear_gradproc(skiatest::Reporter * reporter,const GradRec & buildRec,const GradRec & checkRec)124 static void linear_gradproc(skiatest::Reporter* reporter, const GradRec& buildRec,
125                             const GradRec& checkRec) {
126     sk_sp<SkShader> s(SkGradientShader::MakeLinear(buildRec.fPoint, buildRec.fColors, buildRec.fPos,
127                                                    buildRec.fColorCount, buildRec.fTileMode));
128 
129     SkShaderBase::GradientInfo info;
130     checkRec.gradCheck(reporter, s, &info, SkShaderBase::GradientType::kLinear);
131     REPORTER_ASSERT(reporter, !memcmp(info.fPoint, checkRec.fPoint, 2 * sizeof(SkPoint)));
132 }
133 
radial_gradproc(skiatest::Reporter * reporter,const GradRec & buildRec,const GradRec & checkRec)134 static void radial_gradproc(skiatest::Reporter* reporter, const GradRec& buildRec,
135                             const GradRec& checkRec) {
136     sk_sp<SkShader> s(SkGradientShader::MakeRadial(buildRec.fPoint[0], buildRec.fRadius[0],
137                                                    buildRec.fColors, buildRec.fPos,
138                                                    buildRec.fColorCount, buildRec.fTileMode));
139 
140     SkShaderBase::GradientInfo info;
141     checkRec.gradCheck(reporter, s, &info, SkShaderBase::GradientType::kRadial);
142     REPORTER_ASSERT(reporter, info.fPoint[0] == checkRec.fPoint[0]);
143     REPORTER_ASSERT(reporter, info.fRadius[0] == checkRec.fRadius[0]);
144 }
145 
sweep_gradproc(skiatest::Reporter * reporter,const GradRec & buildRec,const GradRec & checkRec)146 static void sweep_gradproc(skiatest::Reporter* reporter, const GradRec& buildRec,
147                            const GradRec& checkRec) {
148     sk_sp<SkShader> s(SkGradientShader::MakeSweep(buildRec.fPoint[0].fX, buildRec.fPoint[0].fY,
149                                                   buildRec.fColors, buildRec.fPos,
150                                                   buildRec.fColorCount));
151 
152     SkShaderBase::GradientInfo info;
153     checkRec.gradCheck(reporter, s, &info, SkShaderBase::GradientType::kSweep);
154     REPORTER_ASSERT(reporter, info.fPoint[0] == checkRec.fPoint[0]);
155 }
156 
conical_gradproc(skiatest::Reporter * reporter,const GradRec & buildRec,const GradRec & checkRec)157 static void conical_gradproc(skiatest::Reporter* reporter, const GradRec& buildRec,
158                              const GradRec& checkRec) {
159     sk_sp<SkShader> s(SkGradientShader::MakeTwoPointConical(buildRec.fPoint[0],
160                                                             buildRec.fRadius[0],
161                                                             buildRec.fPoint[1],
162                                                             buildRec.fRadius[1],
163                                                             buildRec.fColors,
164                                                             buildRec.fPos,
165                                                             buildRec.fColorCount,
166                                                             buildRec.fTileMode));
167 
168     SkShaderBase::GradientInfo info;
169     checkRec.gradCheck(reporter, s, &info, SkShaderBase::GradientType::kConical);
170     REPORTER_ASSERT(reporter, !memcmp(info.fPoint, checkRec.fPoint, 2 * sizeof(SkPoint)));
171     REPORTER_ASSERT(reporter, !memcmp(info.fRadius, checkRec.fRadius, 2 * sizeof(SkScalar)));
172 }
173 
linear_gradproc_matrix(skiatest::Reporter * reporter,const GradRec & buildRec,const GradRec & checkRec)174 static void linear_gradproc_matrix(skiatest::Reporter* reporter, const GradRec& buildRec,
175                                    const GradRec& checkRec) {
176     SkMatrix localMatrix = SkMatrix::RotateDeg(45, {100, 100});
177     sk_sp<SkShader> s(SkGradientShader::MakeLinear(buildRec.fPoint, buildRec.fColors, buildRec.fPos,
178                                                    buildRec.fColorCount, buildRec.fTileMode,
179                                                    /*flags=*/0,
180                                                    &localMatrix));
181 
182     SkShaderBase::GradientInfo info;
183     checkRec.gradCheck(reporter, s, &info, SkShaderBase::GradientType::kLinear, localMatrix);
184     REPORTER_ASSERT(reporter, !memcmp(info.fPoint, checkRec.fPoint, 2 * sizeof(SkPoint)));
185 
186     // Same but using a local matrix wrapper.
187     s = SkGradientShader::MakeLinear(buildRec.fPoint, buildRec.fColors, buildRec.fPos,
188                                      buildRec.fColorCount, buildRec.fTileMode);
189     s = s->makeWithLocalMatrix(localMatrix);
190     checkRec.gradCheck(reporter, s, &info, SkShaderBase::GradientType::kLinear, localMatrix);
191     REPORTER_ASSERT(reporter, !memcmp(info.fPoint, checkRec.fPoint, 2 * sizeof(SkPoint)));
192 }
193 
194 // Ensure that repeated color gradients behave like drawing a single color
TestConstantGradient(skiatest::Reporter *)195 static void TestConstantGradient(skiatest::Reporter*) {
196     const SkPoint pts[] = {
197         { 0, 0 },
198         { SkIntToScalar(10), 0 }
199     };
200     SkColor colors[] = { SK_ColorBLUE, SK_ColorBLUE };
201     const SkScalar pos[] = { 0, SK_Scalar1 };
202     SkPaint paint;
203     paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2, SkTileMode::kClamp));
204     SkBitmap outBitmap;
205     outBitmap.allocN32Pixels(10, 1);
206     SkCanvas canvas(outBitmap);
207     canvas.drawPaint(paint);
208     for (int i = 0; i < 10; i++) {
209         // The following is commented out because it currently fails
210         // Related bug: https://code.google.com/p/skia/issues/detail?id=1098
211 
212         // REPORTER_ASSERT(reporter, SK_ColorBLUE == outBitmap.getColor(i, 0));
213     }
214 }
215 
216 typedef void (*GradProc)(skiatest::Reporter* reporter, const GradRec&, const GradRec&);
217 
TestGradientShaders(skiatest::Reporter * reporter)218 static void TestGradientShaders(skiatest::Reporter* reporter) {
219     static const SkColor gColors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
220     static const SkScalar gPos[] = { 0, SK_ScalarHalf, SK_Scalar1 };
221     static const SkPoint gPts[] = {
222         { 0, 0 },
223         { SkIntToScalar(10), SkIntToScalar(20) }
224     };
225     static const SkScalar gRad[] = { SkIntToScalar(1), SkIntToScalar(2) };
226 
227     GradRec rec;
228     rec.fColorCount = std::size(gColors);
229     rec.fColors = gColors;
230     rec.fPos = gPos;
231     rec.fPoint = gPts;
232     rec.fRadius = gRad;
233     rec.fTileMode = SkTileMode::kClamp;
234 
235     static const GradProc gProcs[] = {
236         none_gradproc,
237         color_gradproc,
238         linear_gradproc,
239         linear_gradproc_matrix,
240         radial_gradproc,
241         sweep_gradproc,
242         conical_gradproc,
243     };
244 
245     for (size_t i = 0; i < std::size(gProcs); ++i) {
246         gProcs[i](reporter, rec, rec);
247     }
248 }
249 
test_nearly_vertical(skiatest::Reporter * reporter)250 static void test_nearly_vertical(skiatest::Reporter* reporter) {
251     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(200, 200)));
252 
253     const SkPoint pts[] = {{ 100, 50 }, { 100.0001f, 50000 }};
254     const SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
255     const SkScalar pos[] = { 0, 1 };
256     SkPaint paint;
257     paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2, SkTileMode::kClamp));
258 
259     surface->getCanvas()->drawPaint(paint);
260 }
261 
test_vertical(skiatest::Reporter * reporter)262 static void test_vertical(skiatest::Reporter* reporter) {
263     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(200, 200)));
264 
265     const SkPoint pts[] = {{ 100, 50 }, { 100, 50 }};
266     const SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
267     const SkScalar pos[] = { 0, 1 };
268     SkPaint paint;
269     paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2, SkTileMode::kClamp));
270 
271     surface->getCanvas()->drawPaint(paint);
272 }
273 
274 // A linear gradient interval can, due to numerical imprecision (likely in the divide)
275 // finish an interval with the final fx not landing outside of [p0...p1].
276 // The old code had an assert which this test triggered.
277 // We now explicitly clamp the resulting fx value.
test_linear_fuzz(skiatest::Reporter * reporter)278 static void test_linear_fuzz(skiatest::Reporter* reporter) {
279     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(1300, 630)));
280 
281     const SkPoint pts[] = {{ 179.5f, -179.5f }, { 1074.5f, 715.5f }};
282     const SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE };
283     const SkScalar pos[] = {0, 0.200000003f, 0.800000012f, 1 };
284 
285     SkPaint paint;
286     paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 4, SkTileMode::kClamp));
287 
288     SkRect r = {0, 83, 1254, 620};
289     surface->getCanvas()->drawRect(r, paint);
290 }
291 
292 // https://bugs.chromium.org/p/skia/issues/detail?id=5023
293 // We should still shade pixels for which the radius is exactly 0.
test_two_point_conical_zero_radius(skiatest::Reporter * reporter)294 static void test_two_point_conical_zero_radius(skiatest::Reporter* reporter) {
295     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(5, 5)));
296     surface->getCanvas()->clear(SK_ColorRED);
297 
298     const SkColor colors[] = { SK_ColorGREEN, SK_ColorBLUE };
299     SkPaint p;
300     p.setShader(SkGradientShader::MakeTwoPointConical(
301         SkPoint::Make(2.5f, 2.5f), 0,
302         SkPoint::Make(3.0f, 3.0f), 10,
303         colors, nullptr, std::size(colors), SkTileMode::kClamp));
304     surface->getCanvas()->drawPaint(p);
305 
306     // r == 0 for the center pixel.
307     // verify that we draw it (no red bleed)
308     SkPMColor centerPMColor;
309     surface->readPixels(SkImageInfo::MakeN32Premul(1, 1), &centerPMColor, sizeof(SkPMColor), 2, 2);
310     REPORTER_ASSERT(reporter, SkGetPackedR32(centerPMColor) == 0);
311 }
312 
313 // http://crbug.com/599458
test_clamping_overflow(skiatest::Reporter *)314 static void test_clamping_overflow(skiatest::Reporter*) {
315     SkPaint p;
316     const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN };
317     const SkPoint pts1[] = { SkPoint::Make(1001, 1000001), SkPoint::Make(1000.99f, 1000000) };
318 
319     p.setShader(SkGradientShader::MakeLinear(pts1, colors, nullptr, 2, SkTileMode::kClamp));
320 
321     sk_sp<SkSurface> surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(50, 50)));
322     surface->getCanvas()->scale(100, 100);
323     surface->getCanvas()->drawPaint(p);
324 
325     const SkPoint pts2[] = { SkPoint::Make(10000.99f, 1000000), SkPoint::Make(10001, 1000001) };
326     p.setShader(SkGradientShader::MakeLinear(pts2, colors, nullptr, 2, SkTileMode::kClamp));
327     surface->getCanvas()->drawPaint(p);
328 
329     // Passes if we don't trigger asserts.
330 }
331 
332 // http://crbug.com/636194
test_degenerate_linear(skiatest::Reporter *)333 static void test_degenerate_linear(skiatest::Reporter*) {
334     SkPaint p;
335     const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN };
336     const SkPoint pts[] = {
337         SkPoint::Make(-46058024627067344430605278824628224.0f, 0),
338         SkPoint::Make(SK_ScalarMax, 0)
339     };
340 
341     p.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp));
342     sk_sp<SkSurface> surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(50, 50)));
343     surface->getCanvas()->drawPaint(p);
344 
345     // Passes if we don't trigger asserts.
346 }
347 
348 // http://crbug.com/1149216
test_unsorted_degenerate(skiatest::Reporter * r)349 static void test_unsorted_degenerate(skiatest::Reporter* r) {
350     // Passes if a valid solid color is computed for the degenerate gradient
351     // (unsorted positions are fixed during regular gradient construction, so this ensures the
352     // same fixing happens for degenerate gradients as well). If they aren't fixed, this test
353     // case produces a negative alpha, which asserts during SkPMColor4f::isOpaque().
354     const SkColor4f colors[] = { {0.f, 0.f, 0.f, 0.f},
355                                  {0.00784314f, 0.f, 0.f, 0.0627451f},
356                                  {0.f, 0.00392157f, 0.f, 0.f} };
357     const SkScalar positions[] = {0.00753367f, 8.54792e-44f, 1.46955e-39f};
358 
359     const SkPoint points[] { { 0.f, 0.f }, { 1e-20f, -1e-8f }}; // must be degenerate
360     // Use kMirror to go through average color stop calculation, vs. kClamp which would pick a color
361     sk_sp<SkShader> gradient = SkGradientShader::MakeLinear(points, colors, nullptr, positions, 3,
362                                                             SkTileMode::kMirror);
363 
364     // The degenerate gradient shouldn't be null
365     REPORTER_ASSERT(r, SkToBool(gradient));
366     // And it shouldn't crash when creating a fragment processor
367 
368     GrColorInfo dstColorInfo(GrColorType::kRGBA_8888, kPremul_SkAlphaType,
369                              SkColorSpace::MakeSRGB());
370     SkSurfaceProps props;
371     GrMockOptions options;
372     auto context = GrDirectContext::MakeMock(&options);
373 
374     GrFPArgs args(context.get(), &dstColorInfo, props, GrFPArgs::Scope::kDefault);
375     GrFragmentProcessors::Make(gradient.get(), args, SkMatrix::I());
376 }
377 
378 // "Interesting" fuzzer values.
test_linear_fuzzer(skiatest::Reporter *)379 static void test_linear_fuzzer(skiatest::Reporter*) {
380     static const SkColor gColors0[] = { 0x30303030, 0x30303030 };
381     static const SkColor gColors1[] = { 0x30303030, 0x30303030, 0x30303030 };
382 
383     static const SkScalar gPos1[]   = { 0, 0, 1 };
384 
385     static const SkScalar gMatrix0[9] = {
386         6.40969056e-10f, 0              , 6.40969056e-10f,
387         0              , 4.42539023e-39f, 6.40969056e-10f,
388         0              , 0              , 1
389     };
390     static const SkScalar gMatrix1[9] = {
391         -2.75294113f    , 6.40969056e-10f,  6.40969056e-10f,
392          6.40969056e-10f, 6.40969056e-10f, -3.32810161e+24f,
393          6.40969056e-10f, 6.40969056e-10f,  0
394     };
395     static const SkScalar gMatrix2[9] = {
396         7.93481258e+17f, 6.40969056e-10f, 6.40969056e-10f,
397         6.40969056e-10f, 6.40969056e-10f, 6.40969056e-10f,
398         6.40969056e-10f, 6.40969056e-10f, 0.688235283f
399     };
400     static const SkScalar gMatrix3[9] = {
401         1.89180674e+11f,     6.40969056e-10f, 6.40969056e-10f,
402         6.40969056e-10f,     6.40969056e-10f, 6.40969056e-10f,
403         6.40969056e-10f, 11276.0469f        , 8.12524808e+20f
404     };
405 
406     static const struct {
407         SkPoint            fPts[2];
408         const SkColor*     fColors;
409         const SkScalar*    fPos;
410         int                fCount;
411         SkTileMode         fTileMode;
412         uint32_t           fFlags;
413         const SkScalar*    fLocalMatrix;
414         const SkScalar*    fGlobalMatrix;
415     } gConfigs[] = {
416         {
417             {{0, -2.752941f}, {0, 0}},
418             gColors0,
419             nullptr,
420             std::size(gColors0),
421             SkTileMode::kClamp,
422             0,
423             gMatrix0,
424             nullptr
425         },
426         {
427             {{4.42539023e-39f, -4.42539023e-39f}, {9.78041162e-15f, 4.42539023e-39f}},
428             gColors1,
429             gPos1,
430             std::size(gColors1),
431             SkTileMode::kClamp,
432             0,
433             nullptr,
434             gMatrix1
435         },
436         {
437             {{4.42539023e-39f, 6.40969056e-10f}, {6.40969056e-10f, 1.49237238e-19f}},
438             gColors1,
439             gPos1,
440             std::size(gColors1),
441             SkTileMode::kClamp,
442             0,
443             nullptr,
444             gMatrix2
445         },
446         {
447             {{6.40969056e-10f, 6.40969056e-10f}, {6.40969056e-10f, -0.688235283f}},
448             gColors0,
449             nullptr,
450             std::size(gColors0),
451             SkTileMode::kClamp,
452             0,
453             gMatrix3,
454             nullptr
455         },
456     };
457 
458     sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB();
459     SkColorSpace* colorSpaces[] = {
460         nullptr,     // hits the legacy gradient impl
461         srgb.get(),  // triggers 4f/raster-pipeline
462     };
463 
464     SkPaint paint;
465 
466     for (const SkColorSpace* colorSpace : colorSpaces) {
467         sk_sp<SkSurface> surface = SkSurfaces::Raster(SkImageInfo::Make(
468                 100, 100, kN32_SkColorType, kPremul_SkAlphaType, sk_ref_sp(colorSpace)));
469         SkCanvas* canvas = surface->getCanvas();
470 
471         for (const auto& config : gConfigs) {
472             SkAutoCanvasRestore acr(canvas, false);
473             SkTLazy<SkMatrix> localMatrix;
474             if (config.fLocalMatrix) {
475                 localMatrix.init();
476                 localMatrix->set9(config.fLocalMatrix);
477             }
478 
479             paint.setShader(SkGradientShader::MakeLinear(config.fPts,
480                                                          config.fColors,
481                                                          config.fPos,
482                                                          config.fCount,
483                                                          config.fTileMode,
484                                                          config.fFlags,
485                                                          localMatrix.getMaybeNull()));
486             if (config.fGlobalMatrix) {
487                 SkMatrix m;
488                 m.set9(config.fGlobalMatrix);
489                 canvas->save();
490                 canvas->concat(m);
491             }
492 
493             canvas->drawPaint(paint);
494         }
495     }
496 }
497 
test_sweep_fuzzer(skiatest::Reporter *)498 static void test_sweep_fuzzer(skiatest::Reporter*) {
499     static const SkColor gColors0[] = { 0x30303030, 0x30303030, 0x30303030 };
500     static const SkScalar   gPos0[] = { -47919293023455565225163489280.0f, 0, 1 };
501     static const SkScalar gMatrix0[9] = {
502         1.12116716e-13f,  0              ,  8.50489682e+16f,
503         4.1917041e-41f ,  3.51369881e-23f, -2.54344271e-26f,
504         9.61111907e+17f, -3.35263808e-29f, -1.35659403e+14f
505     };
506     static const struct {
507         SkPoint            fCenter;
508         const SkColor*     fColors;
509         const SkScalar*    fPos;
510         int                fCount;
511         const SkScalar*    fGlobalMatrix;
512     } gConfigs[] = {
513         {
514             { 0, 0 },
515             gColors0,
516             gPos0,
517             std::size(gColors0),
518             gMatrix0
519         },
520     };
521 
522     sk_sp<SkSurface> surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100));
523     SkCanvas* canvas = surface->getCanvas();
524     SkPaint paint;
525 
526     for (const auto& config : gConfigs) {
527         paint.setShader(SkGradientShader::MakeSweep(config.fCenter.x(),
528                                                     config.fCenter.y(),
529                                                     config.fColors,
530                                                     config.fPos,
531                                                     config.fCount));
532 
533         SkAutoCanvasRestore acr(canvas, false);
534         if (config.fGlobalMatrix) {
535             SkMatrix m;
536             m.set9(config.fGlobalMatrix);
537             canvas->save();
538             canvas->concat(m);
539         }
540         canvas->drawPaint(paint);
541     }
542 }
543 
544 // Draw a sweep gradient in a translated canvas such that the colors in the center pixels of the
545 // gradient will be evaluated at x = 0. The gradient implementation must not call atan2(y, x) with
546 // x == 0, as this will result in undefined behavior and likely incorrect results.
547 // https://crbug.com/1468916
test_sweep_gradient_zero_x(skiatest::Reporter * reporter,SkSurface * surface)548 void test_sweep_gradient_zero_x(skiatest::Reporter* reporter, SkSurface* surface) {
549     // The gradient drawn has yellow for the first half and blue for the second half, using hard
550     // stops and running clockwise from (1, 0), so we should draw a rectangle with a blue top-half
551     // and yellow bottom-half.
552     constexpr float pts[4] = {0.0f, 0.5f, 0.5f, 1.0f};
553     constexpr SkColor colors[4] = {SK_ColorYELLOW, SK_ColorYELLOW, SK_ColorBLUE, SK_ColorBLUE};
554     SkCanvas* canvas = surface->getCanvas();
555     canvas->save();
556     canvas->translate(2.5f, 2.5f);
557     SkPaint paint;
558     paint.setShader(SkGradientShader::MakeSweep(0.0f, 0.0f, colors, pts, 4));
559     canvas->drawRect(SkRect::MakeXYWH(-2.5f, -2.5f, 5.0f, 5.0f), paint);
560     canvas->restore();
561 
562     // Read pixels.
563     SkBitmap bitmap;
564     SkPixmap pixmap;
565     bitmap.allocPixels(surface->imageInfo());
566     SkAssertResult(bitmap.peekPixels(&pixmap));
567     if (!surface->readPixels(pixmap, 0, 0)) {
568         ERRORF(reporter, "readPixels failed");
569         return;
570     }
571 
572     // Check the results.
573     SkColor4f topColor = pixmap.getColor4f(2, 0);
574     SkColor4f bottomColor = pixmap.getColor4f(2, 4);
575     REPORTER_ASSERT(reporter, topColor == SkColors::kBlue);
576     REPORTER_ASSERT(reporter, bottomColor == SkColors::kYellow);
577 }
578 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(TestSweepGradientZeroXGanesh,reporter,contextInfo,CtsEnforcement::kApiLevel_V)579 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(TestSweepGradientZeroXGanesh,
580                                        reporter,
581                                        contextInfo,
582                                        CtsEnforcement::kApiLevel_V) {
583     SkImageInfo ii = SkImageInfo::Make(SkISize::Make(5, 5),
584                                        SkColorType::kRGBA_8888_SkColorType,
585                                        SkAlphaType::kPremul_SkAlphaType);
586     GrDirectContext* context = contextInfo.directContext();
587     sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(context, skgpu::Budgeted::kYes, ii);
588     test_sweep_gradient_zero_x(reporter, surface.get());
589 }
590 
591 // TODO: Fix this bug in Graphite as well.
592 // #if defined(SK_GRAPHITE)
593 // DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(TestSweepGradientZeroXGraphite, reporter, context,
594 //                                          CtsEnforcement::kNextRelease) {
595 //     using namespace skgpu::graphite;
596 //     SkImageInfo ii = SkImageInfo::Make(SkISize::Make(5, 5),
597 //                                        SkColorType::kRGBA_8888_SkColorType,
598 //                                        SkAlphaType::kPremul_SkAlphaType);
599 //     std::unique_ptr<Recorder> recorder = context->makeRecorder();
600 //     sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(recorder.get(), ii);
601 //     test_sweep_gradient_zero_x(reporter, surface.get());
602 // }
603 // #endif
604 
DEF_TEST(Gradient,reporter)605 DEF_TEST(Gradient, reporter) {
606     TestGradientShaders(reporter);
607     TestConstantGradient(reporter);
608     test_big_grad(reporter);
609     test_nearly_vertical(reporter);
610     test_vertical(reporter);
611     test_linear_fuzz(reporter);
612     test_two_point_conical_zero_radius(reporter);
613     test_clamping_overflow(reporter);
614     test_degenerate_linear(reporter);
615     test_linear_fuzzer(reporter);
616     test_sweep_fuzzer(reporter);
617     test_unsorted_degenerate(reporter);
618 }
619