aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Mike Klein <mtklein@chromium.org>2017-03-10 09:55:51 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-03-13 16:11:38 +0000
commit841101d348bbfae2ca44e0a0f267c974d38c9891 (patch)
tree2d003be1fd9b33a4cd6b75e9443d237b8d7c67c7
parentf880b683048b5098e1e62b534902376626ffabac (diff)
SkColorSpaceXformCanvas
TODO: images shaders color filters image filters a couple stray color arrays Change-Id: Ib91639bb0a6a00af737dd5186180011fe5120860 Reviewed-on: https://skia-review.googlesource.com/9529 Reviewed-by: Brian Osman <brianosman@google.com> Reviewed-by: Matt Sarett <msarett@google.com> Commit-Queue: Mike Klein <mtklein@chromium.org>
-rw-r--r--dm/DM.cpp6
-rw-r--r--dm/DMSrcSink.cpp13
-rw-r--r--dm/DMSrcSink.h10
-rw-r--r--gn/core.gni1
-rw-r--r--include/core/SkColorSpaceXformCanvas.h20
-rw-r--r--src/core/SkColorSpaceXformCanvas.cpp288
6 files changed, 337 insertions, 1 deletions
diff --git a/dm/DM.cpp b/dm/DM.cpp
index bec5dd3ddc..cc662bc44f 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -890,8 +890,14 @@ static Sink* create_sink(const GrContextOptions& grCtxOptions, const SkCommandLi
return nullptr;
}
+static sk_sp<SkColorSpace> adobe_rgb() {
+ return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
+ SkColorSpace::kAdobeRGB_Gamut);
+}
+
static Sink* create_via(const SkString& tag, Sink* wrapped) {
#define VIA(t, via, ...) if (tag.equals(t)) { return new via(__VA_ARGS__); }
+ VIA("adobe", ViaCSXform, wrapped, adobe_rgb());
VIA("lite", ViaLite, wrapped);
VIA("pipe", ViaPipe, wrapped);
VIA("twice", ViaTwice, wrapped);
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index 6561ad9da3..4f5cd43af8 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -13,6 +13,7 @@
#include "SkCodecImageGenerator.h"
#include "SkColorSpace.h"
#include "SkColorSpaceXform.h"
+#include "SkColorSpaceXformCanvas.h"
#include "SkColorSpace_XYZ.h"
#include "SkCommonFlags.h"
#include "SkData.h"
@@ -1839,4 +1840,16 @@ Error ViaLite::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkStrin
});
}
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+ViaCSXform::ViaCSXform(Sink* sink, sk_sp<SkColorSpace> cs) : Via(sink), fCS(std::move(cs)) {}
+
+Error ViaCSXform::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
+ return draw_to_canvas(fSink.get(), bitmap, stream, log, src.size(),
+ [&](SkCanvas* canvas) -> Error {
+ auto proxy = SkCreateColorSpaceXformCanvas(canvas, fCS);
+ return src.draw(proxy.get());
+ });
+}
+
} // namespace DM
diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h
index d4fe29de4e..c973e3b393 100644
--- a/dm/DMSrcSink.h
+++ b/dm/DMSrcSink.h
@@ -349,7 +349,7 @@ public:
class PipeSink : public Sink {
public:
PipeSink();
-
+
Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
const char* fileExtension() const override { return "skpipe"; }
SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; }
@@ -494,6 +494,14 @@ public:
Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
};
+class ViaCSXform : public Via {
+public:
+ explicit ViaCSXform(Sink*, sk_sp<SkColorSpace>);
+ Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
+private:
+ sk_sp<SkColorSpace> fCS;
+};
+
} // namespace DM
#endif//DMSrcSink_DEFINED
diff --git a/gn/core.gni b/gn/core.gni
index 3474843508..59d71ab405 100644
--- a/gn/core.gni
+++ b/gn/core.gni
@@ -86,6 +86,7 @@ skia_core_sources = [
"$_src/core/SkColorSpace_XYZ.h",
"$_src/core/SkColorSpace_ICC.cpp",
"$_src/core/SkColorSpaceXform.cpp",
+ "$_src/core/SkColorSpaceXformCanvas.cpp",
"$_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
new file mode 100644
index 0000000000..08981703c5
--- /dev/null
+++ b/include/core/SkColorSpaceXformCanvas.h
@@ -0,0 +1,20 @@
+/*
+ * 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 SkColorSpaceXformCanvas_DEFINED
+#define SkColorSpaceXformCanvas_DEFINED
+
+#include <SkCanvas.h>
+#include <SkColorSpace.h>
+#include <memory>
+
+// Proxy SkCanvas calls to unowned target, transforming colors into targetCS as it goes.
+std::unique_ptr<SkCanvas> SkCreateColorSpaceXformCanvas(SkCanvas* target,
+ sk_sp<SkColorSpace> targetCS);
+
+
+#endif//SkColorSpaceXformCanvas_DEFINED
diff --git a/src/core/SkColorSpaceXformCanvas.cpp b/src/core/SkColorSpaceXformCanvas.cpp
new file mode 100644
index 0000000000..7267a2893f
--- /dev/null
+++ b/src/core/SkColorSpaceXformCanvas.cpp
@@ -0,0 +1,288 @@
+/*
+ * 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 "SkColorSpaceXform.h"
+#include "SkColorSpaceXformCanvas.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)
+ : SkNoDrawCanvas(SkIRect::MakeSize(target->getBaseLayerSize()))
+ , fTarget(target)
+ , fTargetCS(std::move(targetCS)) {
+
+ fFromSRGB = SkColorSpaceXform::New(SkColorSpace::MakeSRGB().get(), fTargetCS.get());
+ }
+
+ SkColor xform(SkColor srgb) const {
+ SkColor xformed;
+ SkAssertResult(fFromSRGB->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &xformed,
+ SkColorSpaceXform::kBGRA_8888_ColorFormat, &srgb,
+ 1, kUnpremul_SkAlphaType));
+ return xformed;
+ }
+
+ 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()));
+ }
+
+ // TODO:
+ // - shaders
+ // - color filters
+ // - image filters?
+
+ return *result;
+ }
+
+ sk_sp<const SkImage> xform(const SkImage* img) const {
+ // TODO: for real
+ return sk_ref_sp(img);
+ }
+
+ const SkPaint* xform(const SkPaint* paint, SkTLazy<SkPaint>* lazy) const {
+ return paint ? &this->xform(*paint, lazy) : nullptr;
+ }
+
+ void onDrawPaint(const SkPaint& paint) override {
+ SkTLazy<SkPaint> lazy;
+ fTarget->drawPaint(this->xform(paint, &lazy));
+ }
+
+ void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
+ SkTLazy<SkPaint> lazy;
+ fTarget->drawRect(rect, this->xform(paint, &lazy));
+ }
+ void onDrawOval(const SkRect& oval, const SkPaint& paint) override {
+ SkTLazy<SkPaint> lazy;
+ fTarget->drawOval(oval, this->xform(paint, &lazy));
+ }
+ void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override {
+ SkTLazy<SkPaint> lazy;
+ fTarget->drawRRect(rrect, this->xform(paint, &lazy));
+ }
+ void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) override {
+ SkTLazy<SkPaint> lazy;
+ fTarget->drawDRRect(outer, inner, this->xform(paint, &lazy));
+ }
+ void onDrawPath(const SkPath& path, const SkPaint& paint) override {
+ SkTLazy<SkPaint> lazy;
+ fTarget->drawPath(path, this->xform(paint, &lazy));
+ }
+ 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));
+ }
+ void onDrawRegion(const SkRegion& region, const SkPaint& paint) override {
+ SkTLazy<SkPaint> lazy;
+ fTarget->drawRegion(region, this->xform(paint, &lazy));
+ }
+ void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texs[4],
+ SkBlendMode mode, const SkPaint& paint) override {
+ // TODO: colors
+ SkTLazy<SkPaint> lazy;
+ fTarget->drawPatch(cubics, colors, texs, mode, this->xform(paint, &lazy));
+ }
+ 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));
+ }
+ void onDrawVertices(VertexMode vmode, int count,
+ const SkPoint* verts, const SkPoint* texs, const SkColor* colors,
+ SkBlendMode mode,
+ const uint16_t* indices, int indexCount, const SkPaint& paint) override {
+ // TODO: colors
+ SkTLazy<SkPaint> lazy;
+ fTarget->drawVertices(vmode, count, verts, texs, colors, mode, indices, indexCount,
+ this->xform(paint, &lazy));
+ }
+
+ 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));
+ }
+ 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));
+ }
+ 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));
+ }
+ 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));
+ }
+ 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));
+ }
+ 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));
+ }
+
+ void onDrawImage(const SkImage* img,
+ SkScalar l, SkScalar t,
+ const SkPaint* paint) override {
+ SkTLazy<SkPaint> lazy;
+ fTarget->drawImage(this->xform(img).get(),
+ l, t,
+ this->xform(paint, &lazy));
+ }
+ 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(),
+ src ? *src : dst, dst,
+ this->xform(paint, &lazy), 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(),
+ center, dst,
+ this->xform(paint, &lazy));
+ }
+ void onDrawImageLattice(const SkImage* img,
+ const Lattice& lattice, const SkRect& dst,
+ const SkPaint* paint) override {
+ SkTLazy<SkPaint> lazy;
+ fTarget->drawImageLattice(this->xform(img).get(),
+ lattice, dst,
+ this->xform(paint, &lazy));
+ }
+ void onDrawAtlas(const SkImage* atlas, const SkRSXform* xforms, const SkRect* tex,
+ const SkColor* colors, int count, SkBlendMode mode,
+ const SkRect* cull, const SkPaint* paint) override {
+ // TODO: colors
+ SkTLazy<SkPaint> lazy;
+ fTarget->drawAtlas(this->xform(atlas).get(), xforms, tex, colors, count, mode, cull,
+ this->xform(paint, &lazy));
+ }
+
+ void onDrawBitmap(const SkBitmap& bitmap,
+ SkScalar l, SkScalar t,
+ const SkPaint* paint) override {
+ if (auto image = SkImage::MakeFromBitmap(bitmap)) {
+ this->onDrawImage(image.get(), l, t, paint);
+ }
+ }
+ void onDrawBitmapRect(const SkBitmap& bitmap,
+ const SkRect* src, const SkRect& dst,
+ const SkPaint* paint, SrcRectConstraint constraint) override {
+ if (auto image = SkImage::MakeFromBitmap(bitmap)) {
+ this->onDrawImageRect(image.get(), src, dst, paint, constraint);
+ }
+ }
+ void onDrawBitmapNine(const SkBitmap& bitmap,
+ const SkIRect& center, const SkRect& dst,
+ const SkPaint* paint) override {
+ if (auto image = SkImage::MakeFromBitmap(bitmap)) {
+ this->onDrawImageNine(image.get(), center, dst, paint);
+ }
+ }
+ void onDrawBitmapLattice(const SkBitmap& bitmap,
+ const Lattice& lattice, const SkRect& dst,
+ const SkPaint* paint) override {
+ if (auto image = SkImage::MakeFromBitmap(bitmap)) {
+ this->onDrawImageLattice(image.get(), lattice, dst, paint);
+ }
+ }
+
+ // TODO: May not be ideal to unfurl pictures.
+ void onDrawPicture(const SkPicture* pic,
+ const SkMatrix* matrix,
+ const SkPaint* paint) override {
+ SkTLazy<SkPaint> lazy;
+ SkCanvas::onDrawPicture(pic, matrix, this->xform(paint, &lazy));
+ }
+ 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),
+ rec.fBackdrop, // TODO: this is an image filter
+ rec.fSaveLayerFlags,
+ });
+ return kNoLayer_SaveLayerStrategy;
+ }
+
+ // Everything from here on should be uninteresting strictly proxied state-change calls.
+ void willSave() override { fTarget->save(); }
+ void willRestore() override { fTarget->restore(); }
+
+ void didConcat (const SkMatrix& m) override { fTarget->concat (m); }
+ void didSetMatrix(const SkMatrix& m) override { fTarget->setMatrix(m); }
+
+ void onClipRect(const SkRect& clip, SkClipOp op, ClipEdgeStyle style) override {
+ fTarget->clipRect(clip, op, style);
+ }
+ void onClipRRect(const SkRRect& clip, SkClipOp op, ClipEdgeStyle style) override {
+ fTarget->clipRRect(clip, op, style);
+ }
+ void onClipPath(const SkPath& clip, SkClipOp op, ClipEdgeStyle style) override {
+ fTarget->clipPath(clip, op, style);
+ }
+ void onClipRegion(const SkRegion& clip, SkClipOp op) override {
+ fTarget->clipRegion(clip, op);
+ }
+
+ void onDrawAnnotation(const SkRect& rect, const char* key, SkData* val) override {
+ fTarget->drawAnnotation(rect, key, val);
+ }
+
+ sk_sp<SkSurface> onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) override {
+ return fTarget->makeSurface(info, &props);
+ }
+
+private:
+ SkCanvas* fTarget;
+ sk_sp<SkColorSpace> fTargetCS;
+ std::unique_ptr<SkColorSpaceXform> fFromSRGB;
+};
+
+std::unique_ptr<SkCanvas> SkCreateColorSpaceXformCanvas(SkCanvas* target,
+ sk_sp<SkColorSpace> targetCS) {
+ return skstd::make_unique<SkColorSpaceXformCanvas>(target, std::move(targetCS));
+}