aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/effects/gradients/SkLinearGradient.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/effects/gradients/SkLinearGradient.cpp')
-rw-r--r--src/effects/gradients/SkLinearGradient.cpp70
1 files changed, 70 insertions, 0 deletions
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index 4bb640de91..91c0e20955 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -86,6 +86,76 @@ SkShader::Context* SkLinearGradient::onCreateContext(const ContextRec& rec, void
: CheckedCreateContext< LinearGradientContext>(storage, *this, rec);
}
+// For now, only a 2-stop raster pipeline specialization.
+//
+// Stages:
+//
+// * matrix (map dst -> grad space)
+// * clamp/repeat/mirror (tiling)
+// * linear_gradient_2stops (lerp c0/c1)
+// * optional premul
+//
+bool SkLinearGradient::onAppendStages(SkRasterPipeline* p, SkColorSpace* cs, SkArenaAlloc* alloc,
+ const SkMatrix& ctm, const SkPaint& paint) const {
+ if (fColorCount > 2) {
+ return false;
+ }
+
+ // Local matrix not supported currently. Remove once we have a generic RP wrapper.
+ if (!getLocalMatrix().isIdentity()) {
+ return false;
+ }
+
+ SkASSERT(fColorCount == 2);
+ SkASSERT(fOrigPos == nullptr || (fOrigPos[0] == 0 && fOrigPos[1] == 1));
+
+ SkMatrix dstToPts;
+ if (!ctm.invert(&dstToPts)) {
+ return false;
+ }
+
+ const auto dstToUnit = SkMatrix::Concat(fPtsToUnit, dstToPts);
+
+ auto* m = alloc->makeArrayDefault<float>(9);
+ if (dstToUnit.asAffine(m)) {
+ // TODO: mapping y is not needed; split the matrix stages to save some math?
+ p->append(SkRasterPipeline::matrix_2x3, m);
+ } else {
+ dstToUnit.get9(m);
+ p->append(SkRasterPipeline::matrix_perspective, m);
+ }
+
+ // TODO: clamp/repeat/mirror const 1f stages?
+ auto* limit = alloc->make<float>(1.0f);
+
+ switch (fTileMode) {
+ case kClamp_TileMode:
+ *limit += 0.5f; // why is clamp_x offsetting its limit?
+ p->append(SkRasterPipeline::clamp_x, limit);
+ break;
+ case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x, limit); break;
+ case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x, limit); break;
+ }
+
+ const bool premulGrad = fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag;
+ const SkColor4f c0 = to_colorspace(fOrigColors4f[0], fColorSpace.get(), cs),
+ c1 = to_colorspace(fOrigColors4f[1], fColorSpace.get(), cs);
+ const SkPM4f pmc0 = premulGrad ? c0.premul() : SkPM4f::From4f(Sk4f::Load(&c0)),
+ pmc1 = premulGrad ? c1.premul() : SkPM4f::From4f(Sk4f::Load(&c1));
+
+ auto* c0_and_dc = alloc->makeArrayDefault<SkPM4f>(2);
+ c0_and_dc[0] = pmc0;
+ c0_and_dc[1] = SkPM4f::From4f(pmc1.to4f() - pmc0.to4f());
+
+ p->append(SkRasterPipeline::linear_gradient_2stops, c0_and_dc);
+
+ if (!premulGrad && !this->colorsAreOpaque()) {
+ p->append(SkRasterPipeline::premul);
+ }
+
+ return true;
+}
+
// This swizzles SkColor into the same component order as SkPMColor, but does not actually
// "pre" multiply the color components.
//