blob: 9595ffacda869fc0c7e1b627fe3c4622608b2bd7 [file] [log] [blame]
reed@google.com83226972012-06-07 20:26:47 +00001/*
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 */
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +00007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkCanvas.h"
9#include "include/core/SkColorPriv.h"
10#include "include/core/SkShader.h"
11#include "include/core/SkSurface.h"
12#include "include/effects/SkGradientShader.h"
13#include "include/private/SkTemplates.h"
Michael Ludwigad5ec1a2020-11-19 14:15:05 -050014#include "src/core/SkMatrixProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/core/SkTLazy.h"
16#include "src/shaders/SkColorShader.h"
17#include "tests/Test.h"
reed@google.com83226972012-06-07 20:26:47 +000018
reed9d91eb32015-01-28 11:44:48 -080019// https://code.google.com/p/chromium/issues/detail?id=448299
20// Giant (inverse) matrix causes overflow when converting/computing using 32.32
21// Before the fix, we would assert (and then crash).
22static void test_big_grad(skiatest::Reporter* reporter) {
23 const SkColor colors[] = { SK_ColorRED, SK_ColorBLUE };
24 const SkPoint pts[] = {{ 15, 14.7112684f }, { 0.709064007f, 12.6108112f }};
reed9d91eb32015-01-28 11:44:48 -080025 SkPaint paint;
Mike Reedfae8fce2019-04-03 10:27:45 -040026 paint.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp));
reed9d91eb32015-01-28 11:44:48 -080027
28 SkBitmap bm;
29 bm.allocN32Pixels(2000, 1);
30 SkCanvas c(bm);
31
32 const SkScalar affine[] = {
33 1.06608627e-06f, 4.26434525e-07f, 6.2855f, 2.6611f, 273.4393f, 244.0046f
34 };
35 SkMatrix matrix;
36 matrix.setAffine(affine);
37 c.concat(matrix);
halcanary9d524f22016-03-29 09:03:52 -070038
reed9d91eb32015-01-28 11:44:48 -080039 c.drawPaint(paint);
40}
41
reed@google.com83226972012-06-07 20:26:47 +000042struct GradRec {
43 int fColorCount;
44 const SkColor* fColors;
45 const SkScalar* fPos;
46 const SkPoint* fPoint; // 2
47 const SkScalar* fRadius; // 2
Mike Reedfae8fce2019-04-03 10:27:45 -040048 SkTileMode fTileMode;
reed@google.com83226972012-06-07 20:26:47 +000049
reed1a9b9642016-03-13 14:13:58 -070050 void gradCheck(skiatest::Reporter* reporter, const sk_sp<SkShader>& shader,
reed@google.com83226972012-06-07 20:26:47 +000051 SkShader::GradientInfo* info,
52 SkShader::GradientType gt) const {
53 SkAutoTMalloc<SkColor> colorStorage(fColorCount);
54 SkAutoTMalloc<SkScalar> posStorage(fColorCount);
55
56 info->fColorCount = fColorCount;
57 info->fColors = colorStorage;
58 info->fColorOffsets = posStorage.get();
59 REPORTER_ASSERT(reporter, shader->asAGradient(info) == gt);
60
61 REPORTER_ASSERT(reporter, info->fColorCount == fColorCount);
62 REPORTER_ASSERT(reporter,
63 !memcmp(info->fColors, fColors, fColorCount * sizeof(SkColor)));
64 REPORTER_ASSERT(reporter,
65 !memcmp(info->fColorOffsets, fPos, fColorCount * sizeof(SkScalar)));
Mike Reedfae8fce2019-04-03 10:27:45 -040066 REPORTER_ASSERT(reporter, fTileMode == (SkTileMode)info->fTileMode);
reed@google.com83226972012-06-07 20:26:47 +000067 }
68};
69
70
fmalita51229672016-08-22 06:22:28 -070071static void none_gradproc(skiatest::Reporter* reporter, const GradRec&, const GradRec&) {
Mike Reedc8bea7d2019-04-09 13:55:36 -040072 sk_sp<SkShader> s(SkShaders::Empty());
halcanary96fcdcc2015-08-27 07:41:13 -070073 REPORTER_ASSERT(reporter, SkShader::kNone_GradientType == s->asAGradient(nullptr));
reed@google.com83226972012-06-07 20:26:47 +000074}
75
fmalita51229672016-08-22 06:22:28 -070076static void color_gradproc(skiatest::Reporter* reporter, const GradRec& rec, const GradRec&) {
Hal Canary342b7ac2016-11-04 11:49:42 -040077 sk_sp<SkShader> s(new SkColorShader(rec.fColors[0]));
halcanary96fcdcc2015-08-27 07:41:13 -070078 REPORTER_ASSERT(reporter, SkShader::kColor_GradientType == s->asAGradient(nullptr));
reed@google.com83226972012-06-07 20:26:47 +000079
80 SkShader::GradientInfo info;
halcanary96fcdcc2015-08-27 07:41:13 -070081 info.fColors = nullptr;
reed@google.com83226972012-06-07 20:26:47 +000082 info.fColorCount = 0;
83 s->asAGradient(&info);
84 REPORTER_ASSERT(reporter, 1 == info.fColorCount);
85}
86
fmalita51229672016-08-22 06:22:28 -070087static void linear_gradproc(skiatest::Reporter* reporter, const GradRec& buildRec,
88 const GradRec& checkRec) {
89 sk_sp<SkShader> s(SkGradientShader::MakeLinear(buildRec.fPoint, buildRec.fColors, buildRec.fPos,
90 buildRec.fColorCount, buildRec.fTileMode));
rmistry@google.comd6176b02012-08-23 18:14:13 +000091
reed@google.com83226972012-06-07 20:26:47 +000092 SkShader::GradientInfo info;
fmalita51229672016-08-22 06:22:28 -070093 checkRec.gradCheck(reporter, s, &info, SkShader::kLinear_GradientType);
94 REPORTER_ASSERT(reporter, !memcmp(info.fPoint, checkRec.fPoint, 2 * sizeof(SkPoint)));
reed@google.com83226972012-06-07 20:26:47 +000095}
96
fmalita51229672016-08-22 06:22:28 -070097static void radial_gradproc(skiatest::Reporter* reporter, const GradRec& buildRec,
98 const GradRec& checkRec) {
99 sk_sp<SkShader> s(SkGradientShader::MakeRadial(buildRec.fPoint[0], buildRec.fRadius[0],
100 buildRec.fColors, buildRec.fPos,
101 buildRec.fColorCount, buildRec.fTileMode));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000102
reed@google.com83226972012-06-07 20:26:47 +0000103 SkShader::GradientInfo info;
fmalita51229672016-08-22 06:22:28 -0700104 checkRec.gradCheck(reporter, s, &info, SkShader::kRadial_GradientType);
105 REPORTER_ASSERT(reporter, info.fPoint[0] == checkRec.fPoint[0]);
106 REPORTER_ASSERT(reporter, info.fRadius[0] == checkRec.fRadius[0]);
reed@google.com83226972012-06-07 20:26:47 +0000107}
108
fmalita51229672016-08-22 06:22:28 -0700109static void sweep_gradproc(skiatest::Reporter* reporter, const GradRec& buildRec,
110 const GradRec& checkRec) {
111 sk_sp<SkShader> s(SkGradientShader::MakeSweep(buildRec.fPoint[0].fX, buildRec.fPoint[0].fY,
112 buildRec.fColors, buildRec.fPos,
113 buildRec.fColorCount));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000114
reed@google.com83226972012-06-07 20:26:47 +0000115 SkShader::GradientInfo info;
fmalita51229672016-08-22 06:22:28 -0700116 checkRec.gradCheck(reporter, s, &info, SkShader::kSweep_GradientType);
117 REPORTER_ASSERT(reporter, info.fPoint[0] == checkRec.fPoint[0]);
reed@google.com83226972012-06-07 20:26:47 +0000118}
119
fmalita51229672016-08-22 06:22:28 -0700120static void conical_gradproc(skiatest::Reporter* reporter, const GradRec& buildRec,
121 const GradRec& checkRec) {
122 sk_sp<SkShader> s(SkGradientShader::MakeTwoPointConical(buildRec.fPoint[0],
123 buildRec.fRadius[0],
124 buildRec.fPoint[1],
125 buildRec.fRadius[1],
126 buildRec.fColors,
127 buildRec.fPos,
128 buildRec.fColorCount,
129 buildRec.fTileMode));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000130
reed@google.com83226972012-06-07 20:26:47 +0000131 SkShader::GradientInfo info;
fmalita51229672016-08-22 06:22:28 -0700132 checkRec.gradCheck(reporter, s, &info, SkShader::kConical_GradientType);
133 REPORTER_ASSERT(reporter, !memcmp(info.fPoint, checkRec.fPoint, 2 * sizeof(SkPoint)));
134 REPORTER_ASSERT(reporter, !memcmp(info.fRadius, checkRec.fRadius, 2 * sizeof(SkScalar)));
reed@google.com83226972012-06-07 20:26:47 +0000135}
136
junov@chromium.orge94b5e42013-01-30 15:52:06 +0000137// Ensure that repeated color gradients behave like drawing a single color
sugoi@google.come0e385c2013-03-11 18:50:03 +0000138static void TestConstantGradient(skiatest::Reporter*) {
junov@chromium.orge94b5e42013-01-30 15:52:06 +0000139 const SkPoint pts[] = {
140 { 0, 0 },
141 { SkIntToScalar(10), 0 }
142 };
143 SkColor colors[] = { SK_ColorBLUE, SK_ColorBLUE };
144 const SkScalar pos[] = { 0, SK_Scalar1 };
reed1a9b9642016-03-13 14:13:58 -0700145 SkPaint paint;
Mike Reedfae8fce2019-04-03 10:27:45 -0400146 paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2, SkTileMode::kClamp));
junov@chromium.orge94b5e42013-01-30 15:52:06 +0000147 SkBitmap outBitmap;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000148 outBitmap.allocN32Pixels(10, 1);
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000149 SkCanvas canvas(outBitmap);
junov@chromium.orge94b5e42013-01-30 15:52:06 +0000150 canvas.drawPaint(paint);
junov@chromium.orge94b5e42013-01-30 15:52:06 +0000151 for (int i = 0; i < 10; i++) {
152 // The following is commented out because it currently fails
153 // Related bug: https://code.google.com/p/skia/issues/detail?id=1098
154
155 // REPORTER_ASSERT(reporter, SK_ColorBLUE == outBitmap.getColor(i, 0));
156 }
157}
158
fmalita51229672016-08-22 06:22:28 -0700159typedef void (*GradProc)(skiatest::Reporter* reporter, const GradRec&, const GradRec&);
reed@google.com83226972012-06-07 20:26:47 +0000160
junov@chromium.orge94b5e42013-01-30 15:52:06 +0000161static void TestGradientShaders(skiatest::Reporter* reporter) {
reed@google.com83226972012-06-07 20:26:47 +0000162 static const SkColor gColors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
163 static const SkScalar gPos[] = { 0, SK_ScalarHalf, SK_Scalar1 };
164 static const SkPoint gPts[] = {
165 { 0, 0 },
166 { SkIntToScalar(10), SkIntToScalar(20) }
167 };
168 static const SkScalar gRad[] = { SkIntToScalar(1), SkIntToScalar(2) };
169
170 GradRec rec;
171 rec.fColorCount = SK_ARRAY_COUNT(gColors);
172 rec.fColors = gColors;
173 rec.fPos = gPos;
174 rec.fPoint = gPts;
175 rec.fRadius = gRad;
Mike Reedfae8fce2019-04-03 10:27:45 -0400176 rec.fTileMode = SkTileMode::kClamp;
reed@google.com83226972012-06-07 20:26:47 +0000177
178 static const GradProc gProcs[] = {
179 none_gradproc,
180 color_gradproc,
181 linear_gradproc,
182 radial_gradproc,
reed@google.com83226972012-06-07 20:26:47 +0000183 sweep_gradproc,
184 conical_gradproc,
185 };
rmistry@google.comd6176b02012-08-23 18:14:13 +0000186
reed@google.com83226972012-06-07 20:26:47 +0000187 for (size_t i = 0; i < SK_ARRAY_COUNT(gProcs); ++i) {
fmalita51229672016-08-22 06:22:28 -0700188 gProcs[i](reporter, rec, rec);
189 }
190}
191
192static void TestGradientOptimization(skiatest::Reporter* reporter) {
193 static const struct {
194 GradProc fProc;
195 bool fIsClampRestricted;
196 } gProcInfo[] = {
197 { linear_gradproc , false },
198 { radial_gradproc , false },
199 { sweep_gradproc , true }, // sweep is funky in that it always pretends to be kClamp.
200 { conical_gradproc, false },
201 };
202
203 static const SkColor gC_00[] = { 0xff000000, 0xff000000 };
204 static const SkColor gC_01[] = { 0xff000000, 0xffffffff };
205 static const SkColor gC_11[] = { 0xffffffff, 0xffffffff };
206 static const SkColor gC_001[] = { 0xff000000, 0xff000000, 0xffffffff };
207 static const SkColor gC_011[] = { 0xff000000, 0xffffffff, 0xffffffff };
208 static const SkColor gC_0011[] = { 0xff000000, 0xff000000, 0xffffffff, 0xffffffff };
209
210 static const SkScalar gP_01[] = { 0, 1 };
211 static const SkScalar gP_001[] = { 0, 0, 1 };
212 static const SkScalar gP_011[] = { 0, 1, 1 };
213 static const SkScalar gP_0x1[] = { 0, .5f, 1 };
214 static const SkScalar gP_0011[] = { 0, 0, 1, 1 };
215
216 static const SkPoint gPts[] = { {0, 0}, {1, 1} };
217 static const SkScalar gRadii[] = { 1, 2 };
218
219 static const struct {
220 const SkColor* fCol;
221 const SkScalar* fPos;
222 int fCount;
223
224 const SkColor* fExpectedCol;
225 const SkScalar* fExpectedPos;
226 int fExpectedCount;
227 bool fRequiresNonClamp;
228 } gTests[] = {
229 { gC_001, gP_001, 3, gC_01, gP_01, 2, false },
230 { gC_001, gP_011, 3, gC_00, gP_01, 2, true },
231 { gC_001, gP_0x1, 3, gC_001, gP_0x1, 3, false },
232 { gC_001, nullptr, 3, gC_001, gP_0x1, 3, false },
233
234 { gC_011, gP_001, 3, gC_11, gP_01, 2, true },
235 { gC_011, gP_011, 3, gC_01, gP_01, 2, false },
236 { gC_011, gP_0x1, 3, gC_011, gP_0x1, 3, false },
237 { gC_011, nullptr, 3, gC_011, gP_0x1, 3, false },
238
239 { gC_0011, gP_0011, 4, gC_0011, gP_0011, 4, false },
240 };
241
Mike Reedfae8fce2019-04-03 10:27:45 -0400242 const SkTileMode modes[] = {
243 SkTileMode::kClamp, SkTileMode::kRepeat, SkTileMode::kMirror,
Mike Reeddfc0e912018-02-16 12:40:18 -0500244 // TODO: add kDecal_TileMode when it is implemented
245 };
fmalita51229672016-08-22 06:22:28 -0700246 for (size_t i = 0; i < SK_ARRAY_COUNT(gProcInfo); ++i) {
Mike Reeddfc0e912018-02-16 12:40:18 -0500247 for (auto mode : modes) {
Mike Reedfae8fce2019-04-03 10:27:45 -0400248 if (gProcInfo[i].fIsClampRestricted && mode != SkTileMode::kClamp) {
fmalita51229672016-08-22 06:22:28 -0700249 continue;
250 }
251
252 for (size_t t = 0; t < SK_ARRAY_COUNT(gTests); ++t) {
253 GradRec rec;
254 rec.fColorCount = gTests[t].fCount;
255 rec.fColors = gTests[t].fCol;
256 rec.fPos = gTests[t].fPos;
Mike Reedfae8fce2019-04-03 10:27:45 -0400257 rec.fTileMode = mode;
fmalita51229672016-08-22 06:22:28 -0700258 rec.fPoint = gPts;
259 rec.fRadius = gRadii;
260
261 GradRec expected = rec;
Mike Reedfae8fce2019-04-03 10:27:45 -0400262 if (!gTests[t].fRequiresNonClamp || mode != SkTileMode::kClamp) {
fmalita51229672016-08-22 06:22:28 -0700263 expected.fColorCount = gTests[t].fExpectedCount;
264 expected.fColors = gTests[t].fExpectedCol;
265 expected.fPos = gTests[t].fExpectedPos;
266 }
267
268 gProcInfo[i].fProc(reporter, rec, expected);
269 }
270 }
reed@google.com83226972012-06-07 20:26:47 +0000271 }
272}
273
fmalita8d381022015-11-19 10:35:34 -0800274static void test_nearly_vertical(skiatest::Reporter* reporter) {
reede8f30622016-03-23 18:59:25 -0700275 auto surface(SkSurface::MakeRasterN32Premul(200, 200));
fmalita8d381022015-11-19 10:35:34 -0800276
277 const SkPoint pts[] = {{ 100, 50 }, { 100.0001f, 50000 }};
278 const SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
279 const SkScalar pos[] = { 0, 1 };
fmalita8d381022015-11-19 10:35:34 -0800280 SkPaint paint;
Mike Reedfae8fce2019-04-03 10:27:45 -0400281 paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2, SkTileMode::kClamp));
fmalita8d381022015-11-19 10:35:34 -0800282
283 surface->getCanvas()->drawPaint(paint);
284}
285
James Zern44e91c92016-11-09 19:22:46 -0800286static void test_vertical(skiatest::Reporter* reporter) {
287 auto surface(SkSurface::MakeRasterN32Premul(200, 200));
288
289 const SkPoint pts[] = {{ 100, 50 }, { 100, 50 }};
290 const SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
291 const SkScalar pos[] = { 0, 1 };
292 SkPaint paint;
Mike Reedfae8fce2019-04-03 10:27:45 -0400293 paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2, SkTileMode::kClamp));
James Zern44e91c92016-11-09 19:22:46 -0800294
295 surface->getCanvas()->drawPaint(paint);
296}
297
reedaeab8ea2016-01-05 10:01:38 -0800298// A linear gradient interval can, due to numerical imprecision (likely in the divide)
299// finish an interval with the final fx not landing outside of [p0...p1].
300// The old code had an assert which this test triggered.
301// We now explicitly clamp the resulting fx value.
302static void test_linear_fuzz(skiatest::Reporter* reporter) {
reede8f30622016-03-23 18:59:25 -0700303 auto surface(SkSurface::MakeRasterN32Premul(1300, 630));
reedaeab8ea2016-01-05 10:01:38 -0800304
305 const SkPoint pts[] = {{ 179.5f, -179.5f }, { 1074.5f, 715.5f }};
306 const SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE };
307 const SkScalar pos[] = {0, 0.200000003f, 0.800000012f, 1 };
308
reed9283d202016-03-13 13:01:57 -0700309 SkPaint paint;
Mike Reedfae8fce2019-04-03 10:27:45 -0400310 paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 4, SkTileMode::kClamp));
reed1a9b9642016-03-13 14:13:58 -0700311
reedaeab8ea2016-01-05 10:01:38 -0800312 SkRect r = {0, 83, 1254, 620};
313 surface->getCanvas()->drawRect(r, paint);
314}
315
fmalita5edf82e2016-03-03 06:41:54 -0800316// https://bugs.chromium.org/p/skia/issues/detail?id=5023
317// We should still shade pixels for which the radius is exactly 0.
318static void test_two_point_conical_zero_radius(skiatest::Reporter* reporter) {
reede8f30622016-03-23 18:59:25 -0700319 auto surface(SkSurface::MakeRasterN32Premul(5, 5));
fmalita5edf82e2016-03-03 06:41:54 -0800320 surface->getCanvas()->clear(SK_ColorRED);
321
322 const SkColor colors[] = { SK_ColorGREEN, SK_ColorBLUE };
reed1a9b9642016-03-13 14:13:58 -0700323 SkPaint p;
324 p.setShader(SkGradientShader::MakeTwoPointConical(
fmalita5edf82e2016-03-03 06:41:54 -0800325 SkPoint::Make(2.5f, 2.5f), 0,
326 SkPoint::Make(3.0f, 3.0f), 10,
Mike Reedfae8fce2019-04-03 10:27:45 -0400327 colors, nullptr, SK_ARRAY_COUNT(colors), SkTileMode::kClamp));
fmalita5edf82e2016-03-03 06:41:54 -0800328 surface->getCanvas()->drawPaint(p);
329
330 // r == 0 for the center pixel.
331 // verify that we draw it (no red bleed)
332 SkPMColor centerPMColor;
333 surface->readPixels(SkImageInfo::MakeN32Premul(1, 1), &centerPMColor, sizeof(SkPMColor), 2, 2);
334 REPORTER_ASSERT(reporter, SkGetPackedR32(centerPMColor) == 0);
335}
336
fmalita7b38e3c2016-05-26 11:13:52 -0700337// http://crbug.com/599458
338static void test_clamping_overflow(skiatest::Reporter*) {
339 SkPaint p;
340 const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN };
341 const SkPoint pts1[] = { SkPoint::Make(1001, 1000001), SkPoint::Make(1000.99f, 1000000) };
342
Mike Reedfae8fce2019-04-03 10:27:45 -0400343 p.setShader(SkGradientShader::MakeLinear(pts1, colors, nullptr, 2, SkTileMode::kClamp));
fmalita7b38e3c2016-05-26 11:13:52 -0700344
345 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
346 surface->getCanvas()->scale(100, 100);
347 surface->getCanvas()->drawPaint(p);
348
349 const SkPoint pts2[] = { SkPoint::Make(10000.99f, 1000000), SkPoint::Make(10001, 1000001) };
Mike Reedfae8fce2019-04-03 10:27:45 -0400350 p.setShader(SkGradientShader::MakeLinear(pts2, colors, nullptr, 2, SkTileMode::kClamp));
fmalita7b38e3c2016-05-26 11:13:52 -0700351 surface->getCanvas()->drawPaint(p);
352
353 // Passes if we don't trigger asserts.
354}
355
fmalitac5231042016-08-10 05:45:50 -0700356// http://crbug.com/636194
Florin Malitae659c7f2017-02-09 13:46:55 -0500357static void test_degenerate_linear(skiatest::Reporter*) {
fmalitac5231042016-08-10 05:45:50 -0700358 SkPaint p;
359 const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN };
360 const SkPoint pts[] = {
361 SkPoint::Make(-46058024627067344430605278824628224.0f, 0),
362 SkPoint::Make(SK_ScalarMax, 0)
363 };
364
Mike Reedfae8fce2019-04-03 10:27:45 -0400365 p.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp));
fmalitac5231042016-08-10 05:45:50 -0700366 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
367 surface->getCanvas()->drawPaint(p);
368
369 // Passes if we don't trigger asserts.
370}
371
Michael Ludwigad5ec1a2020-11-19 14:15:05 -0500372// http://crbug.com/1149216
373static void test_unsorted_degenerate(skiatest::Reporter* r) {
374 // Passes if a valid solid color is computed for the degenerate gradient
375 // (unsorted positions are fixed during regular gradient construction, so this ensures the
376 // same fixing happens for degenerate gradients as well). If they aren't fixed, this test
377 // case produces a negative alpha, which asserts during SkPMColor4f::isOpaque().
378 const SkColor4f colors[] = { {0.f, 0.f, 0.f, 0.f},
379 {0.00784314f, 0.f, 0.f, 0.0627451f},
380 {0.f, 0.00392157f, 0.f, 0.f} };
381 const SkScalar positions[] = {0.00753367f, 8.54792e-44f, 1.46955e-39f};
382
383 const SkPoint points[] { { 0.f, 0.f }, { 1e-20f, -1e-8f }}; // must be degenerate
384 // Use kMirror to go through average color stop calculation, vs. kClamp which would pick a color
385 sk_sp<SkShader> gradient = SkGradientShader::MakeLinear(points, colors, nullptr, positions, 3,
386 SkTileMode::kMirror);
387
388 // The degenerate gradient shouldn't be null
389 REPORTER_ASSERT(r, SkToBool(gradient));
390 // And it shouldn't crash when creating a fragment processor
391
392 SkSimpleMatrixProvider provider(SkMatrix::I());
393 GrColorInfo dstColorInfo(GrColorType::kRGBA_8888, kPremul_SkAlphaType,
394 SkColorSpace::MakeSRGB());
395 GrMockOptions options;
396 auto context = GrDirectContext::MakeMock(&options);
397
398 GrFPArgs args(context.get(), provider, kNone_SkFilterQuality, &dstColorInfo);
399 as_SB(gradient)->asFragmentProcessor(args);
400}
401
Florin Malitae659c7f2017-02-09 13:46:55 -0500402// "Interesting" fuzzer values.
403static void test_linear_fuzzer(skiatest::Reporter*) {
404 static const SkColor gColors0[] = { 0x30303030, 0x30303030 };
Florin Malita3d1a6bc2017-02-09 15:05:15 -0500405 static const SkColor gColors1[] = { 0x30303030, 0x30303030, 0x30303030 };
406
407 static const SkScalar gPos1[] = { 0, 0, 1 };
408
Florin Malitad9569662017-02-09 16:41:34 -0500409 static const SkScalar gMatrix0[9] = {
410 6.40969056e-10f, 0 , 6.40969056e-10f,
411 0 , 4.42539023e-39f, 6.40969056e-10f,
412 0 , 0 , 1
413 };
414 static const SkScalar gMatrix1[9] = {
415 -2.75294113f , 6.40969056e-10f, 6.40969056e-10f,
416 6.40969056e-10f, 6.40969056e-10f, -3.32810161e+24f,
417 6.40969056e-10f, 6.40969056e-10f, 0
418 };
419 static const SkScalar gMatrix2[9] = {
420 7.93481258e+17f, 6.40969056e-10f, 6.40969056e-10f,
421 6.40969056e-10f, 6.40969056e-10f, 6.40969056e-10f,
422 6.40969056e-10f, 6.40969056e-10f, 0.688235283f
423 };
424 static const SkScalar gMatrix3[9] = {
425 1.89180674e+11f, 6.40969056e-10f, 6.40969056e-10f,
426 6.40969056e-10f, 6.40969056e-10f, 6.40969056e-10f,
427 6.40969056e-10f, 11276.0469f , 8.12524808e+20f
428 };
Florin Malitae659c7f2017-02-09 13:46:55 -0500429
430 static const struct {
431 SkPoint fPts[2];
432 const SkColor* fColors;
433 const SkScalar* fPos;
434 int fCount;
Mike Reedfae8fce2019-04-03 10:27:45 -0400435 SkTileMode fTileMode;
Florin Malitae659c7f2017-02-09 13:46:55 -0500436 uint32_t fFlags;
437 const SkScalar* fLocalMatrix;
438 const SkScalar* fGlobalMatrix;
439 } gConfigs[] = {
440 {
Florin Malita3d1a6bc2017-02-09 15:05:15 -0500441 {{0, -2.752941f}, {0, 0}},
442 gColors0,
443 nullptr,
444 SK_ARRAY_COUNT(gColors0),
Mike Reedfae8fce2019-04-03 10:27:45 -0400445 SkTileMode::kClamp,
Florin Malita3d1a6bc2017-02-09 15:05:15 -0500446 0,
447 gMatrix0,
448 nullptr
449 },
450 {
451 {{4.42539023e-39f, -4.42539023e-39f}, {9.78041162e-15f, 4.42539023e-39f}},
452 gColors1,
453 gPos1,
454 SK_ARRAY_COUNT(gColors1),
Mike Reedfae8fce2019-04-03 10:27:45 -0400455 SkTileMode::kClamp,
Florin Malita3d1a6bc2017-02-09 15:05:15 -0500456 0,
457 nullptr,
458 gMatrix1
Florin Malitae659c7f2017-02-09 13:46:55 -0500459 },
Florin Malitad9569662017-02-09 16:41:34 -0500460 {
461 {{4.42539023e-39f, 6.40969056e-10f}, {6.40969056e-10f, 1.49237238e-19f}},
462 gColors1,
463 gPos1,
464 SK_ARRAY_COUNT(gColors1),
Mike Reedfae8fce2019-04-03 10:27:45 -0400465 SkTileMode::kClamp,
Florin Malitad9569662017-02-09 16:41:34 -0500466 0,
467 nullptr,
468 gMatrix2
469 },
470 {
471 {{6.40969056e-10f, 6.40969056e-10f}, {6.40969056e-10f, -0.688235283f}},
472 gColors0,
473 nullptr,
474 SK_ARRAY_COUNT(gColors0),
Mike Reedfae8fce2019-04-03 10:27:45 -0400475 SkTileMode::kClamp,
Florin Malitad9569662017-02-09 16:41:34 -0500476 0,
477 gMatrix3,
478 nullptr
479 },
Florin Malitae659c7f2017-02-09 13:46:55 -0500480 };
481
Florin Malitad1aedde2017-06-07 15:03:38 -0400482 sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB();
483 SkColorSpace* colorSpaces[] = {
484 nullptr, // hits the legacy gradient impl
485 srgb.get(), // triggers 4f/raster-pipeline
486 };
Florin Malitae659c7f2017-02-09 13:46:55 -0500487
Florin Malitae659c7f2017-02-09 13:46:55 -0500488 SkPaint paint;
489
John Stilesbd3ffa42020-07-30 20:24:57 -0400490 for (const SkColorSpace* colorSpace : colorSpaces) {
Florin Malitad1aedde2017-06-07 15:03:38 -0400491
492 sk_sp<SkSurface> surface = SkSurface::MakeRaster(SkImageInfo::Make(100, 100,
493 kN32_SkColorType,
494 kPremul_SkAlphaType,
495 sk_ref_sp(colorSpace)));
496 SkCanvas* canvas = surface->getCanvas();
497
Florin Malitae659c7f2017-02-09 13:46:55 -0500498 for (const auto& config : gConfigs) {
499 SkAutoCanvasRestore acr(canvas, false);
500 SkTLazy<SkMatrix> localMatrix;
501 if (config.fLocalMatrix) {
502 localMatrix.init();
John Stilesa008b0f2020-08-16 08:48:02 -0400503 localMatrix->set9(config.fLocalMatrix);
Florin Malitae659c7f2017-02-09 13:46:55 -0500504 }
505
506 paint.setShader(SkGradientShader::MakeLinear(config.fPts,
507 config.fColors,
508 config.fPos,
509 config.fCount,
510 config.fTileMode,
Florin Malitad1aedde2017-06-07 15:03:38 -0400511 config.fFlags,
Florin Malitae659c7f2017-02-09 13:46:55 -0500512 localMatrix.getMaybeNull()));
Florin Malita3d1a6bc2017-02-09 15:05:15 -0500513 if (config.fGlobalMatrix) {
514 SkMatrix m;
515 m.set9(config.fGlobalMatrix);
516 canvas->save();
517 canvas->concat(m);
518 }
519
Florin Malitae659c7f2017-02-09 13:46:55 -0500520 canvas->drawPaint(paint);
521 }
522 }
523}
524
Florin Malita03013082017-04-18 13:47:15 -0400525static void test_sweep_fuzzer(skiatest::Reporter*) {
526 static const SkColor gColors0[] = { 0x30303030, 0x30303030, 0x30303030 };
527 static const SkScalar gPos0[] = { -47919293023455565225163489280.0f, 0, 1 };
528 static const SkScalar gMatrix0[9] = {
529 1.12116716e-13f, 0 , 8.50489682e+16f,
530 4.1917041e-41f , 3.51369881e-23f, -2.54344271e-26f,
531 9.61111907e+17f, -3.35263808e-29f, -1.35659403e+14f
532 };
533 static const struct {
534 SkPoint fCenter;
535 const SkColor* fColors;
536 const SkScalar* fPos;
537 int fCount;
538 const SkScalar* fGlobalMatrix;
539 } gConfigs[] = {
540 {
541 { 0, 0 },
542 gColors0,
543 gPos0,
544 SK_ARRAY_COUNT(gColors0),
545 gMatrix0
546 },
547 };
548
549 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(100, 100);
550 SkCanvas* canvas = surface->getCanvas();
551 SkPaint paint;
552
553 for (const auto& config : gConfigs) {
554 paint.setShader(SkGradientShader::MakeSweep(config.fCenter.x(),
555 config.fCenter.y(),
556 config.fColors,
557 config.fPos,
558 config.fCount));
559
560 SkAutoCanvasRestore acr(canvas, false);
561 if (config.fGlobalMatrix) {
562 SkMatrix m;
563 m.set9(config.fGlobalMatrix);
564 canvas->save();
565 canvas->concat(m);
566 }
567 canvas->drawPaint(paint);
568 }
569}
Florin Malitae659c7f2017-02-09 13:46:55 -0500570
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000571DEF_TEST(Gradient, reporter) {
junov@chromium.orge94b5e42013-01-30 15:52:06 +0000572 TestGradientShaders(reporter);
fmalita51229672016-08-22 06:22:28 -0700573 TestGradientOptimization(reporter);
junov@chromium.orge94b5e42013-01-30 15:52:06 +0000574 TestConstantGradient(reporter);
reed9d91eb32015-01-28 11:44:48 -0800575 test_big_grad(reporter);
fmalita8d381022015-11-19 10:35:34 -0800576 test_nearly_vertical(reporter);
James Zern44e91c92016-11-09 19:22:46 -0800577 test_vertical(reporter);
reedaeab8ea2016-01-05 10:01:38 -0800578 test_linear_fuzz(reporter);
fmalita5edf82e2016-03-03 06:41:54 -0800579 test_two_point_conical_zero_radius(reporter);
fmalita7b38e3c2016-05-26 11:13:52 -0700580 test_clamping_overflow(reporter);
Florin Malitae659c7f2017-02-09 13:46:55 -0500581 test_degenerate_linear(reporter);
582 test_linear_fuzzer(reporter);
Florin Malita03013082017-04-18 13:47:15 -0400583 test_sweep_fuzzer(reporter);
Michael Ludwigad5ec1a2020-11-19 14:15:05 -0500584 test_unsorted_degenerate(reporter);
junov@chromium.orge94b5e42013-01-30 15:52:06 +0000585}