aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/effects
diff options
context:
space:
mode:
Diffstat (limited to 'src/effects')
-rw-r--r--src/effects/gradients/SkGradientShader.cpp155
-rw-r--r--src/effects/gradients/SkGradientShaderPriv.h34
-rw-r--r--src/effects/gradients/SkLinearGradient.cpp167
-rw-r--r--src/effects/gradients/SkLinearGradient.h6
-rw-r--r--src/effects/gradients/SkRadialGradient.cpp9
-rw-r--r--src/effects/gradients/SkRadialGradient.h3
-rw-r--r--src/effects/gradients/SkSweepGradient.cpp146
-rw-r--r--src/effects/gradients/SkSweepGradient.h6
-rw-r--r--src/effects/gradients/SkTwoPointConicalGradient.cpp9
-rw-r--r--src/effects/gradients/SkTwoPointConicalGradient.h3
10 files changed, 219 insertions, 319 deletions
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 276eaac8ed..03048dbd70 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -12,8 +12,8 @@
#include "SkLinearGradient.h"
#include "SkMallocPixelRef.h"
#include "SkRadialGradient.h"
-#include "SkTwoPointConicalGradient.h"
#include "SkSweepGradient.h"
+#include "SkTwoPointConicalGradient.h"
enum GradientSerializationFlags {
// Bits 29:31 used for various boolean flags
@@ -347,6 +347,155 @@ void SkGradientShaderBase::FlipGradientColors(SkColor* colorDst, Rec* recDst,
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
+{
+ // Local matrix not supported currently. Remove once we have a generic RP wrapper.
+ if (localM || !getLocalMatrix().isIdentity()) {
+ return false;
+ }
+
+ SkMatrix matrix;
+ if (!ctm.invert(&matrix)) {
+ return false;
+ }
+
+ SkRasterPipeline p;
+ if (!this->adjustMatrixAndAppendStages(alloc, &matrix, &p)) {
+ return false;
+ }
+
+ auto* m = alloc->makeArrayDefault<float>(9);
+ if (matrix.asAffine(m)) {
+ // TODO: mapping y is not needed; split the matrix stages to save some math?
+ pipeline->append(SkRasterPipeline::matrix_2x3, m);
+ } else {
+ matrix.get9(m);
+ pipeline->append(SkRasterPipeline::matrix_perspective, m);
+ }
+
+ pipeline->extend(p);
+
+ const bool premulGrad = fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag;
+ auto prepareColor = [premulGrad, dstCS, this](int i) {
+ SkColor4f c = dstCS ? to_colorspace(fOrigColors4f[i], fColorSpace.get(), dstCS)
+ : SkColor4f_from_SkColor(fOrigColors[i], nullptr);
+ return premulGrad ? c.premul()
+ : SkPM4f::From4f(Sk4f::Load(&c));
+ };
+
+ // The two-stop case with stops at 0 and 1.
+ if (fColorCount == 2 && fOrigPos == nullptr) {
+ const SkPM4f c_l = prepareColor(0),
+ c_r = prepareColor(1);
+
+ // See F and B below.
+ auto* f_and_b = alloc->makeArrayDefault<SkPM4f>(2);
+ 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);
+ } else {
+
+ struct Stop { float t; SkPM4f f, b; };
+ struct Ctx { size_t n; Stop* stops; SkPM4f start; };
+
+ auto* ctx = alloc->make<Ctx>();
+ ctx->start = prepareColor(0);
+
+ // For each stop we calculate a bias B and a scale factor F, such that
+ // for any t between stops n and n+1, the color we want is B[n] + F[n]*t.
+ auto init_stop = [](float t_l, float t_r, SkPM4f c_l, SkPM4f c_r, Stop *stop) {
+ auto F = SkPM4f::From4f((c_r.to4f() - c_l.to4f()) / (t_r - t_l));
+ auto B = SkPM4f::From4f(c_l.to4f() - (F.to4f() * t_l));
+ *stop = {t_l, F, B};
+ };
+
+ if (fOrigPos == nullptr) {
+ // Handle evenly distributed stops.
+
+ float dt = 1.0f / (fColorCount - 1);
+ // In the evenly distributed case, fColorCount is the number of stops. There are no
+ // dummy entries.
+ auto* stopsArray = alloc->makeArrayDefault<Stop>(fColorCount);
+
+ float t_l = 0;
+ SkPM4f c_l = ctx->start;
+ for (int i = 0; i < fColorCount - 1; i++) {
+ // Use multiply instead of accumulating error using repeated addition.
+ float t_r = (i + 1) * dt;
+ SkPM4f c_r = prepareColor(i + 1);
+ init_stop(t_l, t_r, c_l, c_r, &stopsArray[i]);
+
+ t_l = t_r;
+ c_l = c_r;
+ }
+
+ // Force the last stop.
+ stopsArray[fColorCount - 1].t = 1;
+ stopsArray[fColorCount - 1].f = SkPM4f::From4f(Sk4f{0});
+ stopsArray[fColorCount - 1].b = prepareColor(fColorCount - 1);
+
+ ctx->n = fColorCount;
+ ctx->stops = stopsArray;
+ } else {
+ // Handle arbitrary stops.
+
+ // Remove the dummy stops inserted by SkGradientShaderBase::SkGradientShaderBase
+ // because they are naturally handled by the search method.
+ int firstStop;
+ int lastStop;
+ if (fColorCount > 2) {
+ firstStop = fOrigColors4f[0] != fOrigColors4f[1] ? 0 : 1;
+ lastStop = fOrigColors4f[fColorCount - 2] != fOrigColors4f[fColorCount - 1]
+ ? fColorCount - 1 : fColorCount - 2;
+ } else {
+ firstStop = 0;
+ lastStop = 1;
+ }
+ int realCount = lastStop - firstStop + 1;
+
+ // This is the maximum number of stops. There may be fewer stops because the duplicate
+ // points of hard stops are removed.
+ auto* stopsArray = alloc->makeArrayDefault<Stop>(realCount);
+
+ size_t stopCount = 0;
+ float t_l = fOrigPos[firstStop];
+ SkPM4f c_l = prepareColor(firstStop);
+ // N.B. lastStop is the index of the last stop, not one after.
+ for (int i = firstStop; i < lastStop; i++) {
+ float t_r = fOrigPos[i + 1];
+ SkPM4f c_r = prepareColor(i + 1);
+ if (t_l < t_r) {
+ init_stop(t_l, t_r, c_l, c_r, &stopsArray[stopCount]);
+ stopCount += 1;
+ }
+ t_l = t_r;
+ c_l = c_r;
+ }
+
+ stopsArray[stopCount].t = fOrigPos[lastStop];
+ stopsArray[stopCount].f = SkPM4f::From4f(Sk4f{0});
+ stopsArray[stopCount].b = prepareColor(lastStop);
+ stopCount += 1;
+
+ ctx->n = stopCount;
+ ctx->stops = stopsArray;
+ }
+
+ pipeline->append(SkRasterPipeline::linear_gradient, ctx);
+ }
+
+ if (!premulGrad && !this->colorsAreOpaque()) {
+ pipeline->append(SkRasterPipeline::premul);
+ }
+
+ return true;
+}
+
+
bool SkGradientShaderBase::isOpaque() const {
return fColorsAreOpaque;
}
@@ -1173,7 +1322,7 @@ GrGradientEffect::ColorType GrGradientEffect::determineColorType(
} else if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) &&
SkScalarNearlyEqual(shader.fOrigPos[1], 1.0f) &&
SkScalarNearlyEqual(shader.fOrigPos[2], 1.0f)) {
-
+
return kHardStopRightEdged_ColorType;
}
}
@@ -1369,7 +1518,7 @@ uint32_t GrGradientEffect::GLSLProcessor::GenBaseGradientKey(const GrProcessor&
} else if (GrGradientEffect::kHardStopRightEdged_ColorType == e.getColorType()) {
key |= kHardStopZeroOneOneKey;
}
-
+
if (SkShader::TileMode::kClamp_TileMode == e.fTileMode) {
key |= kClampTileMode;
} else if (SkShader::TileMode::kRepeat_TileMode == e.fTileMode) {
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 0feb44bfc8..8c188de39b 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -17,6 +17,8 @@
#include "SkColorPriv.h"
#include "SkColorSpace.h"
#include "SkOnce.h"
+#include "SkPM4fPriv.h"
+#include "SkRasterPipeline.h"
#include "SkReadBuffer.h"
#include "SkShader.h"
#include "SkUtils.h"
@@ -201,28 +203,21 @@ public:
uint32_t getGradFlags() const { return fGradFlags; }
protected:
+ struct Rec {
+ SkFixed fPos; // 0...1
+ uint32_t fScale; // (1 << 24) / range
+ };
+
class GradientShaderBase4fContext;
SkGradientShaderBase(SkReadBuffer& );
void flatten(SkWriteBuffer&) const override;
SK_TO_STRING_OVERRIDE()
- const SkMatrix fPtsToUnit;
- TileMode fTileMode;
- TileProc fTileProc;
- uint8_t fGradFlags;
-
- struct Rec {
- SkFixed fPos; // 0...1
- uint32_t fScale; // (1 << 24) / range
- };
- Rec* fRecs;
-
void commonAsAGradient(GradientInfo*, bool flipGrad = false) const;
bool onAsLuminanceColor(SkColor*) const override;
-
void initLinearBitmap(SkBitmap* bitmap) const;
/*
@@ -236,6 +231,14 @@ protected:
SkColor* colorSrc, Rec* recSrc,
int count);
+ bool onAppendStages(SkRasterPipeline* pipeline, SkColorSpace* dstCS, SkArenaAlloc* alloc,
+ const SkMatrix& ctm, const SkPaint& paint,
+ const SkMatrix* localM) const override;
+
+ virtual bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
+ SkMatrix* matrix,
+ SkRasterPipeline* p) const { return false; }
+
template <typename T, typename... Args>
static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {
auto* ctx = alloc->make<T>(std::forward<Args>(args)...);
@@ -245,6 +248,12 @@ protected:
return ctx;
}
+ const SkMatrix fPtsToUnit;
+ TileMode fTileMode;
+ TileProc fTileProc;
+ uint8_t fGradFlags;
+ Rec* fRecs;
+
private:
enum {
kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
@@ -277,6 +286,7 @@ private:
typedef SkShader INHERITED;
};
+
static inline int init_dither_toggle(int x, int y) {
x &= 1;
y = (y & 1) << 1;
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index 24cb1b592d..0b51da1ec1 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -83,178 +83,31 @@ SkShader::Context* SkLinearGradient::onMakeContext(
: CheckedMakeContext< LinearGradientContext>(alloc, *this, rec);
}
-//
-// Stages:
-//
-// * matrix (map dst -> grad space)
-// * clamp/repeat/mirror (tiling)
-// * linear_gradient_2stops (lerp c0/c1)
-// * optional premul
-//
-bool SkLinearGradient::onAppendStages(SkRasterPipeline* p,
- SkColorSpace* dstCS,
- SkArenaAlloc* alloc,
- const SkMatrix& ctm,
- const SkPaint& paint,
- const SkMatrix* localM) const {
- // Local matrix not supported currently. Remove once we have a generic RP wrapper.
- if (localM || !getLocalMatrix().isIdentity()) {
- return false;
- }
-
- SkMatrix dstToPts;
- if (!ctm.invert(&dstToPts)) {
- return false;
- }
-
- const auto dstToUnit = SkMatrix::Concat(fPtsToUnit, dstToPts);
-
- // If the gradient is less than a quarter of a pixel, this falls into the subpixel gradient code
- // handled on a different path.
- SkVector dx = dstToUnit.mapVector(1, 0);
- if (dx.fX >= 4) {
- return false;
- }
-
- 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);
- }
+bool SkLinearGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
+ SkMatrix* matrix,
+ SkRasterPipeline* p) const {
+ *matrix = SkMatrix::Concat(fPtsToUnit, *matrix);
+ // If the gradient is less than a quarter of a pixel, this falls into the
+ // subpixel gradient code handled on a different path.
+ SkVector dx = matrix->mapVector(1, 0);
+ if (dx.fX >= 4) { return false; }
- // TODO: clamp/repeat/mirror const 1f stages?
auto* limit = alloc->make<float>(1.0f);
-
- const bool premulGrad = fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag;
- auto prepareColor = [premulGrad, dstCS, this](int i) {
- SkColor4f c = dstCS ? to_colorspace(fOrigColors4f[i], fColorSpace.get(), dstCS)
- : SkColor4f_from_SkColor(fOrigColors[i], nullptr);
- return premulGrad ? c.premul()
- : SkPM4f::From4f(Sk4f::Load(&c));
- };
-
- // The two-stop case with stops at 0 and 1.
if (fColorCount == 2 && fOrigPos == nullptr) {
switch (fTileMode) {
- case kClamp_TileMode: p->append(SkRasterPipeline:: clamp_x, limit); break;
+ case kClamp_TileMode: 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 SkPM4f c_l = prepareColor(0),
- c_r = prepareColor(1);
-
- // See F and B below.
- auto* f_and_b = alloc->makeArrayDefault<SkPM4f>(2);
- f_and_b[0] = SkPM4f::From4f(c_r.to4f() - c_l.to4f());
- f_and_b[1] = c_l;
-
- p->append(SkRasterPipeline::linear_gradient_2stops, f_and_b);
} else {
switch (fTileMode) {
// The search strategy does not need clamping. It has implicit hard stops at the
// first and last stop.
- case kClamp_TileMode: break;
+ case kClamp_TileMode: break;
case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x, limit); break;
case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x, limit); break;
}
-
- struct Stop { float t; SkPM4f f, b; };
- struct Ctx { size_t n; Stop* stops; SkPM4f start; };
-
- auto* ctx = alloc->make<Ctx>();
- ctx->start = prepareColor(0);
-
- // For each stop we calculate a bias B and a scale factor F, such that
- // for any t between stops n and n+1, the color we want is B[n] + F[n]*t.
- auto init_stop = [](float t_l, float t_r, SkPM4f c_l, SkPM4f c_r, Stop *stop) {
- auto F = SkPM4f::From4f((c_r.to4f() - c_l.to4f()) / (t_r - t_l));
- auto B = SkPM4f::From4f(c_l.to4f() - (F.to4f() * t_l));
- *stop = {t_l, F, B};
- };
-
- if (fOrigPos == nullptr) {
- // Handle evenly distributed stops.
-
- float dt = 1.0f / (fColorCount - 1);
- // In the evenly distributed case, fColorCount is the number of stops. There are no
- // dummy entries.
- auto* stopsArray = alloc->makeArrayDefault<Stop>(fColorCount);
-
- float t_l = 0;
- SkPM4f c_l = ctx->start;
- for (int i = 0; i < fColorCount - 1; i++) {
- // Use multiply instead of accumulating error using repeated addition.
- float t_r = (i + 1) * dt;
- SkPM4f c_r = prepareColor(i + 1);
- init_stop(t_l, t_r, c_l, c_r, &stopsArray[i]);
-
- t_l = t_r;
- c_l = c_r;
- }
-
- // Force the last stop.
- stopsArray[fColorCount - 1].t = 1;
- stopsArray[fColorCount - 1].f = SkPM4f::From4f(Sk4f{0});
- stopsArray[fColorCount - 1].b = prepareColor(fColorCount - 1);
-
- ctx->n = fColorCount;
- ctx->stops = stopsArray;
- } else {
- // Handle arbitrary stops.
-
- // Remove the dummy stops inserted by SkGradientShaderBase::SkGradientShaderBase
- // because they are naturally handled by the search method.
- int firstStop;
- int lastStop;
- if (fColorCount > 2) {
- firstStop = fOrigColors4f[0] != fOrigColors4f[1] ? 0 : 1;
- lastStop = fOrigColors4f[fColorCount - 2] != fOrigColors4f[fColorCount - 1]
- ? fColorCount - 1 : fColorCount - 2;
- } else {
- firstStop = 0;
- lastStop = 1;
- }
- int realCount = lastStop - firstStop + 1;
-
- // This is the maximum number of stops. There may be fewer stops because the duplicate
- // points of hard stops are removed.
- auto* stopsArray = alloc->makeArrayDefault<Stop>(realCount);
-
- size_t stopCount = 0;
- float t_l = fOrigPos[firstStop];
- SkPM4f c_l = prepareColor(firstStop);
- // N.B. lastStop is the index of the last stop, not one after.
- for (int i = firstStop; i < lastStop; i++) {
- float t_r = fOrigPos[i + 1];
- SkPM4f c_r = prepareColor(i + 1);
- if (t_l < t_r) {
- init_stop(t_l, t_r, c_l, c_r, &stopsArray[stopCount]);
- stopCount += 1;
- }
- t_l = t_r;
- c_l = c_r;
- }
-
- stopsArray[stopCount].t = fOrigPos[lastStop];
- stopsArray[stopCount].f = SkPM4f::From4f(Sk4f{0});
- stopsArray[stopCount].b = prepareColor(lastStop);
- stopCount += 1;
-
- ctx->n = stopCount;
- ctx->stops = stopsArray;
- }
-
- p->append(SkRasterPipeline::linear_gradient, ctx);
- }
-
- if (!premulGrad && !this->colorsAreOpaque()) {
- p->append(SkRasterPipeline::premul);
}
-
return true;
}
diff --git a/src/effects/gradients/SkLinearGradient.h b/src/effects/gradients/SkLinearGradient.h
index f860568147..19a965c7bb 100644
--- a/src/effects/gradients/SkLinearGradient.h
+++ b/src/effects/gradients/SkLinearGradient.h
@@ -68,8 +68,10 @@ protected:
void flatten(SkWriteBuffer& buffer) const override;
Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
- bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*,
- const SkMatrix&, const SkPaint&, const SkMatrix*) const override;
+ bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
+ SkMatrix* matrix,
+ SkRasterPipeline* p) const final;
+
sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index 71cdb9fe17..6a1a19f001 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -393,3 +393,12 @@ void SkRadialGradient::toString(SkString* str) const {
str->append(")");
}
#endif
+
+bool SkRadialGradient::onAppendStages(SkRasterPipeline* p,
+ SkColorSpace* dstCS,
+ SkArenaAlloc* alloc,
+ const SkMatrix& ctm,
+ const SkPaint& paint,
+ const SkMatrix* localM) const {
+ return SkShader::onAppendStages(p, dstCS, alloc, ctm, paint, localM);
+}
diff --git a/src/effects/gradients/SkRadialGradient.h b/src/effects/gradients/SkRadialGradient.h
index c43df09146..df1badd5ac 100644
--- a/src/effects/gradients/SkRadialGradient.h
+++ b/src/effects/gradients/SkRadialGradient.h
@@ -38,6 +38,9 @@ protected:
Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
+ bool onAppendStages(SkRasterPipeline*, SkColorSpace* dstCS, SkArenaAlloc*,
+ const SkMatrix& ctm, const SkPaint&, const SkMatrix* localM) const override;
+
private:
const SkPoint fCenter;
const SkScalar fRadius;
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index 81fdfe481b..b3a24cd16e 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -311,150 +311,12 @@ void SkSweepGradient::toString(SkString* str) const {
str->append(")");
}
-bool SkSweepGradient::onAppendStages(SkRasterPipeline* p,
- SkColorSpace* dstCS,
- SkArenaAlloc* alloc,
- const SkMatrix& ctm,
- const SkPaint& paint,
- const SkMatrix* localM) const {
- // Local matrix not supported currently. Remove once we have a generic RP wrapper.
- if (localM || !getLocalMatrix().isIdentity()) {
- return false;
- }
-
- SkMatrix dstToSrc;
- if (!ctm.invert(&dstToSrc)) {
- return false;
- }
-
- const auto dstToCenter = SkMatrix::Concat(
- SkMatrix::MakeTrans(-fCenter.fX, -fCenter.fY), dstToSrc);
-
- auto* m = alloc->makeArrayDefault<float>(9);
- if (dstToCenter.asAffine(m)) {
- // TODO: mapping y is not needed; split the matrix stages to save some math?
- p->append(SkRasterPipeline::matrix_2x3, m);
- } else {
- dstToCenter.get9(m);
- p->append(SkRasterPipeline::matrix_perspective, m);
- }
-
+bool SkSweepGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
+ SkMatrix* matrix,
+ SkRasterPipeline* p) const {
+ matrix->postTranslate(-fCenter.fX, -fCenter.fY);
p->append(SkRasterPipeline::xy_to_polar_unit);
- const bool premulGrad = fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag;
- auto prepareColor = [premulGrad, dstCS, this](int i) {
- SkColor4f c = dstCS ? to_colorspace(fOrigColors4f[i], fColorSpace.get(), dstCS)
- : SkColor4f_from_SkColor(fOrigColors[i], nullptr);
- return premulGrad ? c.premul()
- : SkPM4f::From4f(Sk4f::Load(&c));
- };
-
- // The two-stop case with stops at 0 and 1.
- if (fColorCount == 2 && fOrigPos == nullptr) {
- const SkPM4f c_l = prepareColor(0),
- c_r = prepareColor(1);
-
- // See F and B below.
- auto* f_and_b = alloc->makeArrayDefault<SkPM4f>(2);
- f_and_b[0] = SkPM4f::From4f(c_r.to4f() - c_l.to4f());
- f_and_b[1] = c_l;
-
- p->append(SkRasterPipeline::linear_gradient_2stops, f_and_b);
- } else {
-
- struct Stop { float t; SkPM4f f, b; };
- struct Ctx { size_t n; Stop* stops; SkPM4f start; };
-
- auto* ctx = alloc->make<Ctx>();
- ctx->start = prepareColor(0);
-
- // For each stop we calculate a bias B and a scale factor F, such that
- // for any t between stops n and n+1, the color we want is B[n] + F[n]*t.
- auto init_stop = [](float t_l, float t_r, SkPM4f c_l, SkPM4f c_r, Stop *stop) {
- auto F = SkPM4f::From4f((c_r.to4f() - c_l.to4f()) / (t_r - t_l));
- auto B = SkPM4f::From4f(c_l.to4f() - (F.to4f() * t_l));
- *stop = {t_l, F, B};
- };
-
- if (fOrigPos == nullptr) {
- // Handle evenly distributed stops.
-
- float dt = 1.0f / (fColorCount - 1);
- // In the evenly distributed case, fColorCount is the number of stops. There are no
- // dummy entries.
- auto* stopsArray = alloc->makeArrayDefault<Stop>(fColorCount);
-
- float t_l = 0;
- SkPM4f c_l = ctx->start;
- for (int i = 0; i < fColorCount - 1; i++) {
- // Use multiply instead of accumulating error using repeated addition.
- float t_r = (i + 1) * dt;
- SkPM4f c_r = prepareColor(i + 1);
- init_stop(t_l, t_r, c_l, c_r, &stopsArray[i]);
-
- t_l = t_r;
- c_l = c_r;
- }
-
- // Force the last stop.
- stopsArray[fColorCount - 1].t = 1;
- stopsArray[fColorCount - 1].f = SkPM4f::From4f(Sk4f{0});
- stopsArray[fColorCount - 1].b = prepareColor(fColorCount - 1);
-
- ctx->n = fColorCount;
- ctx->stops = stopsArray;
- } else {
- // Handle arbitrary stops.
-
- // Remove the dummy stops inserted by SkGradientShaderBase::SkGradientShaderBase
- // because they are naturally handled by the search method.
- int firstStop;
- int lastStop;
- if (fColorCount > 2) {
- firstStop = fOrigColors4f[0] != fOrigColors4f[1] ? 0 : 1;
- lastStop = fOrigColors4f[fColorCount - 2] != fOrigColors4f[fColorCount - 1]
- ? fColorCount - 1 : fColorCount - 2;
- } else {
- firstStop = 0;
- lastStop = 1;
- }
- int realCount = lastStop - firstStop + 1;
-
- // This is the maximum number of stops. There may be fewer stops because the duplicate
- // points of hard stops are removed.
- auto* stopsArray = alloc->makeArrayDefault<Stop>(realCount);
-
- size_t stopCount = 0;
- float t_l = fOrigPos[firstStop];
- SkPM4f c_l = prepareColor(firstStop);
- // N.B. lastStop is the index of the last stop, not one after.
- for (int i = firstStop; i < lastStop; i++) {
- float t_r = fOrigPos[i + 1];
- SkPM4f c_r = prepareColor(i + 1);
- if (t_l < t_r) {
- init_stop(t_l, t_r, c_l, c_r, &stopsArray[stopCount]);
- stopCount += 1;
- }
- t_l = t_r;
- c_l = c_r;
- }
-
- stopsArray[stopCount].t = fOrigPos[lastStop];
- stopsArray[stopCount].f = SkPM4f::From4f(Sk4f{0});
- stopsArray[stopCount].b = prepareColor(lastStop);
- stopCount += 1;
-
- ctx->n = stopCount;
- ctx->stops = stopsArray;
- }
-
- p->append(SkRasterPipeline::linear_gradient, ctx);
- }
-
- if (!premulGrad && !this->colorsAreOpaque()) {
- p->append(SkRasterPipeline::premul);
- }
-
return true;
}
diff --git a/src/effects/gradients/SkSweepGradient.h b/src/effects/gradients/SkSweepGradient.h
index 45c4233d88..5f12744b4d 100644
--- a/src/effects/gradients/SkSweepGradient.h
+++ b/src/effects/gradients/SkSweepGradient.h
@@ -38,9 +38,9 @@ protected:
Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
- bool onAppendStages(SkRasterPipeline* pipeline, SkColorSpace* space, SkArenaAlloc* alloc,
- const SkMatrix& matrix, const SkPaint& paint,
- const SkMatrix* localM) const override;
+ bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
+ SkMatrix* matrix,
+ SkRasterPipeline* p) const final;
private:
const SkPoint fCenter;
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index ced299ee23..bc97700827 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -419,3 +419,12 @@ void SkTwoPointConicalGradient::toString(SkString* str) const {
str->append(")");
}
#endif
+
+bool SkTwoPointConicalGradient::onAppendStages(SkRasterPipeline* p,
+ SkColorSpace* dstCS,
+ SkArenaAlloc* alloc,
+ const SkMatrix& ctm,
+ const SkPaint& paint,
+ const SkMatrix* localM) const {
+ return SkShader::onAppendStages(p, dstCS, alloc, ctm, paint, localM);
+}
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.h b/src/effects/gradients/SkTwoPointConicalGradient.h
index b32f52c1e0..d5de47eb9a 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.h
+++ b/src/effects/gradients/SkTwoPointConicalGradient.h
@@ -79,6 +79,9 @@ protected:
Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
+ bool onAppendStages(SkRasterPipeline*, SkColorSpace* dstCS, SkArenaAlloc*,
+ const SkMatrix& ctm, const SkPaint&, const SkMatrix* localM) const override;
+
private:
SkPoint fCenter1;
SkPoint fCenter2;