aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gn/core.gni2
-rw-r--r--include/core/SkColorSpaceXformCanvas.h1
-rw-r--r--include/core/SkDrawLooper.h8
-rw-r--r--include/effects/SkLayerDrawLooper.h2
-rw-r--r--src/core/SkColorSpaceXformCanvas.cpp251
-rw-r--r--src/core/SkColorSpaceXformer.cpp169
-rw-r--r--src/core/SkColorSpaceXformer.h35
-rw-r--r--src/effects/SkLayerDrawLooper.cpp32
-rw-r--r--tests/QuickRejectTest.cpp6
9 files changed, 299 insertions, 207 deletions
diff --git a/gn/core.gni b/gn/core.gni
index 083b2f51c5..fa65f25eea 100644
--- a/gn/core.gni
+++ b/gn/core.gni
@@ -87,6 +87,8 @@ skia_core_sources = [
"$_src/core/SkColorSpace_ICC.cpp",
"$_src/core/SkColorSpaceXform.cpp",
"$_src/core/SkColorSpaceXformCanvas.cpp",
+ "$_src/core/SkColorSpaceXformer.cpp",
+ "$_src/core/SkColorSpaceXformer.h",
"$_src/core/SkColorSpaceXform_A2B.cpp",
"$_src/core/SkColorSpaceXform_A2B.h",
"$_src/core/SkColorTable.cpp",
diff --git a/include/core/SkColorSpaceXformCanvas.h b/include/core/SkColorSpaceXformCanvas.h
index d46dac4ed3..6bca6c705e 100644
--- a/include/core/SkColorSpaceXformCanvas.h
+++ b/include/core/SkColorSpaceXformCanvas.h
@@ -13,6 +13,7 @@
#include <memory>
// Proxy SkCanvas calls to unowned target, transforming colors into targetCS as it goes.
+// May return nullptr if |targetCS| is unsupported.
std::unique_ptr<SkCanvas> SK_API SkCreateColorSpaceXformCanvas(SkCanvas* target,
sk_sp<SkColorSpace> targetCS);
diff --git a/include/core/SkDrawLooper.h b/include/core/SkDrawLooper.h
index 0b0ae05868..6d9a871ca3 100644
--- a/include/core/SkDrawLooper.h
+++ b/include/core/SkDrawLooper.h
@@ -17,6 +17,7 @@
class SkArenaAlloc;
class SkCanvas;
+class SkColorSpaceXformer;
class SkPaint;
struct SkRect;
class SkString;
@@ -100,9 +101,16 @@ public:
SK_DEFINE_FLATTENABLE_TYPE(SkDrawLooper)
protected:
+ sk_sp<SkDrawLooper> makeColorSpace(SkColorSpaceXformer* xformer) const {
+ return this->onMakeColorSpace(xformer);
+ }
+ virtual sk_sp<SkDrawLooper> onMakeColorSpace(SkColorSpaceXformer*) const = 0;
+
SkDrawLooper() {}
private:
+ friend class SkColorSpaceXformer;
+
typedef SkFlattenable INHERITED;
};
diff --git a/include/effects/SkLayerDrawLooper.h b/include/effects/SkLayerDrawLooper.h
index 3a3514091f..f71b93a706 100644
--- a/include/effects/SkLayerDrawLooper.h
+++ b/include/effects/SkLayerDrawLooper.h
@@ -81,6 +81,8 @@ public:
static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer);
protected:
+ sk_sp<SkDrawLooper> onMakeColorSpace(SkColorSpaceXformer*) const override;
+
SkLayerDrawLooper();
void flatten(SkWriteBuffer&) const override;
diff --git a/src/core/SkColorSpaceXformCanvas.cpp b/src/core/SkColorSpaceXformCanvas.cpp
index fd9fbb8e15..aac94ff171 100644
--- a/src/core/SkColorSpaceXformCanvas.cpp
+++ b/src/core/SkColorSpaceXformCanvas.cpp
@@ -6,218 +6,66 @@
*/
#include "SkColorFilter.h"
-#include "SkColorSpaceXform.h"
#include "SkColorSpaceXformCanvas.h"
+#include "SkColorSpaceXformer.h"
#include "SkGradientShader.h"
#include "SkImage_Base.h"
#include "SkMakeUnique.h"
#include "SkNoDrawCanvas.h"
#include "SkSurface.h"
-#include "SkTLazy.h"
class SkColorSpaceXformCanvas : public SkNoDrawCanvas {
public:
SkColorSpaceXformCanvas(SkCanvas* target,
- sk_sp<SkColorSpace> targetCS)
+ std::unique_ptr<SkColorSpaceXformer> xformer)
: SkNoDrawCanvas(SkIRect::MakeSize(target->getBaseLayerSize()))
, fTarget(target)
- , fTargetCS(std::move(targetCS)) {
-
- fFromSRGB = SkColorSpaceXform::New(SkColorSpace::MakeSRGB().get(), fTargetCS.get());
- }
-
- sk_sp<const SkImage> xform(const SkImage* img) const {
- return as_IB(img)->makeColorSpace(fTargetCS);
- }
-
- void xform(SkColor* xformed, const SkColor* srgb, int n) const {
- SkAssertResult(fFromSRGB->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, xformed,
- SkColorSpaceXform::kBGRA_8888_ColorFormat, srgb,
- n, kUnpremul_SkAlphaType));
- }
-
- SkColor xform(SkColor srgb) const {
- SkColor xformed;
- this->xform(&xformed, &srgb, 1);
- return xformed;
- }
-
- // TODO: Is this introspection going to be enough, or do we need a new SkShader method?
- sk_sp<SkShader> xform(const SkShader* shader) const {
- SkColor color;
- if (shader->isConstant() && shader->asLuminanceColor(&color)) {
- return SkShader::MakeColorShader(this->xform(color));
- }
-
- SkShader::TileMode xy[2];
- SkMatrix local;
- if (auto img = shader->isAImage(&local, xy)) {
- return this->xform(img)->makeShader(xy[0], xy[1], &local);
- }
-
- SkShader::ComposeRec compose;
- if (shader->asACompose(&compose)) {
- auto A = this->xform(compose.fShaderA),
- B = this->xform(compose.fShaderB);
- if (A && B) {
- return SkShader::MakeComposeShader(std::move(A), std::move(B), compose.fBlendMode);
- }
- }
-
- SkShader::GradientInfo gradient;
- sk_bzero(&gradient, sizeof(gradient));
- if (auto type = shader->asAGradient(&gradient)) {
- SkSTArray<8, SkColor> colors(gradient.fColorCount);
- SkSTArray<8, SkScalar> pos(gradient.fColorCount);
-
- gradient.fColors = colors.begin();
- gradient.fColorOffsets = pos.begin();
- shader->asAGradient(&gradient);
-
- SkSTArray<8, SkColor> xformed(gradient.fColorCount);
- this->xform(xformed.begin(), gradient.fColors, gradient.fColorCount);
-
- switch (type) {
- case SkShader::kNone_GradientType:
- case SkShader::kColor_GradientType:
- SkASSERT(false); // Should be unreachable.
- break;
-
- case SkShader::kLinear_GradientType:
- return SkGradientShader::MakeLinear(gradient.fPoint,
- xformed.begin(),
- gradient.fColorOffsets,
- gradient.fColorCount,
- gradient.fTileMode,
- gradient.fGradientFlags,
- &shader->getLocalMatrix());
- case SkShader::kRadial_GradientType:
- return SkGradientShader::MakeRadial(gradient.fPoint[0],
- gradient.fRadius[0],
- xformed.begin(),
- gradient.fColorOffsets,
- gradient.fColorCount,
- gradient.fTileMode,
- gradient.fGradientFlags,
- &shader->getLocalMatrix());
- case SkShader::kSweep_GradientType:
- return SkGradientShader::MakeSweep(gradient.fPoint[0].fX,
- gradient.fPoint[0].fY,
- xformed.begin(),
- gradient.fColorOffsets,
- gradient.fColorCount,
- gradient.fGradientFlags,
- &shader->getLocalMatrix());
- case SkShader::kConical_GradientType:
- return SkGradientShader::MakeTwoPointConical(gradient.fPoint[0],
- gradient.fRadius[0],
- gradient.fPoint[1],
- gradient.fRadius[1],
- xformed.begin(),
- gradient.fColorOffsets,
- gradient.fColorCount,
- gradient.fTileMode,
- gradient.fGradientFlags,
- &shader->getLocalMatrix());
- }
- }
-
- return nullptr;
- }
-
- const SkPaint& xform(const SkPaint& paint, SkTLazy<SkPaint>* lazy) const {
- const SkPaint* result = &paint;
- auto get_lazy = [&] {
- if (!lazy->isValid()) {
- lazy->init(paint);
- result = lazy->get();
- }
- return lazy->get();
- };
-
- // All SkColorSpaces have the same black point.
- if (paint.getColor() & 0xffffff) {
- get_lazy()->setColor(this->xform(paint.getColor()));
- }
-
- if (auto shader = paint.getShader()) {
- if (auto replacement = this->xform(shader)) {
- get_lazy()->setShader(std::move(replacement));
- }
- }
-
- // As far as I know, SkModeColorFilter is the only color filter that holds a color.
- if (auto cf = paint.getColorFilter()) {
- SkColor color;
- SkBlendMode mode;
- if (cf->asColorMode(&color, &mode)) {
- get_lazy()->setColorFilter(SkColorFilter::MakeModeFilter(this->xform(color), mode));
- }
- }
-
- // TODO:
- // - image filters?
-
- return *result;
- }
-
- const SkPaint* xform(const SkPaint* paint, SkTLazy<SkPaint>* lazy) const {
- return paint ? &this->xform(*paint, lazy) : nullptr;
- }
+ , fXformer(std::move(xformer))
+ {}
SkImageInfo onImageInfo() const override {
return fTarget->imageInfo();
}
void onDrawPaint(const SkPaint& paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawPaint(this->xform(paint, &lazy));
+ fTarget->drawPaint(fXformer->apply(paint));
}
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawRect(rect, this->xform(paint, &lazy));
+ fTarget->drawRect(rect, fXformer->apply(paint));
}
void onDrawOval(const SkRect& oval, const SkPaint& paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawOval(oval, this->xform(paint, &lazy));
+ fTarget->drawOval(oval, fXformer->apply(paint));
}
void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawRRect(rrect, this->xform(paint, &lazy));
+ fTarget->drawRRect(rrect, fXformer->apply(paint));
}
void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawDRRect(outer, inner, this->xform(paint, &lazy));
+ fTarget->drawDRRect(outer, inner, fXformer->apply(paint));
}
void onDrawPath(const SkPath& path, const SkPaint& paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawPath(path, this->xform(paint, &lazy));
+ fTarget->drawPath(path, fXformer->apply(paint));
}
void onDrawArc(const SkRect& oval, SkScalar start, SkScalar sweep, bool useCenter,
const SkPaint& paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawArc(oval, start, sweep, useCenter, this->xform(paint, &lazy));
+ fTarget->drawArc(oval, start, sweep, useCenter, fXformer->apply(paint));
}
void onDrawRegion(const SkRegion& region, const SkPaint& paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawRegion(region, this->xform(paint, &lazy));
+ fTarget->drawRegion(region, fXformer->apply(paint));
}
void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texs[4],
SkBlendMode mode, const SkPaint& paint) override {
SkColor xformed[4];
if (colors) {
- this->xform(xformed, colors, 4);
+ fXformer->apply(xformed, colors, 4);
colors = xformed;
}
- SkTLazy<SkPaint> lazy;
- fTarget->drawPatch(cubics, colors, texs, mode, this->xform(paint, &lazy));
+ fTarget->drawPatch(cubics, colors, texs, mode, fXformer->apply(paint));
}
void onDrawPoints(PointMode mode, size_t count, const SkPoint* pts,
const SkPaint& paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawPoints(mode, count, pts, this->xform(paint, &lazy));
+ fTarget->drawPoints(mode, count, pts, fXformer->apply(paint));
}
void onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode,
const SkPaint& paint) override {
@@ -225,85 +73,74 @@ public:
if (vertices->hasColors()) {
int count = vertices->vertexCount();
SkSTArray<8, SkColor> xformed(count);
- this->xform(xformed.begin(), vertices->colors(), count);
+ fXformer->apply(xformed.begin(), vertices->colors(), count);
copy = SkVertices::MakeCopy(vertices->mode(), count, vertices->positions(),
vertices->texCoords(), xformed.begin(),
vertices->indexCount(), vertices->indices());
vertices = copy.get();
}
- SkTLazy<SkPaint> lazy;
- fTarget->drawVertices(vertices, mode, this->xform(paint, &lazy));
+ fTarget->drawVertices(vertices, mode, fXformer->apply(paint));
}
void onDrawText(const void* ptr, size_t len,
SkScalar x, SkScalar y,
const SkPaint& paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawText(ptr, len, x, y, this->xform(paint, &lazy));
+ fTarget->drawText(ptr, len, x, y, fXformer->apply(paint));
}
void onDrawPosText(const void* ptr, size_t len,
const SkPoint* xys,
const SkPaint& paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawPosText(ptr, len, xys, this->xform(paint, &lazy));
+ fTarget->drawPosText(ptr, len, xys, fXformer->apply(paint));
}
void onDrawPosTextH(const void* ptr, size_t len,
const SkScalar* xs, SkScalar y,
const SkPaint& paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawPosTextH(ptr, len, xs, y, this->xform(paint, &lazy));
+ fTarget->drawPosTextH(ptr, len, xs, y, fXformer->apply(paint));
}
void onDrawTextOnPath(const void* ptr, size_t len,
const SkPath& path, const SkMatrix* matrix,
const SkPaint& paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawTextOnPath(ptr, len, path, matrix, this->xform(paint, &lazy));
+ fTarget->drawTextOnPath(ptr, len, path, matrix, fXformer->apply(paint));
}
void onDrawTextRSXform(const void* ptr, size_t len,
const SkRSXform* xforms, const SkRect* cull,
const SkPaint& paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawTextRSXform(ptr, len, xforms, cull, this->xform(paint, &lazy));
+ fTarget->drawTextRSXform(ptr, len, xforms, cull, fXformer->apply(paint));
}
void onDrawTextBlob(const SkTextBlob* blob,
SkScalar x, SkScalar y,
const SkPaint& paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawTextBlob(blob, x, y, this->xform(paint, &lazy));
+ fTarget->drawTextBlob(blob, x, y, fXformer->apply(paint));
}
void onDrawImage(const SkImage* img,
SkScalar l, SkScalar t,
const SkPaint* paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawImage(this->xform(img).get(),
+ fTarget->drawImage(fXformer->apply(img).get(),
l, t,
- this->xform(paint, &lazy));
+ fXformer->apply(paint));
}
void onDrawImageRect(const SkImage* img,
const SkRect* src, const SkRect& dst,
const SkPaint* paint, SrcRectConstraint constraint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawImageRect(this->xform(img).get(),
+ fTarget->drawImageRect(fXformer->apply(img).get(),
src ? *src : dst, dst,
- this->xform(paint, &lazy), constraint);
+ fXformer->apply(paint), constraint);
}
void onDrawImageNine(const SkImage* img,
const SkIRect& center, const SkRect& dst,
const SkPaint* paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawImageNine(this->xform(img).get(),
+ fTarget->drawImageNine(fXformer->apply(img).get(),
center, dst,
- this->xform(paint, &lazy));
+ fXformer->apply(paint));
}
void onDrawImageLattice(const SkImage* img,
const Lattice& lattice, const SkRect& dst,
const SkPaint* paint) override {
- SkTLazy<SkPaint> lazy;
- fTarget->drawImageLattice(this->xform(img).get(),
+ fTarget->drawImageLattice(fXformer->apply(img).get(),
lattice, dst,
- this->xform(paint, &lazy));
+ fXformer->apply(paint));
}
void onDrawAtlas(const SkImage* atlas, const SkRSXform* xforms, const SkRect* tex,
const SkColor* colors, int count, SkBlendMode mode,
@@ -311,13 +148,12 @@ public:
SkSTArray<8, SkColor> xformed;
if (colors) {
xformed.reset(count);
- this->xform(xformed.begin(), colors, count);
+ fXformer->apply(xformed.begin(), colors, count);
colors = xformed.begin();
}
- SkTLazy<SkPaint> lazy;
- fTarget->drawAtlas(this->xform(atlas).get(), xforms, tex, colors, count, mode, cull,
- this->xform(paint, &lazy));
+ fTarget->drawAtlas(fXformer->apply(atlas).get(), xforms, tex, colors, count, mode, cull,
+ fXformer->apply(paint));
}
void onDrawBitmap(const SkBitmap& bitmap,
@@ -353,19 +189,16 @@ public:
void onDrawPicture(const SkPicture* pic,
const SkMatrix* matrix,
const SkPaint* paint) override {
- SkTLazy<SkPaint> lazy;
- SkCanvas::onDrawPicture(pic, matrix, this->xform(paint, &lazy));
+ SkCanvas::onDrawPicture(pic, matrix, fXformer->apply(paint));
}
void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
- SkTLazy<SkPaint> lazy;
SkCanvas::onDrawDrawable(drawable, matrix);
}
SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
- SkTLazy<SkPaint> lazy;
fTarget->saveLayer({
rec.fBounds,
- this->xform(rec.fPaint, &lazy),
+ fXformer->apply(rec.fPaint),
rec.fBackdrop, // TODO: this is an image filter
rec.fSaveLayerFlags,
});
@@ -405,12 +238,16 @@ public:
}
private:
- SkCanvas* fTarget;
- sk_sp<SkColorSpace> fTargetCS;
- std::unique_ptr<SkColorSpaceXform> fFromSRGB;
+ SkCanvas* fTarget;
+ std::unique_ptr<SkColorSpaceXformer> fXformer;
};
std::unique_ptr<SkCanvas> SkCreateColorSpaceXformCanvas(SkCanvas* target,
sk_sp<SkColorSpace> targetCS) {
- return skstd::make_unique<SkColorSpaceXformCanvas>(target, std::move(targetCS));
+ std::unique_ptr<SkColorSpaceXformer> xformer = SkColorSpaceXformer::Make(std::move(targetCS));
+ if (!xformer) {
+ return nullptr;
+ }
+
+ return skstd::make_unique<SkColorSpaceXformCanvas>(target, std::move(xformer));
}
diff --git a/src/core/SkColorSpaceXformer.cpp b/src/core/SkColorSpaceXformer.cpp
new file mode 100644
index 0000000000..e983756426
--- /dev/null
+++ b/src/core/SkColorSpaceXformer.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkColorFilter.h"
+#include "SkColorSpaceXformer.h"
+#include "SkColorSpaceXform_Base.h"
+#include "SkDrawLooper.h"
+#include "SkGradientShader.h"
+#include "SkImage_Base.h"
+#include "SkMakeUnique.h"
+
+std::unique_ptr<SkColorSpaceXformer> SkColorSpaceXformer::Make(sk_sp<SkColorSpace> dst) {
+ std::unique_ptr<SkColorSpaceXform> fromSRGB = SkColorSpaceXform_Base::New(
+ SkColorSpace::MakeSRGB().get(), dst.get(), SkTransferFunctionBehavior::kIgnore);
+ if (!fromSRGB) {
+ return nullptr;
+ }
+
+ auto xformer = std::unique_ptr<SkColorSpaceXformer>(new SkColorSpaceXformer());
+ xformer->fDst = std::move(dst);
+ xformer->fFromSRGB = std::move(fromSRGB);
+ return xformer;
+}
+
+sk_sp<SkImage> SkColorSpaceXformer::apply(const SkImage* src) {
+ return as_IB(src)->makeColorSpace(fDst);
+}
+
+void SkColorSpaceXformer::apply(SkColor* xformed, const SkColor* srgb, int n) {
+ SkAssertResult(fFromSRGB->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, xformed,
+ SkColorSpaceXform::kBGRA_8888_ColorFormat, srgb,
+ n, kUnpremul_SkAlphaType));
+}
+
+SkColor SkColorSpaceXformer::apply(SkColor srgb) {
+ SkColor xformed;
+ this->apply(&xformed, &srgb, 1);
+ return xformed;
+}
+
+// TODO: Is this introspection going to be enough, or do we need a new SkShader method?
+sk_sp<SkShader> SkColorSpaceXformer::apply(const SkShader* shader) {
+ SkColor color;
+ if (shader->isConstant() && shader->asLuminanceColor(&color)) {
+ return SkShader::MakeColorShader(this->apply(color));
+ }
+
+ SkShader::TileMode xy[2];
+ SkMatrix local;
+ if (auto img = shader->isAImage(&local, xy)) {
+ return this->apply(img)->makeShader(xy[0], xy[1], &local);
+ }
+
+ SkShader::ComposeRec compose;
+ if (shader->asACompose(&compose)) {
+ auto A = this->apply(compose.fShaderA),
+ B = this->apply(compose.fShaderB);
+ if (A && B) {
+ return SkShader::MakeComposeShader(std::move(A), std::move(B), compose.fBlendMode);
+ }
+ }
+
+ SkShader::GradientInfo gradient;
+ sk_bzero(&gradient, sizeof(gradient));
+ if (auto type = shader->asAGradient(&gradient)) {
+ SkSTArray<8, SkColor> colors(gradient.fColorCount);
+ SkSTArray<8, SkScalar> pos(gradient.fColorCount);
+
+ gradient.fColors = colors.begin();
+ gradient.fColorOffsets = pos.begin();
+ shader->asAGradient(&gradient);
+
+ SkSTArray<8, SkColor> xformed(gradient.fColorCount);
+ this->apply(xformed.begin(), gradient.fColors, gradient.fColorCount);
+
+ switch (type) {
+ case SkShader::kNone_GradientType:
+ case SkShader::kColor_GradientType:
+ SkASSERT(false); // Should be unreachable.
+ break;
+
+ case SkShader::kLinear_GradientType:
+ return SkGradientShader::MakeLinear(gradient.fPoint,
+ xformed.begin(),
+ gradient.fColorOffsets,
+ gradient.fColorCount,
+ gradient.fTileMode,
+ gradient.fGradientFlags,
+ &shader->getLocalMatrix());
+ case SkShader::kRadial_GradientType:
+ return SkGradientShader::MakeRadial(gradient.fPoint[0],
+ gradient.fRadius[0],
+ xformed.begin(),
+ gradient.fColorOffsets,
+ gradient.fColorCount,
+ gradient.fTileMode,
+ gradient.fGradientFlags,
+ &shader->getLocalMatrix());
+ case SkShader::kSweep_GradientType:
+ return SkGradientShader::MakeSweep(gradient.fPoint[0].fX,
+ gradient.fPoint[0].fY,
+ xformed.begin(),
+ gradient.fColorOffsets,
+ gradient.fColorCount,
+ gradient.fGradientFlags,
+ &shader->getLocalMatrix());
+ case SkShader::kConical_GradientType:
+ return SkGradientShader::MakeTwoPointConical(gradient.fPoint[0],
+ gradient.fRadius[0],
+ gradient.fPoint[1],
+ gradient.fRadius[1],
+ xformed.begin(),
+ gradient.fColorOffsets,
+ gradient.fColorCount,
+ gradient.fTileMode,
+ gradient.fGradientFlags,
+ &shader->getLocalMatrix());
+ }
+ }
+
+ return nullptr;
+}
+
+const SkPaint& SkColorSpaceXformer::apply(const SkPaint& src) {
+ const SkPaint* result = &src;
+ auto get_dst = [&] {
+ if (result == &src) {
+ fDstPaint = src;
+ result = &fDstPaint;
+ }
+ return &fDstPaint;
+ };
+
+ // All SkColorSpaces have the same black point.
+ if (src.getColor() & 0xffffff) {
+ get_dst()->setColor(this->apply(src.getColor()));
+ }
+
+ if (auto shader = src.getShader()) {
+ if (auto replacement = this->apply(shader)) {
+ get_dst()->setShader(std::move(replacement));
+ }
+ }
+
+ // As far as I know, SkModeColorFilter is the only color filter that holds a color.
+ if (auto cf = src.getColorFilter()) {
+ SkColor color;
+ SkBlendMode mode;
+ if (cf->asColorMode(&color, &mode)) {
+ get_dst()->setColorFilter(SkColorFilter::MakeModeFilter(this->apply(color), mode));
+ }
+ }
+
+ if (auto looper = src.getDrawLooper()) {
+ get_dst()->setDrawLooper(looper->makeColorSpace(this));
+ }
+
+ // TODO:
+ // - image filters?
+ return *result;
+}
+
+const SkPaint* SkColorSpaceXformer::apply(const SkPaint* src) {
+ return src ? &this->apply(*src) : nullptr;
+}
diff --git a/src/core/SkColorSpaceXformer.h b/src/core/SkColorSpaceXformer.h
new file mode 100644
index 0000000000..b89fd8a333
--- /dev/null
+++ b/src/core/SkColorSpaceXformer.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkColorSpaceXformer_DEFINED
+#define SkColorSpaceXformer_DEFINED
+
+#include "SkColorSpaceXform.h"
+#include "SkImage.h"
+#include "SkShader.h"
+
+class SkColorSpaceXformer : public SkNoncopyable {
+public:
+ static std::unique_ptr<SkColorSpaceXformer> Make(sk_sp<SkColorSpace> dst);
+
+ sk_sp<SkImage> apply(const SkImage* src);
+ const SkPaint* apply(const SkPaint* src);
+ const SkPaint& apply(const SkPaint& src);
+ void apply(SkColor dst[], const SkColor src[], int n);
+
+private:
+ SkColor apply(SkColor srgb);
+ sk_sp<SkShader> apply(const SkShader* shader);
+
+ SkColorSpaceXformer() {}
+
+ sk_sp<SkColorSpace> fDst;
+ std::unique_ptr<SkColorSpaceXform> fFromSRGB;
+ SkPaint fDstPaint;
+};
+
+#endif
diff --git a/src/effects/SkLayerDrawLooper.cpp b/src/effects/SkLayerDrawLooper.cpp
index a20638c005..feeea66a35 100644
--- a/src/effects/SkLayerDrawLooper.cpp
+++ b/src/effects/SkLayerDrawLooper.cpp
@@ -8,6 +8,7 @@
#include "SkBlurDrawLooper.h"
#include "SkBlurMaskFilter.h"
#include "SkCanvas.h"
+#include "SkColorSpaceXformer.h"
#include "SkColor.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"
@@ -206,6 +207,37 @@ bool SkLayerDrawLooper::asABlurShadow(BlurShadowRec* bsRec) const {
return true;
}
+sk_sp<SkDrawLooper> SkLayerDrawLooper::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
+ if (!fCount) {
+ return sk_ref_sp(const_cast<SkLayerDrawLooper*>(this));
+ }
+
+ auto looper = sk_sp<SkLayerDrawLooper>(new SkLayerDrawLooper());
+ looper->fCount = fCount;
+
+ Rec* oldRec = fRecs;
+ Rec* newTopRec = new Rec();
+ newTopRec->fInfo = oldRec->fInfo;
+ newTopRec->fPaint = xformer->apply(oldRec->fPaint);
+ newTopRec->fNext = nullptr;
+
+ Rec* prevNewRec = newTopRec;
+ oldRec = oldRec->fNext;
+ while (oldRec) {
+ Rec* newRec = new Rec();
+ newRec->fInfo = oldRec->fInfo;
+ newRec->fPaint = xformer->apply(oldRec->fPaint);
+ newRec->fNext = nullptr;
+ prevNewRec->fNext = newRec;
+
+ prevNewRec = newRec;
+ oldRec = oldRec->fNext;
+ }
+
+ looper->fRecs = newTopRec;
+ return std::move(looper);
+}
+
///////////////////////////////////////////////////////////////////////////////
void SkLayerDrawLooper::flatten(SkWriteBuffer& buffer) const {
diff --git a/tests/QuickRejectTest.cpp b/tests/QuickRejectTest.cpp
index cf886d3d34..b705253e34 100644
--- a/tests/QuickRejectTest.cpp
+++ b/tests/QuickRejectTest.cpp
@@ -7,6 +7,7 @@
#include "SkArenaAlloc.h"
#include "SkCanvas.h"
+#include "SkColorSpaceXformer.h"
#include "SkDrawLooper.h"
#include "SkLightingImageFilter.h"
#include "SkTypes.h"
@@ -22,6 +23,10 @@ public:
return alloc->make<TestDrawLooperContext>();
}
+ sk_sp<SkDrawLooper> onMakeColorSpace(SkColorSpaceXformer*) const override {
+ return nullptr;
+ }
+
#ifndef SK_IGNORE_TO_STRING
void toString(SkString* str) const override {
str->append("TestLooper:");
@@ -44,6 +49,7 @@ private:
}
return false;
}
+
private:
bool fOnce;
};