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>
This commit is contained in:
Mike Klein 2017-03-10 09:55:51 -05:00 committed by Skia Commit-Bot
parent f880b68304
commit 841101d348
6 changed files with 337 additions and 1 deletions

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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",

View File

@ -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

View File

@ -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));
}