spin off: always clamp linear gradients
While we're refactoring how gradients work it's going to be easier
to centralized how and when we tile.
- PS2 changed linear and radial in place to alwys clamp.
- PS3 moved tiling to the base class, where it's even harder to
screw up. Sweeps don't need but don't mind tiling.
- PS4 clamps when iff evenly spaced
PS4 has image diffs for only a few GMs that I'm not familiar with.
If its logic reads as correct to you, they may be bug fixes?
Change-Id: I5e37d6e88aaea898356d4c57db0cd5bf414c0295
Reviewed-on: https://skia-review.googlesource.com/16501
Commit-Queue: Mike Klein <mtklein@chromium.org>
Reviewed-by: Florin Malita <fmalita@chromium.org>
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index e5cf071..6f9b404 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -347,30 +347,44 @@
memcpy(colorDst, colorsTemp.get(), count * sizeof(SkColor));
}
-bool SkGradientShaderBase::onAppendStages(
- SkRasterPipeline* pipeline, SkColorSpace* dstCS, SkArenaAlloc* alloc,
- const SkMatrix& ctm, const SkPaint& paint,
- const SkMatrix* localM) const
-{
+bool SkGradientShaderBase::onAppendStages(SkRasterPipeline* p,
+ SkColorSpace* dstCS,
+ SkArenaAlloc* alloc,
+ const SkMatrix& ctm,
+ const SkPaint& paint,
+ const SkMatrix* localM) const {
SkMatrix matrix;
if (!this->computeTotalInverse(ctm, localM, &matrix)) {
return false;
}
- SkRasterPipeline p;
- if (!this->adjustMatrixAndAppendStages(alloc, &matrix, &p)) {
+ SkRasterPipeline subclass;
+ if (!this->adjustMatrixAndAppendStages(alloc, &matrix, &subclass)) {
return false;
}
auto* m = alloc->makeArrayDefault<float>(9);
if (matrix.asAffine(m)) {
- pipeline->append(SkRasterPipeline::matrix_2x3, m);
+ p->append(SkRasterPipeline::matrix_2x3, m);
} else {
matrix.get9(m);
- pipeline->append(SkRasterPipeline::matrix_perspective, m);
+ p->append(SkRasterPipeline::matrix_perspective, m);
}
- pipeline->extend(p);
+ p->extend(subclass);
+
+ switch(fTileMode) {
+ case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x, alloc->make<float>(1)); break;
+ case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x, alloc->make<float>(1)); break;
+ case kClamp_TileMode:
+ if (!fOrigPos) {
+ // We clamp only when the stops are evenly spaced.
+ // If not, there may be hard stops, and clamping ruins hard stops at 0 and/or 1.
+ // In that case, we must make sure we're using the general linear_gradient stage,
+ // which is the only stage that will correctly handle unclamped t.
+ p->append(SkRasterPipeline::clamp_x, alloc->make<float>(1));
+ }
+ }
const bool premulGrad = fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag;
auto prepareColor = [premulGrad, dstCS, this](int i) {
@@ -390,7 +404,7 @@
f_and_b[0] = SkPM4f::From4f(c_r.to4f() - c_l.to4f());
f_and_b[1] = c_l;
- pipeline->append(SkRasterPipeline::linear_gradient_2stops, f_and_b);
+ p->append(SkRasterPipeline::linear_gradient_2stops, f_and_b);
} else {
struct Stop { float t; SkPM4f f, b; };
@@ -479,11 +493,11 @@
ctx->stops = stopsArray;
}
- pipeline->append(SkRasterPipeline::linear_gradient, ctx);
+ p->append(SkRasterPipeline::linear_gradient, ctx);
}
if (!premulGrad && !this->colorsAreOpaque()) {
- pipeline->append(SkRasterPipeline::premul);
+ p->append(SkRasterPipeline::premul);
}
return true;