aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/effects
diff options
context:
space:
mode:
authorGravatar fmalita <fmalita@chromium.org>2016-11-01 13:41:34 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-11-01 13:41:34 -0700
commitafac581523af9de5e0af0af1dc128cac1b846006 (patch)
treec4c8965d894e64eae842ad4a6bc0205b3d24c465 /src/effects
parent08ed0d4926e65f41e6db57dbf72efc871eb4d51e (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.cpp45
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);