Revert "Factor out common code from sweep and linear."
This reverts commit b7a330ff0048875e178b2d9a68cd5605d83baf8d.
Reason for revert: Oof, I hate to do this, but we didn't expect this to change any drawing did we? This draws a bunch of GMs differently in both 565 and sRGB mode, some very noticeably.
Original change's description:
> Factor out common code from sweep and linear.
>
> And, some file cleanup.
>
> Change-Id: I804db924bce3b5834f6cda481315dd2da38df5ca
> Reviewed-on: https://skia-review.googlesource.com/15226
> Commit-Queue: Herb Derby <herb@google.com>
> Reviewed-by: Mike Klein <mtklein@chromium.org>
> Reviewed-by: Florin Malita <fmalita@chromium.org>
>
TBR=mtklein@chromium.org,mtklein@google.com,herb@google.com,fmalita@chromium.org,fmalita@google.com
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
Change-Id: I75bb6c3e4045a0f70c7e9552b84b22f0fed73b80
Reviewed-on: https://skia-review.googlesource.com/15464
Reviewed-by: Mike Klein <mtklein@chromium.org>
Commit-Queue: Mike Klein <mtklein@chromium.org>
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 03048db..276eaac 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 "SkSweepGradient.h"
#include "SkTwoPointConicalGradient.h"
+#include "SkSweepGradient.h"
enum GradientSerializationFlags {
// Bits 29:31 used for various boolean flags
@@ -347,155 +347,6 @@
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;
}
@@ -1322,7 +1173,7 @@
} else if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) &&
SkScalarNearlyEqual(shader.fOrigPos[1], 1.0f) &&
SkScalarNearlyEqual(shader.fOrigPos[2], 1.0f)) {
-
+
return kHardStopRightEdged_ColorType;
}
}
@@ -1518,7 +1369,7 @@
} 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 c1e9c93..0feb44b 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -17,8 +17,6 @@
#include "SkColorPriv.h"
#include "SkColorSpace.h"
#include "SkOnce.h"
-#include "SkPM4fPriv.h"
-#include "SkRasterPipeline.h"
#include "SkReadBuffer.h"
#include "SkShader.h"
#include "SkUtils.h"
@@ -203,21 +201,28 @@
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;
/*
@@ -231,14 +236,6 @@
SkColor* colorSrc, Rec* recSrc,
int count);
- bool onAppendStages(SkRasterPipeline* pipeline, SkColorSpace* dstCS, SkArenaAlloc* alloc,
- const SkMatrix& ctm, const SkPaint& paint,
- const SkMatrix* localM) const final;
-
- virtual bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
- SkMatrix* matrix,
- SkRasterPipeline* p) const = 0;
-
template <typename T, typename... Args>
static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {
auto* ctx = alloc->make<T>(std::forward<Args>(args)...);
@@ -248,12 +245,6 @@
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
@@ -286,7 +277,6 @@
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 0b51da1..24cb1b5 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -83,31 +83,178 @@
: CheckedMakeContext< LinearGradientContext>(alloc, *this, rec);
}
-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; }
+//
+// 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);
+ }
+
+ // 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 19a965c..f860568 100644
--- a/src/effects/gradients/SkLinearGradient.h
+++ b/src/effects/gradients/SkLinearGradient.h
@@ -68,10 +68,8 @@
void flatten(SkWriteBuffer& buffer) const override;
Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
- bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
- SkMatrix* matrix,
- SkRasterPipeline* p) const final;
-
+ bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*,
+ const SkMatrix&, const SkPaint&, const SkMatrix*) const override;
sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
diff --git a/src/effects/gradients/SkRadialGradient.h b/src/effects/gradients/SkRadialGradient.h
index f91f343..c43df09 100644
--- a/src/effects/gradients/SkRadialGradient.h
+++ b/src/effects/gradients/SkRadialGradient.h
@@ -38,12 +38,6 @@
Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
- bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
- SkMatrix* matrix,
- SkRasterPipeline* p) const final {
- return false;
- }
-
private:
const SkPoint fCenter;
const SkScalar fRadius;
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index b3a24cd..81fdfe4 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -311,12 +311,150 @@
str->append(")");
}
-bool SkSweepGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
- SkMatrix* matrix,
- SkRasterPipeline* p) const {
- matrix->postTranslate(-fCenter.fX, -fCenter.fY);
+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);
+ }
+
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 5f12744..45c4233 100644
--- a/src/effects/gradients/SkSweepGradient.h
+++ b/src/effects/gradients/SkSweepGradient.h
@@ -38,9 +38,9 @@
Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
- bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
- SkMatrix* matrix,
- SkRasterPipeline* p) const final;
+ bool onAppendStages(SkRasterPipeline* pipeline, SkColorSpace* space, SkArenaAlloc* alloc,
+ const SkMatrix& matrix, const SkPaint& paint,
+ const SkMatrix* localM) const override;
private:
const SkPoint fCenter;
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.h b/src/effects/gradients/SkTwoPointConicalGradient.h
index d24dbd4..b32f52c 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.h
+++ b/src/effects/gradients/SkTwoPointConicalGradient.h
@@ -78,11 +78,6 @@
void flatten(SkWriteBuffer& buffer) const override;
Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
- bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
- SkMatrix* matrix,
- SkRasterPipeline* p) const final {
- return false;
- }
private:
SkPoint fCenter1;