Fix fuzzer assert in GradientShaderBase4fContext::TSampler

The arithmetic in tileProc<kMirror> may cause the result to snap to the
open interval value - which violates invariants down the line.

We need to clamp the result to nextafterf(2, 0) to ensure it stays less
than two.

BUG=skia:5913
R=reed@google.com,herb@google.com
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2472763002

Review-Url: https://codereview.chromium.org/2472763002
This commit is contained in:
fmalita 2016-11-09 11:58:10 -08:00 committed by Commit bot
parent 792079cf33
commit 8ffb3e5d4c

View File

@ -20,28 +20,6 @@ Sk4f pack_color(SkColor c, bool premul, const Sk4f& component_scale) {
return pm4f * component_scale;
}
template<SkShader::TileMode>
SkScalar tileProc(SkScalar t);
template<>
SkScalar tileProc<SkShader::kClamp_TileMode>(SkScalar t) {
// synthetic clamp-mode edge intervals allow for a free-floating t:
// [-inf..0)[0..1)[1..+inf)
return t;
}
template<>
SkScalar tileProc<SkShader::kRepeat_TileMode>(SkScalar t) {
// t % 1 (intervals range: [0..1))
return t - SkScalarFloorToScalar(t);
}
template<>
SkScalar tileProc<SkShader::kMirror_TileMode>(SkScalar t) {
// t % 2 (synthetic mirror intervals expand the range to [0..2)
return t - SkScalarFloorToScalar(t / 2) * 2;
}
class IntervalIterator {
public:
IntervalIterator(const SkColor* colors, const SkScalar* pos, int count, bool reverse)
@ -359,12 +337,13 @@ public:
TSampler(const GradientShaderBase4fContext& ctx)
: fFirstInterval(ctx.fIntervals.begin())
, fLastInterval(ctx.fIntervals.end() - 1)
, fInterval(nullptr) {
, fInterval(nullptr)
, fLargestLessThanTwo(nextafterf(2, 0)) {
SkASSERT(fLastInterval >= fFirstInterval);
}
Sk4f sample(SkScalar t) {
const SkScalar tiled_t = tileProc<tileMode>(t);
const auto tiled_t = tileProc(t);
if (!fInterval) {
// Very first sample => locate the initial interval.
@ -381,6 +360,25 @@ public:
}
private:
SkScalar tileProc(SkScalar t) const {
switch (tileMode) {
case kClamp_TileMode:
// synthetic clamp-mode edge intervals allow for a free-floating t:
// [-inf..0)[0..1)[1..+inf)
return t;
case kRepeat_TileMode:
// t % 1 (intervals range: [0..1))
return t - SkScalarFloorToScalar(t);
case kMirror_TileMode:
// t % 2 (synthetic mirror intervals expand the range to [0..2)
// Due to the extra arithmetic, we must clamp to ensure the value remains less than 2.
return SkTMin(t - SkScalarFloorToScalar(t / 2) * 2, fLargestLessThanTwo);
}
SK_ABORT("Unhandled tile mode.");
return 0;
}
Sk4f lerp(SkScalar t) {
SkASSERT(t >= fInterval->fP0 && t < fInterval->fP1);
return fCc + fDc * (t - fInterval->fP0);
@ -444,6 +442,7 @@ private:
const Interval* fLastInterval;
const Interval* fInterval;
SkScalar fPrevT;
SkScalar fLargestLessThanTwo;
Sk4f fCc;
Sk4f fDc;
};