aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar fmalita <fmalita@chromium.org>2015-09-14 13:31:18 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-09-14 13:31:18 -0700
commitcd56f812e09fdd8f8322c5c28cbc4423a74b9a0a (patch)
tree7b4b54c3a4f7b89653635820d28026971b9b076a
parent506c802a3dd3b6dc8a172621ff2a1f9bda202a13 (diff)
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
-rw-r--r--gm/imagesource.cpp80
-rw-r--r--gyp/effects.gypi2
-rw-r--r--include/effects/SkImageSource.h48
-rw-r--r--src/core/SkPictureData.cpp38
-rw-r--r--src/core/SkReadBuffer.cpp42
-rw-r--r--src/core/SkReadBuffer.h3
-rw-r--r--src/effects/SkImageSource.cpp118
-rw-r--r--src/ports/SkGlobalInitialization_chromium.cpp2
-rw-r--r--src/ports/SkGlobalInitialization_default.cpp2
-rw-r--r--tests/ImageFilterTest.cpp26
10 files changed, 324 insertions, 37 deletions
diff --git a/gm/imagesource.cpp b/gm/imagesource.cpp
new file mode 100644
index 0000000000..f4574d267c
--- /dev/null
+++ b/gm/imagesource.cpp
@@ -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; )
diff --git a/gyp/effects.gypi b/gyp/effects.gypi
index 053942484a..188be80d0e 100644
--- a/gyp/effects.gypi
+++ b/gyp/effects.gypi
@@ -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',
diff --git a/include/effects/SkImageSource.h b/include/effects/SkImageSource.h
new file mode 100644
index 0000000000..56c6a6e96a
--- /dev/null
+++ b/include/effects/SkImageSource.h
@@ -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
diff --git a/src/core/SkPictureData.cpp b/src/core/SkPictureData.cpp
index 9d497f676a..9ed98cf4ff 100644
--- a/src/core/SkPictureData.cpp
+++ b/src/core/SkPictureData.cpp
@@ -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,
diff --git a/src/core/SkReadBuffer.cpp b/src/core/SkReadBuffer.cpp
index 00e3e2c1ce..4a1d44f0bf 100644
--- a/src/core/SkReadBuffer.cpp
+++ b/src/core/SkReadBuffer.cpp
@@ -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();
diff --git a/src/core/SkReadBuffer.h b/src/core/SkReadBuffer.h
index 06b5a77abd..3d6dd362ac 100644
--- a/src/core/SkReadBuffer.h
+++ b/src/core/SkReadBuffer.h
@@ -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) {
diff --git a/src/effects/SkImageSource.cpp b/src/effects/SkImageSource.cpp
new file mode 100644
index 0000000000..8f8c72b75c
--- /dev/null
+++ b/src/effects/SkImageSource.cpp
@@ -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
diff --git a/src/ports/SkGlobalInitialization_chromium.cpp b/src/ports/SkGlobalInitialization_chromium.cpp
index 04ca841e5f..e0c7d191b3 100644
--- a/src/ports/SkGlobalInitialization_chromium.cpp
+++ b/src/ports/SkGlobalInitialization_chromium.cpp
@@ -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)
diff --git a/src/ports/SkGlobalInitialization_default.cpp b/src/ports/SkGlobalInitialization_default.cpp
index 0d05c1dcb7..73e4f5a902 100644
--- a/src/ports/SkGlobalInitialization_default.cpp
+++ b/src/ports/SkGlobalInitialization_default.cpp
@@ -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)
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index 8c3206680a..8444bd38c3 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -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) {