--- /dev/null
+/*
+ * 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; )
'<(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',
'<(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',
--- /dev/null
+/*
+ * 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
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,
#include "SkBitmap.h"
#include "SkErrorInternals.h"
+#include "SkImage.h"
+#include "SkImageGenerator.h"
#include "SkReadBuffer.h"
#include "SkStream.h"
#include "SkTypeface.h"
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();
#include "SkXfermode.h"
class SkBitmap;
+class SkImage;
#if defined(SK_DEBUG) && defined(SK_BUILD_FOR_MAC)
#define DEBUG_NON_DETERMINISTIC_ASSERT
*/
bool readBitmap(SkBitmap* bitmap);
+ SkImage* readImage();
+
virtual SkTypeface* readTypeface();
void setBitmapStorage(SkBitmapHeapReader* bitmapStorage) {
--- /dev/null
+/*
+ * 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
#include "SkEmbossMaskFilter.h"
#include "SkFlattenable.h"
#include "SkGradientShader.h"
+#include "SkImageSource.h"
#include "SkLayerDrawLooper.h"
#include "SkLayerRasterizer.h"
#include "SkLerpXfermode.h"
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)
#include "SkEmbossMaskFilter.h"
#include "SkFlattenable.h"
#include "SkGradientShader.h"
+#include "SkImageSource.h"
#include "SkLayerDrawLooper.h"
#include "SkLayerRasterizer.h"
#include "SkLerpXfermode.h"
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)
#include "SkDropShadowImageFilter.h"
#include "SkFlattenableSerialization.h"
#include "SkGradientShader.h"
+#include "SkImageSource.h"
#include "SkLightingImageFilter.h"
#include "SkMatrixConvolutionImageFilter.h"
#include "SkMergeImageFilter.h"
#include "SkReadBuffer.h"
#include "SkRect.h"
#include "SkRectShaderImageFilter.h"
+#include "SkSurface.h"
#include "SkTableColorFilter.h"
#include "SkTileImageFilter.h"
#include "SkXfermodeImageFilter.h"
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) {