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), ¢erPMColor, 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