Make SkColorSpaceXformer::apply(SkPaint) safe to call recursively

Before, we would stomp on the original paint in the recursive call.

This fixes 4 gbr-8888 gms.  Currently, this only affects loopers
and SkPaintImageFilter.

Bug: skia:6516
Change-Id: Ic47d637a912370c0a1ae8ef3282ad7d15d9902e3
Reviewed-on: https://skia-review.googlesource.com/14182
Commit-Queue: Matt Sarett <msarett@google.com>
Reviewed-by: Mike Klein <mtklein@chromium.org>
This commit is contained in:
Matt Sarett 2017-04-25 13:53:11 -04:00 committed by Skia Commit-Bot
parent 4785897c96
commit c15bb7b107
3 changed files with 40 additions and 56 deletions

View File

@ -15,6 +15,18 @@
#include "SkMakeUnique.h"
#include "SkNoDrawCanvas.h"
#include "SkSurface.h"
#include "SkTLazy.h"
namespace {
struct MaybePaint {
SkTLazy<SkPaint> fStorage;
const SkPaint* fPaint = nullptr;
MaybePaint(const SkPaint* p, SkColorSpaceXformer* xformer) {
if (p) { fPaint = fStorage.set(xformer->apply(*p)); }
}
operator const SkPaint*() const { return fPaint; }
};
};
class SkColorSpaceXformCanvas : public SkNoDrawCanvas {
public:
@ -126,30 +138,26 @@ public:
void onDrawImage(const SkImage* img,
SkScalar l, SkScalar t,
const SkPaint* paint) override {
fTarget->drawImage(fXformer->apply(img).get(),
l, t,
fXformer->apply(paint));
fTarget->drawImage(fXformer->apply(img).get(), l, t, MaybePaint(paint, fXformer.get()));
}
void onDrawImageRect(const SkImage* img,
const SkRect* src, const SkRect& dst,
const SkPaint* paint, SrcRectConstraint constraint) override {
fTarget->drawImageRect(fXformer->apply(img).get(),
src ? *src : SkRect::MakeIWH(img->width(), img->height()), dst,
fXformer->apply(paint), constraint);
MaybePaint(paint, fXformer.get()), constraint);
}
void onDrawImageNine(const SkImage* img,
const SkIRect& center, const SkRect& dst,
const SkPaint* paint) override {
fTarget->drawImageNine(fXformer->apply(img).get(),
center, dst,
fXformer->apply(paint));
fTarget->drawImageNine(fXformer->apply(img).get(), center, dst,
MaybePaint(paint, fXformer.get()));
}
void onDrawImageLattice(const SkImage* img,
const Lattice& lattice, const SkRect& dst,
const SkPaint* paint) override {
fTarget->drawImageLattice(fXformer->apply(img).get(),
lattice, dst,
fXformer->apply(paint));
fTarget->drawImageLattice(fXformer->apply(img).get(), lattice, dst,
MaybePaint(paint, fXformer.get()));
}
void onDrawAtlas(const SkImage* atlas, const SkRSXform* xforms, const SkRect* tex,
const SkColor* colors, int count, SkBlendMode mode,
@ -160,19 +168,18 @@ public:
fXformer->apply(xformed.begin(), colors, count);
colors = xformed.begin();
}
fTarget->drawAtlas(fXformer->apply(atlas).get(), xforms, tex, colors, count, mode, cull,
fXformer->apply(paint));
MaybePaint(paint, fXformer.get()));
}
void onDrawBitmap(const SkBitmap& bitmap,
SkScalar l, SkScalar t,
const SkPaint* paint) override {
if (this->skipXform(bitmap)) {
return fTarget->drawBitmap(bitmap, l, t, fXformer->apply(paint));
return fTarget->drawBitmap(bitmap, l, t, MaybePaint(paint, fXformer.get()));
}
fTarget->drawImage(fXformer->apply(bitmap).get(), l, t, fXformer->apply(paint));
fTarget->drawImage(fXformer->apply(bitmap).get(), l, t, MaybePaint(paint, fXformer.get()));
}
void onDrawBitmapRect(const SkBitmap& bitmap,
const SkRect* src, const SkRect& dst,
@ -180,39 +187,41 @@ public:
if (this->skipXform(bitmap)) {
return fTarget->drawBitmapRect(bitmap,
src ? *src : SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst,
fXformer->apply(paint), constraint);
MaybePaint(paint, fXformer.get()), constraint);
}
fTarget->drawImageRect(fXformer->apply(bitmap).get(),
src ? *src : SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst,
fXformer->apply(paint), constraint);
MaybePaint(paint, fXformer.get()), constraint);
}
void onDrawBitmapNine(const SkBitmap& bitmap,
const SkIRect& center, const SkRect& dst,
const SkPaint* paint) override {
if (this->skipXform(bitmap)) {
return fTarget->drawBitmapNine(bitmap, center, dst, fXformer->apply(paint));
return fTarget->drawBitmapNine(bitmap, center, dst, MaybePaint(paint, fXformer.get()));
}
fTarget->drawImageNine(fXformer->apply(bitmap).get(), center, dst, fXformer->apply(paint));
fTarget->drawImageNine(fXformer->apply(bitmap).get(), center, dst,
MaybePaint(paint, fXformer.get()));
}
void onDrawBitmapLattice(const SkBitmap& bitmap,
const Lattice& lattice, const SkRect& dst,
const SkPaint* paint) override {
if (this->skipXform(bitmap)) {
return fTarget->drawBitmapLattice(bitmap, lattice, dst, fXformer->apply(paint));
return fTarget->drawBitmapLattice(bitmap, lattice, dst,
MaybePaint(paint, fXformer.get()));
}
fTarget->drawImageLattice(fXformer->apply(bitmap).get(), lattice, dst,
fXformer->apply(paint));
MaybePaint(paint, fXformer.get()));
}
void onDrawPicture(const SkPicture* pic,
const SkMatrix* matrix,
const SkPaint* paint) override {
SkCanvas::onDrawPicture(pic, matrix, fXformer->apply(paint));
SkCanvas::onDrawPicture(pic, matrix, MaybePaint(paint, fXformer.get()));
}
void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
SkCanvas::onDrawDrawable(drawable, matrix);
@ -222,7 +231,7 @@ public:
sk_sp<SkImageFilter> backdrop = rec.fBackdrop ? fXformer->apply(rec.fBackdrop) : nullptr;
fTarget->saveLayer({
rec.fBounds,
fXformer->apply(rec.fPaint),
MaybePaint(rec.fPaint, fXformer.get()),
backdrop.get(),
rec.fSaveLayerFlags,
});

