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
This commit is contained in:
parent
08ed0d4926
commit
afac581523
@ -919,3 +919,20 @@ DEF_SIMPLE_GM(gradient_many_stops, canvas, 500, 500) {
|
||||
DEF_SIMPLE_GM(gradient_many_stops_4f, canvas, 500, 500) {
|
||||
draw_many_stops(canvas, SkLinearGradient::kForce4fContext_PrivateFlag);
|
||||
}
|
||||
|
||||
static void draw_subpixel_gradient(SkCanvas* canvas, uint32_t flags) {
|
||||
const SkPoint pts[] = { {50, 50}, {50.1f, 50.1f}};
|
||||
SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
|
||||
SkPaint p;
|
||||
p.setShader(SkGradientShader::MakeLinear(
|
||||
pts, colors, nullptr, SK_ARRAY_COUNT(colors), SkShader::kRepeat_TileMode, flags, nullptr));
|
||||
canvas->drawRect(SkRect::MakeXYWH(0, 0, 500, 500), p);
|
||||
}
|
||||
|
||||
DEF_SIMPLE_GM(gradient_subpixel, canvas, 500, 500) {
|
||||
draw_subpixel_gradient(canvas, 0);
|
||||
}
|
||||
|
||||
DEF_SIMPLE_GM(gradient_subpixel_4f, canvas, 500, 500) {
|
||||
draw_subpixel_gradient(canvas, SkLinearGradient::kForce4fContext_PrivateFlag);
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user