SkImageSource
Blink is migrating away from SkBitmaps, so we need an SkImage-based SkImageFilter source. This is pretty much a 1-1 equivalent of SkBitmapSource. To avoid duplication, relocate the SkImage deserialization logic from SkPictureData to SkReadBuffer. R=reed@google.com,robertphillips@google.com,senorblanco@chromium.org Review URL: https://codereview.chromium.org/1343703005
This commit is contained in:
parent
506c802a3d
commit
cd56f812e0
80
gm/imagesource.cpp
Normal file
80
gm/imagesource.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "gm.h"
|
||||
|
||||
#include "SkImage.h"
|
||||
#include "SkImageSource.h"
|
||||
|
||||
// This GM exercises the SkImageSource ImageFilter class.
|
||||
|
||||
class ImageSourceGM : public skiagm::GM {
|
||||
public:
|
||||
ImageSourceGM() { }
|
||||
|
||||
protected:
|
||||
SkString onShortName() override {
|
||||
return SkString("imagesource");
|
||||
}
|
||||
|
||||
SkISize onISize() override { return SkISize::Make(500, 150); }
|
||||
|
||||
void onOnceBeforeDraw() override {
|
||||
SkBitmap bm = sk_tool_utils::create_string_bitmap(100, 100, 0xFFFFFFFF, 20, 70, 96, "e");
|
||||
fImage.reset(SkImage::NewFromBitmap(bm));
|
||||
}
|
||||
|
||||
static void FillRectFiltered(SkCanvas* canvas, const SkRect& clipRect, SkImageFilter* filter) {
|
||||
SkPaint paint;
|
||||
paint.setImageFilter(filter);
|
||||
canvas->save();
|
||||
canvas->clipRect(clipRect);
|
||||
canvas->drawPaint(paint);
|
||||
canvas->restore();
|
||||
}
|
||||
|
||||
void onDraw(SkCanvas* canvas) override {
|
||||
canvas->clear(SK_ColorBLACK);
|
||||
{
|
||||
SkRect srcRect = SkRect::MakeXYWH(20, 20, 30, 30);
|
||||
SkRect dstRect = SkRect::MakeXYWH(0, 10, 60, 60);
|
||||
SkRect clipRect = SkRect::MakeXYWH(0, 0, 100, 100);
|
||||
SkRect bounds = SkRect::MakeIWH(fImage->width(), fImage->height());
|
||||
SkAutoTUnref<SkImageFilter> imageSource(SkImageSource::Create(fImage));
|
||||
SkAutoTUnref<SkImageFilter> imageSourceSrcRect(
|
||||
SkImageSource::Create(fImage, srcRect, srcRect, kHigh_SkFilterQuality));
|
||||
SkAutoTUnref<SkImageFilter> imageSourceSrcRectDstRect(
|
||||
SkImageSource::Create(fImage, srcRect, dstRect, kHigh_SkFilterQuality));
|
||||
SkAutoTUnref<SkImageFilter> imageSourceDstRectOnly(
|
||||
SkImageSource::Create(fImage, bounds, dstRect, kHigh_SkFilterQuality));
|
||||
|
||||
// Draw an unscaled bitmap.
|
||||
FillRectFiltered(canvas, clipRect, imageSource);
|
||||
canvas->translate(SkIntToScalar(100), 0);
|
||||
|
||||
// Draw an unscaled subset of the source bitmap (srcRect -> srcRect).
|
||||
FillRectFiltered(canvas, clipRect, imageSourceSrcRect);
|
||||
canvas->translate(SkIntToScalar(100), 0);
|
||||
|
||||
// Draw a subset of the bitmap scaled to a destination rect (srcRect -> dstRect).
|
||||
FillRectFiltered(canvas, clipRect, imageSourceSrcRectDstRect);
|
||||
canvas->translate(SkIntToScalar(100), 0);
|
||||
|
||||
// Draw the entire bitmap scaled to a destination rect (bounds -> dstRect).
|
||||
FillRectFiltered(canvas, clipRect, imageSourceDstRectOnly);
|
||||
canvas->translate(SkIntToScalar(100), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SkAutoTUnref<SkImage> fImage;
|
||||
typedef GM INHERITED;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DEF_GM( return new ImageSourceGM; )
|
@ -39,6 +39,7 @@
|
||||
'<(skia_src_path)/effects/SkEmbossMask.h',
|
||||
'<(skia_src_path)/effects/SkEmbossMask_Table.h',
|
||||
'<(skia_src_path)/effects/SkEmbossMaskFilter.cpp',
|
||||
'<(skia_src_path)/effects/SkImageSource.cpp',
|
||||
'<(skia_src_path)/effects/SkGpuBlurUtils.h',
|
||||
'<(skia_src_path)/effects/SkGpuBlurUtils.cpp',
|
||||
'<(skia_src_path)/effects/SkLayerDrawLooper.cpp',
|
||||
@ -100,6 +101,7 @@
|
||||
'<(skia_include_path)/effects/SkDropShadowImageFilter.h',
|
||||
'<(skia_include_path)/effects/SkEmbossMaskFilter.h',
|
||||
'<(skia_include_path)/effects/SkGradientShader.h',
|
||||
'<(skia_include_path)/effects/SkImageSource.h',
|
||||
'<(skia_include_path)/effects/SkLayerDrawLooper.h',
|
||||
'<(skia_include_path)/effects/SkLayerRasterizer.h',
|
||||
'<(skia_include_path)/effects/SkLerpXfermode.h',
|
||||
|
48
include/effects/SkImageSource.h
Normal file
48
include/effects/SkImageSource.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkImageSource_DEFINED
|
||||
#define SkImageSource_DEFINED
|
||||
|
||||
#include "SkImageFilter.h"
|
||||
|
||||
class SkImage;
|
||||
|
||||
class SK_API SkImageSource : public SkImageFilter {
|
||||
public:
|
||||
static SkImageFilter* Create(const SkImage*);
|
||||
static SkImageFilter* Create(const SkImage*,
|
||||
const SkRect& srcRect,
|
||||
const SkRect& dstRect,
|
||||
SkFilterQuality);
|
||||
|
||||
void computeFastBounds(const SkRect& src, SkRect* dst) const override;
|
||||
|
||||
SK_TO_STRING_OVERRIDE()
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkImageSource)
|
||||
|
||||
protected:
|
||||
void flatten(SkWriteBuffer&) const override;
|
||||
|
||||
bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
|
||||
SkBitmap* result, SkIPoint* offset) const override;
|
||||
|
||||
private:
|
||||
explicit SkImageSource(const SkImage*);
|
||||
SkImageSource(const SkImage*,
|
||||
const SkRect& srcRect,
|
||||
const SkRect& dstRect,
|
||||
SkFilterQuality);
|
||||
|
||||
SkAutoTUnref<const SkImage> fImage;
|
||||
SkRect fSrcRect, fDstRect;
|
||||
SkFilterQuality fFilterQuality;
|
||||
|
||||
typedef SkImageFilter INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
@ -434,44 +434,8 @@ bool SkPictureData::parseStreamTag(SkStream* stream,
|
||||
return true; // success
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// This generator intentionally should always fail on all attempts to get its pixels,
|
||||
// simulating a bad or empty codec stream.
|
||||
class EmptyImageGenerator final : public SkImageGenerator {
|
||||
public:
|
||||
EmptyImageGenerator(const SkImageInfo& info) : INHERITED(info) { }
|
||||
|
||||
private:
|
||||
typedef SkImageGenerator INHERITED;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
static const SkImage* create_image_from_buffer(SkReadBuffer& buffer) {
|
||||
int width = buffer.read32();
|
||||
int height = buffer.read32();
|
||||
if (width <= 0 || height <= 0) { // SkImage never has a zero dimension
|
||||
buffer.validate(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkAutoTUnref<SkData> encoded(buffer.readByteArrayAsData());
|
||||
if (encoded->size() == 0) {
|
||||
// The image could not be encoded at serialization time - return an empty placeholder.
|
||||
return SkImage::NewFromGenerator(
|
||||
new EmptyImageGenerator(SkImageInfo::MakeN32Premul(width, height)));
|
||||
}
|
||||
|
||||
int originX = buffer.read32();
|
||||
int originY = buffer.read32();
|
||||
if (originX < 0 || originY < 0) {
|
||||
buffer.validate(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const SkIRect subset = SkIRect::MakeXYWH(originX, originY, width, height);
|
||||
return SkImage::NewFromEncoded(encoded, &subset);
|
||||
return buffer.readImage();
|
||||
}
|
||||
|
||||
// Need a shallow wrapper to return const SkPicture* to match the other factories,
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
#include "SkBitmap.h"
|
||||
#include "SkErrorInternals.h"
|
||||
#include "SkImage.h"
|
||||
#include "SkImageGenerator.h"
|
||||
#include "SkReadBuffer.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkTypeface.h"
|
||||
@ -274,6 +276,46 @@ bool SkReadBuffer::readBitmap(SkBitmap* bitmap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// This generator intentionally should always fail on all attempts to get its pixels,
|
||||
// simulating a bad or empty codec stream.
|
||||
class EmptyImageGenerator final : public SkImageGenerator {
|
||||
public:
|
||||
EmptyImageGenerator(const SkImageInfo& info) : INHERITED(info) { }
|
||||
|
||||
private:
|
||||
typedef SkImageGenerator INHERITED;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
SkImage* SkReadBuffer::readImage() {
|
||||
int width = this->read32();
|
||||
int height = this->read32();
|
||||
if (width <= 0 || height <= 0) { // SkImage never has a zero dimension
|
||||
this->validate(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkAutoTUnref<SkData> encoded(this->readByteArrayAsData());
|
||||
if (encoded->size() == 0) {
|
||||
// The image could not be encoded at serialization time - return an empty placeholder.
|
||||
return SkImage::NewFromGenerator(
|
||||
new EmptyImageGenerator(SkImageInfo::MakeN32Premul(width, height)));
|
||||
}
|
||||
|
||||
int originX = this->read32();
|
||||
int originY = this->read32();
|
||||
if (originX < 0 || originY < 0) {
|
||||
this->validate(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const SkIRect subset = SkIRect::MakeXYWH(originX, originY, width, height);
|
||||
return SkImage::NewFromEncoded(encoded, &subset);
|
||||
}
|
||||
|
||||
SkTypeface* SkReadBuffer::readTypeface() {
|
||||
|
||||
uint32_t index = fReader.readU32();
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "SkXfermode.h"
|
||||
|
||||
class SkBitmap;
|
||||
class SkImage;
|
||||
|
||||
#if defined(SK_DEBUG) && defined(SK_BUILD_FOR_MAC)
|
||||
#define DEBUG_NON_DETERMINISTIC_ASSERT
|
||||
@ -169,6 +170,8 @@ public:
|
||||
*/
|
||||
bool readBitmap(SkBitmap* bitmap);
|
||||
|
||||
SkImage* readImage();
|
||||
|
||||
virtual SkTypeface* readTypeface();
|
||||
|
||||
void setBitmapStorage(SkBitmapHeapReader* bitmapStorage) {
|
||||
|
118
src/effects/SkImageSource.cpp
Normal file
118
src/effects/SkImageSource.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkImageSource.h"
|
||||
|
||||
#include "SkCanvas.h"
|
||||
#include "SkDevice.h"
|
||||
#include "SkImage.h"
|
||||
#include "SkReadBuffer.h"
|
||||
#include "SkWriteBuffer.h"
|
||||
#include "SkString.h"
|
||||
|
||||
SkImageFilter* SkImageSource::Create(const SkImage* image) {
|
||||
return image ? SkNEW_ARGS(SkImageSource, (image)) : nullptr;
|
||||
}
|
||||
|
||||
SkImageFilter* SkImageSource::Create(const SkImage* image,
|
||||
const SkRect& srcRect,
|
||||
const SkRect& dstRect,
|
||||
SkFilterQuality filterQuality) {
|
||||
return image ? SkNEW_ARGS(SkImageSource, (image, srcRect, dstRect, filterQuality)) : nullptr;
|
||||
}
|
||||
|
||||
SkImageSource::SkImageSource(const SkImage* image)
|
||||
: INHERITED(0, nullptr)
|
||||
, fImage(SkRef(image))
|
||||
, fSrcRect(SkRect::MakeIWH(image->width(), image->height()))
|
||||
, fDstRect(fSrcRect)
|
||||
, fFilterQuality(kHigh_SkFilterQuality) { }
|
||||
|
||||
SkImageSource::SkImageSource(const SkImage* image,
|
||||
const SkRect& srcRect,
|
||||
const SkRect& dstRect,
|
||||
SkFilterQuality filterQuality)
|
||||
: INHERITED(0, nullptr)
|
||||
, fImage(SkRef(image))
|
||||
, fSrcRect(srcRect)
|
||||
, fDstRect(dstRect)
|
||||
, fFilterQuality(filterQuality) { }
|
||||
|
||||
SkFlattenable* SkImageSource::CreateProc(SkReadBuffer& buffer) {
|
||||
SkFilterQuality filterQuality = (SkFilterQuality)buffer.readInt();
|
||||
|
||||
SkRect src, dst;
|
||||
buffer.readRect(&src);
|
||||
buffer.readRect(&dst);
|
||||
|
||||
SkAutoTUnref<SkImage> image(buffer.readImage());
|
||||
if (!image) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return SkImageSource::Create(image, src, dst, filterQuality);
|
||||
}
|
||||
|
||||
void SkImageSource::flatten(SkWriteBuffer& buffer) const {
|
||||
buffer.writeInt(fFilterQuality);
|
||||
buffer.writeRect(fSrcRect);
|
||||
buffer.writeRect(fDstRect);
|
||||
buffer.writeImage(fImage);
|
||||
}
|
||||
|
||||
bool SkImageSource::onFilterImage(Proxy* proxy, const SkBitmap& src, const Context& ctx,
|
||||
SkBitmap* result, SkIPoint* offset) const {
|
||||
SkRect dstRect;
|
||||
ctx.ctm().mapRect(&dstRect, fDstRect);
|
||||
SkRect bounds = SkRect::MakeIWH(fImage->width(), fImage->height());
|
||||
if (fSrcRect == bounds && dstRect == bounds) {
|
||||
// No regions cropped out or resized; return entire image.
|
||||
offset->fX = offset->fY = 0;
|
||||
return fImage->asLegacyBitmap(result, SkImage::kRO_LegacyBitmapMode);
|
||||
}
|
||||
|
||||
const SkIRect dstIRect = dstRect.roundOut();
|
||||
SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(dstIRect.width(), dstIRect.height()));
|
||||
if (nullptr == device.get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkCanvas canvas(device.get());
|
||||
SkPaint paint;
|
||||
|
||||
// Subtract off the integer component of the translation (will be applied in loc, below).
|
||||
dstRect.offset(-SkIntToScalar(dstIRect.fLeft), -SkIntToScalar(dstIRect.fTop));
|
||||
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
|
||||
// FIXME: this probably shouldn't be necessary, but drawImageRect asserts
|
||||
// None filtering when it's translate-only
|
||||
paint.setFilterQuality(
|
||||
fSrcRect.width() == dstRect.width() && fSrcRect.height() == dstRect.height() ?
|
||||
kNone_SkFilterQuality : fFilterQuality);
|
||||
canvas.drawImageRect(fImage, fSrcRect, dstRect, &paint, SkCanvas::kStrict_SrcRectConstraint);
|
||||
|
||||
*result = device.get()->accessBitmap(false);
|
||||
offset->fX = dstIRect.fLeft;
|
||||
offset->fY = dstIRect.fTop;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SkImageSource::computeFastBounds(const SkRect& src, SkRect* dst) const {
|
||||
*dst = fDstRect;
|
||||
}
|
||||
|
||||
#ifndef SK_IGNORE_TO_STRING
|
||||
void SkImageSource::toString(SkString* str) const {
|
||||
str->appendf("SkImageSource: (");
|
||||
str->appendf("src: (%f,%f,%f,%f) dst: (%f,%f,%f,%f) ",
|
||||
fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.fRight, fSrcRect.fBottom,
|
||||
fDstRect.fLeft, fDstRect.fTop, fDstRect.fRight, fDstRect.fBottom);
|
||||
str->appendf("image: (%d,%d)",
|
||||
fImage->width(), fImage->height());
|
||||
str->append(")");
|
||||
}
|
||||
#endif
|
@ -37,6 +37,7 @@
|
||||
#include "SkEmbossMaskFilter.h"
|
||||
#include "SkFlattenable.h"
|
||||
#include "SkGradientShader.h"
|
||||
#include "SkImageSource.h"
|
||||
#include "SkLayerDrawLooper.h"
|
||||
#include "SkLayerRasterizer.h"
|
||||
#include "SkLerpXfermode.h"
|
||||
@ -101,6 +102,7 @@ public:
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkEmbossMaskFilter)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkEmptyShader)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkErodeImageFilter)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageSource)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLayerDrawLooper)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLayerRasterizer)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLerpXfermode)
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "SkEmbossMaskFilter.h"
|
||||
#include "SkFlattenable.h"
|
||||
#include "SkGradientShader.h"
|
||||
#include "SkImageSource.h"
|
||||
#include "SkLayerDrawLooper.h"
|
||||
#include "SkLayerRasterizer.h"
|
||||
#include "SkLerpXfermode.h"
|
||||
@ -80,6 +81,7 @@ public:
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkEmbossMaskFilter)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkEmptyShader)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkErodeImageFilter)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageSource)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLayerDrawLooper)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLayerRasterizer)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLerpXfermode)
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "SkDropShadowImageFilter.h"
|
||||
#include "SkFlattenableSerialization.h"
|
||||
#include "SkGradientShader.h"
|
||||
#include "SkImageSource.h"
|
||||
#include "SkLightingImageFilter.h"
|
||||
#include "SkMatrixConvolutionImageFilter.h"
|
||||
#include "SkMergeImageFilter.h"
|
||||
@ -30,6 +31,7 @@
|
||||
#include "SkReadBuffer.h"
|
||||
#include "SkRect.h"
|
||||
#include "SkRectShaderImageFilter.h"
|
||||
#include "SkSurface.h"
|
||||
#include "SkTableColorFilter.h"
|
||||
#include "SkTileImageFilter.h"
|
||||
#include "SkXfermodeImageFilter.h"
|
||||
@ -1212,6 +1214,30 @@ DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
|
||||
REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
|
||||
}
|
||||
|
||||
// Verify that SkImageSource survives serialization
|
||||
DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
|
||||
SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(10, 10));
|
||||
surface->getCanvas()->clear(SK_ColorGREEN);
|
||||
SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
|
||||
SkAutoTUnref<SkImageFilter> filter(SkImageSource::Create(image));
|
||||
|
||||
SkAutoTUnref<SkData> data(SkValidatingSerializeFlattenable(filter));
|
||||
SkAutoTUnref<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
|
||||
data->data(), data->size(), SkImageFilter::GetFlattenableType()));
|
||||
SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
|
||||
REPORTER_ASSERT(reporter, unflattenedFilter);
|
||||
|
||||
SkBitmap bm;
|
||||
bm.allocN32Pixels(10, 10);
|
||||
SkPaint paint;
|
||||
paint.setColor(SK_ColorRED);
|
||||
paint.setImageFilter(unflattenedFilter);
|
||||
|
||||
SkCanvas canvas(bm);
|
||||
canvas.drawRect(SkRect::MakeWH(10, 10), paint);
|
||||
REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
DEF_GPUTEST(ImageFilterCropRectGPU, reporter, factory) {
|
||||
|
Loading…
Reference in New Issue
Block a user