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