aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/shaders
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2017-06-05 23:33:45 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-06-06 15:54:45 +0000
commit0e36b3f9307a90f65b7f5e351818223bcb1b64a9 (patch)
treef1f50003dd64d340de02556b01385c5cbb63e35c /src/shaders
parent6b3542aeb0780e7e3dd1a1e0493164f27add9827 (diff)
Add color space support to 4f gradients
Similar to the raster pipeline stage, transform the stops into the dest color space before interpolation. Change-Id: I626b6ef18606fd2308d7da166ce70d05f3951e21 Reviewed-on: https://skia-review.googlesource.com/18767 Reviewed-by: Florin Malita <fmalita@chromium.org> Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'src/shaders')
-rw-r--r--src/shaders/gradients/Sk4fGradientBase.cpp85
-rw-r--r--src/shaders/gradients/Sk4fGradientBase.h4
-rw-r--r--src/shaders/gradients/Sk4fLinearGradient.cpp2
-rw-r--r--src/shaders/gradients/SkGradientShader.cpp8
-rw-r--r--src/shaders/gradients/SkGradientShaderPriv.h2
5 files changed, 56 insertions, 45 deletions
diff --git a/src/shaders/gradients/Sk4fGradientBase.cpp b/src/shaders/gradients/Sk4fGradientBase.cpp
index e20f5f4702..bf884ac476 100644
--- a/src/shaders/gradients/Sk4fGradientBase.cpp
+++ b/src/shaders/gradients/Sk4fGradientBase.cpp
@@ -11,8 +11,7 @@
namespace {
-Sk4f pack_color(SkColor c, bool premul, const Sk4f& component_scale) {
- const SkColor4f c4f = SkColor4f::FromColor(c);
+Sk4f pack_color(const SkColor4f& c4f, bool premul, const Sk4f& component_scale) {
const Sk4f pm4f = premul
? c4f.premul().to4f()
: Sk4f{c4f.fR, c4f.fG, c4f.fB, c4f.fA};
@@ -22,40 +21,40 @@ Sk4f pack_color(SkColor c, bool premul, const Sk4f& component_scale) {
class IntervalIterator {
public:
- IntervalIterator(const SkColor* colors, const SkScalar* pos, int count, bool reverse)
- : fColors(colors)
- , fPos(pos)
- , fCount(count)
+ IntervalIterator(const SkGradientShaderBase& shader, SkColorSpace* dstCS, bool reverse)
+ : fShader(shader)
+ , fDstCS(dstCS)
, fFirstPos(reverse ? SK_Scalar1 : 0)
- , fBegin(reverse ? count - 1 : 0)
+ , fBegin(reverse ? shader.fColorCount - 1 : 0)
, fAdvance(reverse ? -1 : 1) {
- SkASSERT(colors);
- SkASSERT(count > 0);
+ SkASSERT(shader.fColorCount > 0);
}
- void iterate(std::function<void(SkColor, SkColor, SkScalar, SkScalar)> func) const {
- if (!fPos) {
+ void iterate(std::function<void(const SkColor4f&, const SkColor4f&,
+ SkScalar, SkScalar)> func) const {
+ if (!fShader.fOrigPos) {
this->iterateImplicitPos(func);
return;
}
- const int end = fBegin + fAdvance * (fCount - 1);
+ const int end = fBegin + fAdvance * (fShader.fColorCount - 1);
const SkScalar lastPos = 1 - fFirstPos;
int prev = fBegin;
SkScalar prevPos = fFirstPos;
do {
const int curr = prev + fAdvance;
- SkASSERT(curr >= 0 && curr < fCount);
+ SkASSERT(curr >= 0 && curr < fShader.fColorCount);
// TODO: this sanitization should be done in SkGradientShaderBase
const SkScalar currPos = (fAdvance > 0)
- ? SkTPin(fPos[curr], prevPos, lastPos)
- : SkTPin(fPos[curr], lastPos, prevPos);
+ ? SkTPin(fShader.fOrigPos[curr], prevPos, lastPos)
+ : SkTPin(fShader.fOrigPos[curr], lastPos, prevPos);
if (currPos != prevPos) {
SkASSERT((currPos - prevPos > 0) == (fAdvance > 0));
- func(fColors[prev], fColors[curr], prevPos, currPos);
+ func(fShader.getXformedColor(prev, fDstCS), fShader.getXformedColor(curr, fDstCS),
+ prevPos, currPos);
}
prev = curr;
@@ -64,44 +63,48 @@ public:
}
private:
- void iterateImplicitPos(std::function<void(SkColor, SkColor, SkScalar, SkScalar)> func) const {
+ void iterateImplicitPos(std::function<void(const SkColor4f&, const SkColor4f&,
+ SkScalar, SkScalar)> func) const {
// When clients don't provide explicit color stop positions (fPos == nullptr),
// the color stops are distributed evenly across the unit interval
// (implicit positioning).
- const SkScalar dt = fAdvance * SK_Scalar1 / (fCount - 1);
- const int end = fBegin + fAdvance * (fCount - 2);
+ const SkScalar dt = fAdvance * SK_Scalar1 / (fShader.fColorCount - 1);
+ const int end = fBegin + fAdvance * (fShader.fColorCount - 2);
int prev = fBegin;
SkScalar prevPos = fFirstPos;
while (prev != end) {
const int curr = prev + fAdvance;
- SkASSERT(curr >= 0 && curr < fCount);
+ SkASSERT(curr >= 0 && curr < fShader.fColorCount);
const SkScalar currPos = prevPos + dt;
- func(fColors[prev], fColors[curr], prevPos, currPos);
+ func(fShader.getXformedColor(prev, fDstCS),
+ fShader.getXformedColor(curr, fDstCS),
+ prevPos, currPos);
prev = curr;
prevPos = currPos;
}
// emit the last interval with a pinned end position, to avoid precision issues
- func(fColors[prev], fColors[prev + fAdvance], prevPos, 1 - fFirstPos);
+ func(fShader.getXformedColor(prev, fDstCS),
+ fShader.getXformedColor(prev + fAdvance, fDstCS),
+ prevPos, 1 - fFirstPos);
}
- const SkColor* fColors;
- const SkScalar* fPos;
- const int fCount;
- const SkScalar fFirstPos;
- const int fBegin;
- const int fAdvance;
+ const SkGradientShaderBase& fShader;
+ SkColorSpace* fDstCS;
+ const SkScalar fFirstPos;
+ const int fBegin;
+ const int fAdvance;
};
-void addMirrorIntervals(const SkColor colors[],
- const SkScalar pos[], int count,
+void addMirrorIntervals(const SkGradientShaderBase& shader,
+ SkColorSpace* dstCS,
const Sk4f& componentScale,
bool premulColors, bool reverse,
Sk4fGradientIntervalBuffer::BufferType* buffer) {
- const IntervalIterator iter(colors, pos, count, reverse);
- iter.iterate([&] (SkColor c0, SkColor c1, SkScalar t0, SkScalar t1) {
+ const IntervalIterator iter(shader, dstCS, reverse);
+ iter.iterate([&] (const SkColor4f& c0, const SkColor4f& c1, SkScalar t0, SkScalar t1) {
SkASSERT(buffer->empty() || buffer->back().fT1 == 2 - t0);
const auto mirror_t0 = 2 - t0;
@@ -137,7 +140,7 @@ Sk4fGradientInterval::Sk4fGradientInterval(const Sk4f& c0, SkScalar t0,
dc.store(&fCg.fVec);
}
-void Sk4fGradientIntervalBuffer::init(const SkColor colors[], const SkScalar pos[], int count,
+void Sk4fGradientIntervalBuffer::init(const SkGradientShaderBase& shader, SkColorSpace* dstCS,
SkShader::TileMode tileMode, bool premulColors,
SkScalar alpha, bool reverse) {
// The main job here is to build a specialized interval list: a different
@@ -181,8 +184,9 @@ void Sk4fGradientIntervalBuffer::init(const SkColor colors[], const SkScalar pos
//
// TODO: investigate collapsing intervals << 1px.
+ const auto count = shader.fColorCount;
+
SkASSERT(count > 0);
- SkASSERT(colors);
fIntervals.reset();
@@ -196,18 +200,18 @@ void Sk4fGradientIntervalBuffer::init(const SkColor colors[], const SkScalar pos
if (tileMode == SkShader::kClamp_TileMode) {
// synthetic edge interval: -/+inf .. P0
- const Sk4f clamp_color = pack_color(colors[first_index],
+ const Sk4f clamp_color = pack_color(shader.getXformedColor(first_index, dstCS),
premulColors, componentScale);
const SkScalar clamp_pos = reverse ? SK_ScalarInfinity : SK_ScalarNegativeInfinity;
fIntervals.emplace_back(clamp_color, clamp_pos,
clamp_color, first_pos);
} else if (tileMode == SkShader::kMirror_TileMode && reverse) {
// synthetic mirror intervals injected before main intervals: (2 .. 1]
- addMirrorIntervals(colors, pos, count, componentScale, premulColors, false, &fIntervals);
+ addMirrorIntervals(shader, dstCS, componentScale, premulColors, false, &fIntervals);
}
- const IntervalIterator iter(colors, pos, count, reverse);
- iter.iterate([&] (SkColor c0, SkColor c1, SkScalar t0, SkScalar t1) {
+ const IntervalIterator iter(shader, dstCS, reverse);
+ iter.iterate([&] (const SkColor4f& c0, const SkColor4f& c1, SkScalar t0, SkScalar t1) {
SkASSERT(fIntervals.empty() || fIntervals.back().fT1 == t0);
fIntervals.emplace_back(pack_color(c0, premulColors, componentScale), t0,
@@ -216,13 +220,14 @@ void Sk4fGradientIntervalBuffer::init(const SkColor colors[], const SkScalar pos
if (tileMode == SkShader::kClamp_TileMode) {
// synthetic edge interval: Pn .. +/-inf
- const Sk4f clamp_color = pack_color(colors[last_index], premulColors, componentScale);
+ const Sk4f clamp_color = pack_color(shader.getXformedColor(last_index, dstCS),
+ premulColors, componentScale);
const SkScalar clamp_pos = reverse ? SK_ScalarNegativeInfinity : SK_ScalarInfinity;
fIntervals.emplace_back(clamp_color, last_pos,
clamp_color, clamp_pos);
} else if (tileMode == SkShader::kMirror_TileMode && !reverse) {
// synthetic mirror intervals injected after main intervals: [1 .. 2)
- addMirrorIntervals(colors, pos, count, componentScale, premulColors, true, &fIntervals);
+ addMirrorIntervals(shader, dstCS, componentScale, premulColors, true, &fIntervals);
}
}
diff --git a/src/shaders/gradients/Sk4fGradientBase.h b/src/shaders/gradients/Sk4fGradientBase.h
index a660d6bde5..bd0aab4203 100644
--- a/src/shaders/gradients/Sk4fGradientBase.h
+++ b/src/shaders/gradients/Sk4fGradientBase.h
@@ -37,8 +37,8 @@ struct Sk4fGradientInterval {
class Sk4fGradientIntervalBuffer {
public:
- void init(const SkColor colors[], const SkScalar pos[], int count,
- SkShader::TileMode tileMode, bool premulColors, SkScalar alpha, bool reverse);
+ void init(const SkGradientShaderBase&, SkColorSpace* dstCS, SkShader::TileMode tileMode,
+ bool premulColors, SkScalar alpha, bool reverse);
const Sk4fGradientInterval* find(SkScalar t) const;
const Sk4fGradientInterval* findNext(SkScalar t, const Sk4fGradientInterval* prev,
diff --git a/src/shaders/gradients/Sk4fLinearGradient.cpp b/src/shaders/gradients/Sk4fLinearGradient.cpp
index 7b7498eaef..202461cc22 100644
--- a/src/shaders/gradients/Sk4fLinearGradient.cpp
+++ b/src/shaders/gradients/Sk4fLinearGradient.cpp
@@ -92,7 +92,7 @@ LinearGradient4fContext::LinearGradient4fContext(const SkLinearGradient& shader,
// Our fast path expects interval points to be monotonically increasing in x.
const bool reverseIntervals = this->isFast() && std::signbit(fDstToPos.getScaleX());
- fIntervals.init(shader.fOrigColors, shader.fOrigPos, shader.fColorCount, shader.fTileMode,
+ fIntervals.init(shader, rec.fDstColorSpace, shader.fTileMode,
fColorsArePremul, rec.fPaint->getAlpha() * (1.0f / 255), reverseIntervals);
SkASSERT(fIntervals->count() > 0);
diff --git a/src/shaders/gradients/SkGradientShader.cpp b/src/shaders/gradients/SkGradientShader.cpp
index a34a35acb2..ab774f6b04 100644
--- a/src/shaders/gradients/SkGradientShader.cpp
+++ b/src/shaders/gradients/SkGradientShader.cpp
@@ -449,8 +449,7 @@ bool SkGradientShaderBase::onAppendStages(SkRasterPipeline* 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);
+ SkColor4f c = this->getXformedColor(i, dstCS);
return premulGrad ? c.premul()
: SkPM4f::From4f(Sk4f::Load(&c));
};
@@ -870,6 +869,11 @@ sk_sp<SkGradientShaderBase::GradientShaderCache> SkGradientShaderBase::refCache(
return fCache;
}
+SkColor4f SkGradientShaderBase::getXformedColor(size_t i, SkColorSpace* dstCS) const {
+ return dstCS ? to_colorspace(fOrigColors4f[i], fColorSpace.get(), dstCS)
+ : SkColor4f_from_SkColor(fOrigColors[i], nullptr);
+}
+
SK_DECLARE_STATIC_MUTEX(gGradientCacheMutex);
/*
* Because our caller might rebuild the same (logically the same) gradient
diff --git a/src/shaders/gradients/SkGradientShaderPriv.h b/src/shaders/gradients/SkGradientShaderPriv.h
index 7a66edaffc..c7c7761e1b 100644
--- a/src/shaders/gradients/SkGradientShaderPriv.h
+++ b/src/shaders/gradients/SkGradientShaderPriv.h
@@ -202,6 +202,8 @@ public:
uint32_t getGradFlags() const { return fGradFlags; }
+ SkColor4f getXformedColor(size_t index, SkColorSpace*) const;
+
protected:
struct Rec {
SkFixed fPos; // 0...1