View File

@ -79,52 +79,29 @@ SkColor SkColorSpaceXformer::apply(SkColor srgb) {
return xformed;
}
const SkPaint& SkColorSpaceXformer::apply(const SkPaint& src) {
const SkPaint* result = &src;
auto get_dst = [&] {
if (result == &src) {
fDstPaint = src;
result = &fDstPaint;
}
return &fDstPaint;
};
SkPaint SkColorSpaceXformer::apply(const SkPaint& src) {
SkPaint dst = src;
// All SkColorSpaces have the same black point.
if (src.getColor() & 0xffffff) {
get_dst()->setColor(this->apply(src.getColor()));
dst.setColor(this->apply(src.getColor()));
}
if (auto shader = src.getShader()) {
auto replacement = shader->makeColorSpace(this);
if (replacement.get() != shader) {
get_dst()->setShader(std::move(replacement));
}
dst.setShader(shader->makeColorSpace(this));
}
if (auto cf = src.getColorFilter()) {
auto replacement = this->apply(cf);
if (replacement.get() != cf) {
get_dst()->setColorFilter(std::move(replacement));
}
dst.setColorFilter(this->apply(cf));
}
if (auto looper = src.getDrawLooper()) {
auto replacement = looper->makeColorSpace(this);
if (replacement.get() != looper) {
get_dst()->setDrawLooper(std::move(replacement));
}
dst.setDrawLooper(looper->makeColorSpace(this));
}
if (auto imageFilter = src.getImageFilter()) {
auto replacement = this->apply(imageFilter);
if (replacement.get() != imageFilter) {
get_dst()->setImageFilter(std::move(replacement));
}
dst.setImageFilter(this->apply(imageFilter));
}
return *result;
}
const SkPaint* SkColorSpaceXformer::apply(const SkPaint* src) {
return src ? &this->apply(*src) : nullptr;
return dst;
}

View File

@ -20,8 +20,7 @@ public:
sk_sp<SkImage> apply(const SkBitmap& bitmap);
sk_sp<SkColorFilter> apply(const SkColorFilter* filter);
sk_sp<SkImageFilter> apply(const SkImageFilter* filter);
const SkPaint* apply(const SkPaint* src);
const SkPaint& apply(const SkPaint& src);
SkPaint apply(const SkPaint& src);
void apply(SkColor dst[], const SkColor src[], int n);
SkColor apply(SkColor srgb);
@ -32,7 +31,6 @@ private:
sk_sp<SkColorSpace> fDst;
std::unique_ptr<SkColorSpaceXform> fFromSRGB;
SkPaint fDstPaint;
};
#endif