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