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