diff options
-rw-r--r-- | src/effects/gradients/SkLinearGradient.cpp | 11 | ||||
-rw-r--r-- | tests/GradientTest.cpp | 22 |
2 files changed, 29 insertions, 4 deletions
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp index 298466c8a6..4f90c27c8c 100644 --- a/src/effects/gradients/SkLinearGradient.cpp +++ b/src/effects/gradients/SkLinearGradient.cpp @@ -668,12 +668,12 @@ void SkLinearGradient::LinearGradientContext::shade4_dx_clamp(SkPMColor dstC[], } fx += n * dx; - count -= n; - SkASSERT(count >= 0); + // fx should now outside of the p0..p1 interval. However, due to float precision loss, + // its possible that fx is slightly too small/large, so we clamp it. if (dx_is_pos) { - SkASSERT(0 == count || fx >= p1); + fx = SkTMax(fx, p1); } else { - SkASSERT(0 == count || fx <= p0); + fx = SkTMin(fx, p0); } ramp<apply_alpha>(dstC, n, c, dc, dither0, dither1); @@ -683,6 +683,9 @@ void SkLinearGradient::LinearGradientContext::shade4_dx_clamp(SkPMColor dstC[], if (n & 1) { SkTSwap(dither0, dither1); } + + count -= n; + SkASSERT(count >= 0); } } diff --git a/tests/GradientTest.cpp b/tests/GradientTest.cpp index 8d73569f64..6a277d520e 100644 --- a/tests/GradientTest.cpp +++ b/tests/GradientTest.cpp @@ -212,9 +212,31 @@ static void test_nearly_vertical(skiatest::Reporter* reporter) { surface->getCanvas()->drawPaint(paint); } +// A linear gradient interval can, due to numerical imprecision (likely in the divide) +// finish an interval with the final fx not landing outside of [p0...p1]. +// The old code had an assert which this test triggered. +// We now explicitly clamp the resulting fx value. +static void test_linear_fuzz(skiatest::Reporter* reporter) { + SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(1300, 630)); + + const SkPoint pts[] = {{ 179.5f, -179.5f }, { 1074.5f, 715.5f }}; + const SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE }; + const SkScalar pos[] = {0, 0.200000003f, 0.800000012f, 1 }; + + + SkAutoTUnref<SkShader> gradient( + SkGradientShader::CreateLinear(pts, colors, pos, 4, SkShader::kClamp_TileMode)); + + SkPaint paint; + paint.setShader(gradient); + SkRect r = {0, 83, 1254, 620}; + surface->getCanvas()->drawRect(r, paint); +} + DEF_TEST(Gradient, reporter) { TestGradientShaders(reporter); TestConstantGradient(reporter); test_big_grad(reporter); test_nearly_vertical(reporter); + test_linear_fuzz(reporter); } |