| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkCanvas.h" | 8 #include "SkCanvas.h" |
| 9 #include "SkColorPriv.h" | 9 #include "SkColorPriv.h" |
| 10 #include "SkColorShader.h" | 10 #include "SkColorShader.h" |
| 11 #include "SkGradientShader.h" | 11 #include "SkGradientShader.h" |
| 12 #include "SkShader.h" | 12 #include "SkShader.h" |
| 13 #include "SkSurface.h" | 13 #include "SkSurface.h" |
| 14 #include "SkTemplates.h" | 14 #include "SkTemplates.h" |
| 15 #include "Test.h" | 15 #include "Test.h" |
| 16 | 16 |
| 17 // https://code.google.com/p/chromium/issues/detail?id=448299 | 17 // https://code.google.com/p/chromium/issues/detail?id=448299 |
| 18 // Giant (inverse) matrix causes overflow when converting/computing using 32.32 | 18 // Giant (inverse) matrix causes overflow when converting/computing using 32.32 |
| 19 // Before the fix, we would assert (and then crash). | 19 // Before the fix, we would assert (and then crash). |
| 20 static void test_big_grad(skiatest::Reporter* reporter) { | 20 static void test_big_grad(skiatest::Reporter* reporter) { |
| 21 const SkColor colors[] = { SK_ColorRED, SK_ColorBLUE }; | 21 const SkColor colors[] = { SK_ColorRED, SK_ColorBLUE }; |
| 22 const SkPoint pts[] = {{ 15, 14.7112684f }, { 0.709064007f, 12.6108112f }}; | 22 const SkPoint pts[] = {{ 15, 14.7112684f }, { 0.709064007f, 12.6108112f }}; |
| 23 SkShader* s = SkGradientShader::CreateLinear(pts, colors, nullptr, 2, SkShad
er::kClamp_TileMode); |
| 23 SkPaint paint; | 24 SkPaint paint; |
| 24 paint.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, 2, | 25 paint.setShader(s)->unref(); |
| 25 SkShader::kClamp_TileMode)); | |
| 26 | 26 |
| 27 SkBitmap bm; | 27 SkBitmap bm; |
| 28 bm.allocN32Pixels(2000, 1); | 28 bm.allocN32Pixels(2000, 1); |
| 29 SkCanvas c(bm); | 29 SkCanvas c(bm); |
| 30 | 30 |
| 31 const SkScalar affine[] = { | 31 const SkScalar affine[] = { |
| 32 1.06608627e-06f, 4.26434525e-07f, 6.2855f, 2.6611f, 273.4393f, 244.0046f | 32 1.06608627e-06f, 4.26434525e-07f, 6.2855f, 2.6611f, 273.4393f, 244.0046f |
| 33 }; | 33 }; |
| 34 SkMatrix matrix; | 34 SkMatrix matrix; |
| 35 matrix.setAffine(affine); | 35 matrix.setAffine(affine); |
| 36 c.concat(matrix); | 36 c.concat(matrix); |
| 37 | 37 |
| 38 c.drawPaint(paint); | 38 c.drawPaint(paint); |
| 39 } | 39 } |
| 40 | 40 |
| 41 struct GradRec { | 41 struct GradRec { |
| 42 int fColorCount; | 42 int fColorCount; |
| 43 const SkColor* fColors; | 43 const SkColor* fColors; |
| 44 const SkScalar* fPos; | 44 const SkScalar* fPos; |
| 45 const SkPoint* fPoint; // 2 | 45 const SkPoint* fPoint; // 2 |
| 46 const SkScalar* fRadius; // 2 | 46 const SkScalar* fRadius; // 2 |
| 47 SkShader::TileMode fTileMode; | 47 SkShader::TileMode fTileMode; |
| 48 | 48 |
| 49 void gradCheck(skiatest::Reporter* reporter, const sk_sp<SkShader>& shader, | 49 void gradCheck(skiatest::Reporter* reporter, SkShader* shader, |
| 50 SkShader::GradientInfo* info, | 50 SkShader::GradientInfo* info, |
| 51 SkShader::GradientType gt) const { | 51 SkShader::GradientType gt) const { |
| 52 SkAutoTMalloc<SkColor> colorStorage(fColorCount); | 52 SkAutoTMalloc<SkColor> colorStorage(fColorCount); |
| 53 SkAutoTMalloc<SkScalar> posStorage(fColorCount); | 53 SkAutoTMalloc<SkScalar> posStorage(fColorCount); |
| 54 | 54 |
| 55 info->fColorCount = fColorCount; | 55 info->fColorCount = fColorCount; |
| 56 info->fColors = colorStorage; | 56 info->fColors = colorStorage; |
| 57 info->fColorOffsets = posStorage.get(); | 57 info->fColorOffsets = posStorage.get(); |
| 58 REPORTER_ASSERT(reporter, shader->asAGradient(info) == gt); | 58 REPORTER_ASSERT(reporter, shader->asAGradient(info) == gt); |
| 59 | 59 |
| 60 REPORTER_ASSERT(reporter, info->fColorCount == fColorCount); | 60 REPORTER_ASSERT(reporter, info->fColorCount == fColorCount); |
| 61 REPORTER_ASSERT(reporter, | 61 REPORTER_ASSERT(reporter, |
| 62 !memcmp(info->fColors, fColors, fColorCount * sizeof(SkC
olor))); | 62 !memcmp(info->fColors, fColors, fColorCount * sizeof(SkC
olor))); |
| 63 REPORTER_ASSERT(reporter, | 63 REPORTER_ASSERT(reporter, |
| 64 !memcmp(info->fColorOffsets, fPos, fColorCount * sizeof(
SkScalar))); | 64 !memcmp(info->fColorOffsets, fPos, fColorCount * sizeof(
SkScalar))); |
| 65 REPORTER_ASSERT(reporter, fTileMode == info->fTileMode); | 65 REPORTER_ASSERT(reporter, fTileMode == info->fTileMode); |
| 66 } | 66 } |
| 67 }; | 67 }; |
| 68 | 68 |
| 69 | 69 |
| 70 static void none_gradproc(skiatest::Reporter* reporter, const GradRec&) { | 70 static void none_gradproc(skiatest::Reporter* reporter, const GradRec&) { |
| 71 sk_sp<SkShader> s(SkShader::MakeEmptyShader()); | 71 SkAutoTUnref<SkShader> s(SkShader::CreateEmptyShader()); |
| 72 REPORTER_ASSERT(reporter, SkShader::kNone_GradientType == s->asAGradient(nul
lptr)); | 72 REPORTER_ASSERT(reporter, SkShader::kNone_GradientType == s->asAGradient(nul
lptr)); |
| 73 } | 73 } |
| 74 | 74 |
| 75 static void color_gradproc(skiatest::Reporter* reporter, const GradRec& rec) { | 75 static void color_gradproc(skiatest::Reporter* reporter, const GradRec& rec) { |
| 76 SkAutoTUnref<SkShader> s(new SkColorShader(rec.fColors[0])); | 76 SkAutoTUnref<SkShader> s(new SkColorShader(rec.fColors[0])); |
| 77 REPORTER_ASSERT(reporter, SkShader::kColor_GradientType == s->asAGradient(nu
llptr)); | 77 REPORTER_ASSERT(reporter, SkShader::kColor_GradientType == s->asAGradient(nu
llptr)); |
| 78 | 78 |
| 79 SkShader::GradientInfo info; | 79 SkShader::GradientInfo info; |
| 80 info.fColors = nullptr; | 80 info.fColors = nullptr; |
| 81 info.fColorCount = 0; | 81 info.fColorCount = 0; |
| 82 s->asAGradient(&info); | 82 s->asAGradient(&info); |
| 83 REPORTER_ASSERT(reporter, 1 == info.fColorCount); | 83 REPORTER_ASSERT(reporter, 1 == info.fColorCount); |
| 84 } | 84 } |
| 85 | 85 |
| 86 static void linear_gradproc(skiatest::Reporter* reporter, const GradRec& rec) { | 86 static void linear_gradproc(skiatest::Reporter* reporter, const GradRec& rec) { |
| 87 sk_sp<SkShader> s(SkGradientShader::MakeLinear(rec.fPoint, rec.fColors, rec.
fPos, | 87 SkAutoTUnref<SkShader> s(SkGradientShader::CreateLinear(rec.fPoint, |
| 88 rec.fColorCount, rec.fTileMod
e)); | 88 rec.fColors, |
| 89 rec.fPos, |
| 90 rec.fColorCount, |
| 91 rec.fTileMode)); |
| 89 | 92 |
| 90 SkShader::GradientInfo info; | 93 SkShader::GradientInfo info; |
| 91 rec.gradCheck(reporter, s, &info, SkShader::kLinear_GradientType); | 94 rec.gradCheck(reporter, s, &info, SkShader::kLinear_GradientType); |
| 92 REPORTER_ASSERT(reporter, !memcmp(info.fPoint, rec.fPoint, 2 * sizeof(SkPoin
t))); | 95 REPORTER_ASSERT(reporter, !memcmp(info.fPoint, rec.fPoint, 2 * sizeof(SkPoin
t))); |
| 93 } | 96 } |
| 94 | 97 |
| 95 static void radial_gradproc(skiatest::Reporter* reporter, const GradRec& rec) { | 98 static void radial_gradproc(skiatest::Reporter* reporter, const GradRec& rec) { |
| 96 sk_sp<SkShader> s(SkGradientShader::MakeRadial(rec.fPoint[0], rec.fRadius[0]
, rec.fColors, | 99 SkAutoTUnref<SkShader> s(SkGradientShader::CreateRadial(rec.fPoint[0], |
| 97 rec.fPos, rec.fColorCount, re
c.fTileMode)); | 100 rec.fRadius[0], |
| 101 rec.fColors, |
| 102 rec.fPos, |
| 103 rec.fColorCount, |
| 104 rec.fTileMode)); |
| 98 | 105 |
| 99 SkShader::GradientInfo info; | 106 SkShader::GradientInfo info; |
| 100 rec.gradCheck(reporter, s, &info, SkShader::kRadial_GradientType); | 107 rec.gradCheck(reporter, s, &info, SkShader::kRadial_GradientType); |
| 101 REPORTER_ASSERT(reporter, info.fPoint[0] == rec.fPoint[0]); | 108 REPORTER_ASSERT(reporter, info.fPoint[0] == rec.fPoint[0]); |
| 102 REPORTER_ASSERT(reporter, info.fRadius[0] == rec.fRadius[0]); | 109 REPORTER_ASSERT(reporter, info.fRadius[0] == rec.fRadius[0]); |
| 103 } | 110 } |
| 104 | 111 |
| 105 static void sweep_gradproc(skiatest::Reporter* reporter, const GradRec& rec) { | 112 static void sweep_gradproc(skiatest::Reporter* reporter, const GradRec& rec) { |
| 106 sk_sp<SkShader> s(SkGradientShader::MakeSweep(rec.fPoint[0].fX, rec.fPoint[0
].fY, rec.fColors, | 113 SkAutoTUnref<SkShader> s(SkGradientShader::CreateSweep(rec.fPoint[0].fX, |
| 107 rec.fPos, rec.fColorCount)); | 114 rec.fPoint[0].fY, |
| 115 rec.fColors, |
| 116 rec.fPos, |
| 117 rec.fColorCount)); |
| 108 | 118 |
| 109 SkShader::GradientInfo info; | 119 SkShader::GradientInfo info; |
| 110 rec.gradCheck(reporter, s, &info, SkShader::kSweep_GradientType); | 120 rec.gradCheck(reporter, s, &info, SkShader::kSweep_GradientType); |
| 111 REPORTER_ASSERT(reporter, info.fPoint[0] == rec.fPoint[0]); | 121 REPORTER_ASSERT(reporter, info.fPoint[0] == rec.fPoint[0]); |
| 112 } | 122 } |
| 113 | 123 |
| 114 static void conical_gradproc(skiatest::Reporter* reporter, const GradRec& rec) { | 124 static void conical_gradproc(skiatest::Reporter* reporter, const GradRec& rec) { |
| 115 sk_sp<SkShader> s(SkGradientShader::MakeTwoPointConical(rec.fPoint[0], | 125 SkAutoTUnref<SkShader> s(SkGradientShader::CreateTwoPointConical(rec.fPoint[
0], |
| 116 rec.fRadius[0], | 126 rec.fRadius[0], |
| 117 rec.fPoint[1], | 127 rec.fPoint[1], |
| 118 rec.fRadius[1], | 128 rec.fRadius[1], |
| 119 rec.fColors, | 129 rec.fColors, |
| 120 rec.fPos, | 130 rec.fPos, |
| 121 rec.fColorCount, | 131 rec.fColorCount, |
| 122 rec.fTileMode)); | 132 rec.fTileMode)); |
| 123 | 133 |
| 124 SkShader::GradientInfo info; | 134 SkShader::GradientInfo info; |
| 125 rec.gradCheck(reporter, s, &info, SkShader::kConical_GradientType); | 135 rec.gradCheck(reporter, s, &info, SkShader::kConical_GradientType); |
| 126 REPORTER_ASSERT(reporter, !memcmp(info.fPoint, rec.fPoint, 2 * sizeof(SkPoin
t))); | 136 REPORTER_ASSERT(reporter, !memcmp(info.fPoint, rec.fPoint, 2 * sizeof(SkPoin
t))); |
| 127 REPORTER_ASSERT(reporter, !memcmp(info.fRadius, rec.fRadius, 2 * sizeof(SkSc
alar))); | 137 REPORTER_ASSERT(reporter, !memcmp(info.fRadius, rec.fRadius, 2 * sizeof(SkSc
alar))); |
| 128 } | 138 } |
| 129 | 139 |
| 130 // Ensure that repeated color gradients behave like drawing a single color | 140 // Ensure that repeated color gradients behave like drawing a single color |
| 131 static void TestConstantGradient(skiatest::Reporter*) { | 141 static void TestConstantGradient(skiatest::Reporter*) { |
| 132 const SkPoint pts[] = { | 142 const SkPoint pts[] = { |
| 133 { 0, 0 }, | 143 { 0, 0 }, |
| 134 { SkIntToScalar(10), 0 } | 144 { SkIntToScalar(10), 0 } |
| 135 }; | 145 }; |
| 136 SkColor colors[] = { SK_ColorBLUE, SK_ColorBLUE }; | 146 SkColor colors[] = { SK_ColorBLUE, SK_ColorBLUE }; |
| 137 const SkScalar pos[] = { 0, SK_Scalar1 }; | 147 const SkScalar pos[] = { 0, SK_Scalar1 }; |
| 138 SkPaint paint; | 148 SkAutoTUnref<SkShader> s(SkGradientShader::CreateLinear(pts, |
| 139 paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2, SkShader::
kClamp_TileMode)); | 149 colors, |
| 150 pos, |
| 151 2, |
| 152 SkShader::kClamp_Til
eMode)); |
| 140 SkBitmap outBitmap; | 153 SkBitmap outBitmap; |
| 141 outBitmap.allocN32Pixels(10, 1); | 154 outBitmap.allocN32Pixels(10, 1); |
| 155 SkPaint paint; |
| 156 paint.setShader(s.get()); |
| 142 SkCanvas canvas(outBitmap); | 157 SkCanvas canvas(outBitmap); |
| 143 canvas.drawPaint(paint); | 158 canvas.drawPaint(paint); |
| 144 SkAutoLockPixels alp(outBitmap); | 159 SkAutoLockPixels alp(outBitmap); |
| 145 for (int i = 0; i < 10; i++) { | 160 for (int i = 0; i < 10; i++) { |
| 146 // The following is commented out because it currently fails | 161 // The following is commented out because it currently fails |
| 147 // Related bug: https://code.google.com/p/skia/issues/detail?id=1098 | 162 // Related bug: https://code.google.com/p/skia/issues/detail?id=1098 |
| 148 | 163 |
| 149 // REPORTER_ASSERT(reporter, SK_ColorBLUE == outBitmap.getColor(i, 0)); | 164 // REPORTER_ASSERT(reporter, SK_ColorBLUE == outBitmap.getColor(i, 0)); |
| 150 } | 165 } |
| 151 } | 166 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 182 gProcs[i](reporter, rec); | 197 gProcs[i](reporter, rec); |
| 183 } | 198 } |
| 184 } | 199 } |
| 185 | 200 |
| 186 static void test_nearly_vertical(skiatest::Reporter* reporter) { | 201 static void test_nearly_vertical(skiatest::Reporter* reporter) { |
| 187 SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(200, 200)); | 202 SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(200, 200)); |
| 188 | 203 |
| 189 const SkPoint pts[] = {{ 100, 50 }, { 100.0001f, 50000 }}; | 204 const SkPoint pts[] = {{ 100, 50 }, { 100.0001f, 50000 }}; |
| 190 const SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE }; | 205 const SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE }; |
| 191 const SkScalar pos[] = { 0, 1 }; | 206 const SkScalar pos[] = { 0, 1 }; |
| 207 SkAutoTUnref<SkShader> gradient( |
| 208 SkGradientShader::CreateLinear(pts, colors, pos, 2, SkShader::kClamp_Til
eMode)); |
| 209 |
| 192 SkPaint paint; | 210 SkPaint paint; |
| 193 paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2, SkShader::
kClamp_TileMode)); | 211 paint.setShader(gradient); |
| 194 | 212 |
| 195 surface->getCanvas()->drawPaint(paint); | 213 surface->getCanvas()->drawPaint(paint); |
| 196 } | 214 } |
| 197 | 215 |
| 198 // A linear gradient interval can, due to numerical imprecision (likely in the d
ivide) | 216 // A linear gradient interval can, due to numerical imprecision (likely in the d
ivide) |
| 199 // finish an interval with the final fx not landing outside of [p0...p1]. | 217 // finish an interval with the final fx not landing outside of [p0...p1]. |
| 200 // The old code had an assert which this test triggered. | 218 // The old code had an assert which this test triggered. |
| 201 // We now explicitly clamp the resulting fx value. | 219 // We now explicitly clamp the resulting fx value. |
| 202 static void test_linear_fuzz(skiatest::Reporter* reporter) { | 220 static void test_linear_fuzz(skiatest::Reporter* reporter) { |
| 203 SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(1300, 630)); | 221 SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(1300, 630)); |
| 204 | 222 |
| 205 const SkPoint pts[] = {{ 179.5f, -179.5f }, { 1074.5f, 715.5f }}; | 223 const SkPoint pts[] = {{ 179.5f, -179.5f }, { 1074.5f, 715.5f }}; |
| 206 const SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_C
olorWHITE }; | 224 const SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_C
olorWHITE }; |
| 207 const SkScalar pos[] = {0, 0.200000003f, 0.800000012f, 1 }; | 225 const SkScalar pos[] = {0, 0.200000003f, 0.800000012f, 1 }; |
| 208 | 226 |
| 227 |
| 228 SkAutoTUnref<SkShader> gradient( |
| 229 SkGradientShader::CreateLinear(pts, colors, pos, 4, SkShader:
:kClamp_TileMode)); |
| 230 |
| 209 SkPaint paint; | 231 SkPaint paint; |
| 210 paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 4, SkShader::
kClamp_TileMode)); | 232 paint.setShader(gradient); |
| 211 | |
| 212 SkRect r = {0, 83, 1254, 620}; | 233 SkRect r = {0, 83, 1254, 620}; |
| 213 surface->getCanvas()->drawRect(r, paint); | 234 surface->getCanvas()->drawRect(r, paint); |
| 214 } | 235 } |
| 215 | 236 |
| 216 // https://bugs.chromium.org/p/skia/issues/detail?id=5023 | 237 // https://bugs.chromium.org/p/skia/issues/detail?id=5023 |
| 217 // We should still shade pixels for which the radius is exactly 0. | 238 // We should still shade pixels for which the radius is exactly 0. |
| 218 static void test_two_point_conical_zero_radius(skiatest::Reporter* reporter) { | 239 static void test_two_point_conical_zero_radius(skiatest::Reporter* reporter) { |
| 219 SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(5, 5)); | 240 SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(5, 5)); |
| 220 surface->getCanvas()->clear(SK_ColorRED); | 241 surface->getCanvas()->clear(SK_ColorRED); |
| 221 | 242 |
| 222 const SkColor colors[] = { SK_ColorGREEN, SK_ColorBLUE }; | 243 const SkColor colors[] = { SK_ColorGREEN, SK_ColorBLUE }; |
| 223 SkPaint p; | 244 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical( |
| 224 p.setShader(SkGradientShader::MakeTwoPointConical( | |
| 225 SkPoint::Make(2.5f, 2.5f), 0, | 245 SkPoint::Make(2.5f, 2.5f), 0, |
| 226 SkPoint::Make(3.0f, 3.0f), 10, | 246 SkPoint::Make(3.0f, 3.0f), 10, |
| 227 colors, nullptr, SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode)); | 247 colors, nullptr, SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode)); |
| 248 SkPaint p; |
| 249 p.setShader(shader); |
| 228 surface->getCanvas()->drawPaint(p); | 250 surface->getCanvas()->drawPaint(p); |
| 229 | 251 |
| 230 // r == 0 for the center pixel. | 252 // r == 0 for the center pixel. |
| 231 // verify that we draw it (no red bleed) | 253 // verify that we draw it (no red bleed) |
| 232 SkPMColor centerPMColor; | 254 SkPMColor centerPMColor; |
| 233 surface->readPixels(SkImageInfo::MakeN32Premul(1, 1), ¢erPMColor, sizeof
(SkPMColor), 2, 2); | 255 surface->readPixels(SkImageInfo::MakeN32Premul(1, 1), ¢erPMColor, sizeof
(SkPMColor), 2, 2); |
| 234 REPORTER_ASSERT(reporter, SkGetPackedR32(centerPMColor) == 0); | 256 REPORTER_ASSERT(reporter, SkGetPackedR32(centerPMColor) == 0); |
| 235 } | 257 } |
| 236 | 258 |
| 237 DEF_TEST(Gradient, reporter) { | 259 DEF_TEST(Gradient, reporter) { |
| 238 TestGradientShaders(reporter); | 260 TestGradientShaders(reporter); |
| 239 TestConstantGradient(reporter); | 261 TestConstantGradient(reporter); |
| 240 test_big_grad(reporter); | 262 test_big_grad(reporter); |
| 241 test_nearly_vertical(reporter); | 263 test_nearly_vertical(reporter); |
| 242 test_linear_fuzz(reporter); | 264 test_linear_fuzz(reporter); |
| 243 test_two_point_conical_zero_radius(reporter); | 265 test_two_point_conical_zero_radius(reporter); |
| 244 } | 266 } |
| OLD | NEW |