diff options
Diffstat (limited to 'src/effects/gradients')
-rw-r--r-- | src/effects/gradients/SkLinearGradient.cpp | 70 | ||||
-rw-r--r-- | src/effects/gradients/SkLinearGradient.h | 3 |
2 files changed, 73 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. // diff --git a/src/effects/gradients/SkLinearGradient.h b/src/effects/gradients/SkLinearGradient.h index 7a85b88cb7..acf9c21ec0 100644 --- a/src/effects/gradients/SkLinearGradient.h +++ b/src/effects/gradients/SkLinearGradient.h @@ -69,6 +69,9 @@ protected: size_t onContextSize(const ContextRec&) const override; Context* onCreateContext(const ContextRec&, void* storage) const override; + bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + const SkMatrix&, const SkPaint&) const override; + private: class LinearGradient4fContext; |