Index: src/effects/gradients/Sk4fLinearGradient.cpp |
diff --git a/src/effects/gradients/Sk4fLinearGradient.cpp b/src/effects/gradients/Sk4fLinearGradient.cpp |
index ebfd13812e0c7eaf30199323b9a95dc3434e14ad..1100493212e22e1e80758ff06f8a1eb8c1b1eb7c 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); |