diff options
author | 2016-11-01 13:41:34 -0700 | |
---|---|---|
committer | 2016-11-01 13:41:34 -0700 | |
commit | afac581523af9de5e0af0af1dc128cac1b846006 (patch) | |
tree | c4c8965d894e64eae842ad4a6bc0205b3d24c465 /src/effects | |
parent | 08ed0d4926e65f41e6db57dbf72efc871eb4d51e (diff) |
Sk4fLinearGradient fuzzer fixes
1) update in_range() to actually follow the documented rules regarding interval
open/close endpoints
2) detect cases where the intervals provide negligible advance and fall back
to using a color average
BUG=skia:5647
R=reed@google.com
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2472483002
Review-Url: https://codereview.chromium.org/2472483002
Diffstat (limited to 'src/effects')
-rw-r--r-- | src/effects/gradients/Sk4fLinearGradient.cpp | 45 |
1 files changed, 42 insertions, 3 deletions
diff --git a/src/effects/gradients/Sk4fLinearGradient.cpp b/src/effects/gradients/Sk4fLinearGradient.cpp index ebfd13812e..1100493212 100644 --- a/src/effects/gradients/Sk4fLinearGradient.cpp +++ b/src/effects/gradients/Sk4fLinearGradient.cpp @@ -105,8 +105,8 @@ SkScalar pinFx<SkShader::kMirror_TileMode>(SkScalar fx) { bool in_range(SkScalar x, SkScalar k1, SkScalar k2) { SkASSERT(k1 != k2); return (k1 < k2) - ? (x >= k1 && x < k2) - : (x > k2 && x <= k1); + ? (x >= k1 && x < k2) + : (x >= k2 && x < k1); } } // anonymous namespace @@ -294,12 +294,28 @@ public: SkASSERT(fAdvX >= 0); SkASSERT(firstInterval <= lastInterval); SkASSERT(in_range(fx, i->fP0, i->fP1)); + + if (tileMode != kClamp_TileMode && !is_vertical) { + const auto spanX = (lastInterval->fP1 - firstInterval->fP0) / dx; + SkASSERT(spanX >= 0); + + // If we're in a repeating tile mode and the whole gradient is compressed into a + // fraction of a pixel, we just use the average color in zero-ramp mode. + // This also avoids cases where we make no progress due to interval advances being + // close to zero. + static constexpr SkScalar kMinSpanX = .25f; + if (spanX < kMinSpanX) { + this->init_average_props(); + return; + } + } + this->compute_interval_props(fx - i->fP0); } SkScalar currentAdvance() const { SkASSERT(fAdvX >= 0); - SkASSERT(fAdvX <= (fInterval->fP1 - fInterval->fP0) / fDx); + SkASSERT(fAdvX <= (fInterval->fP1 - fInterval->fP0) / fDx || !isfinite(fAdvX)); return fAdvX; } @@ -334,6 +350,29 @@ private: } } + void init_average_props() { + fAdvX = SK_ScalarInfinity; + fZeroRamp = true; + fDcDx = 0; + fCc = Sk4f(0); + + // TODO: precompute the average at interval setup time? + for (const auto* i = fFirstInterval; i <= fLastInterval; ++i) { + // Each interval contributes its average color to the total/weighted average: + // + // C = (c0 + c1) / 2 = (c0 + c0 + dc * (p1 - p0)) / 2 + // + // Avg += C * (p1 - p0) + // + const auto dp = i->fP1 - i->fP0; + auto c = DstTraits<dstType, premul>::load(i->fC0); + if (!i->fZeroRamp) { + c = c + DstTraits<dstType, premul>::load(i->fDc) * dp * 0.5f; + } + fCc = fCc + c * dp; + } + } + const Interval* next_interval(const Interval* i) const { SkASSERT(i >= fFirstInterval); SkASSERT(i <= fLastInterval); |