diff options
author | 2014-10-20 14:03:12 -0700 | |
---|---|---|
committer | 2014-10-20 14:03:13 -0700 | |
commit | b0e89dcc1d8c1c2f9f7ffb45e8609cdb4a68104b (patch) | |
tree | 1661cc79e593b0225c6224664d08ad192c5b2902 | |
parent | 1d932663e12dc5f56a66bb764c9f36eb3bab9502 (diff) |
Fix image filters for PDF backend.
Currently, the PDF backend does not support image filters (since PDF
does not have that functionality), so it simply removes them. This is
causing Chrome print preview to render incorrectly (see bug). The fix
here is to fall back to a raster device for image filters, as we used
to do in Blink. The resulting bitmap will be drawn to the destination
device as a normal main-memory-backed bitmap.
Note: this change invalidates the PDF results of all GMs containing
image filters (since they'll actually be rendered).
BUG=422144
Review URL: https://codereview.chromium.org/644323006
-rw-r--r-- | expectations/gm/ignored-tests.txt | 31 | ||||
-rw-r--r-- | include/core/SkDevice.h | 5 | ||||
-rw-r--r-- | include/pdf/SkPDFDevice.h | 4 | ||||
-rw-r--r-- | src/core/SkCanvas.cpp | 2 | ||||
-rw-r--r-- | src/core/SkDevice.cpp | 4 | ||||
-rw-r--r-- | src/core/SkDeviceImageFilterProxy.h | 2 | ||||
-rw-r--r-- | src/pdf/SkPDFDevice.cpp | 10 | ||||
-rw-r--r-- | tests/PDFPrimitivesTest.cpp | 52 |
8 files changed, 103 insertions, 7 deletions
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt index 86cc83ce21..5f16953307 100644 --- a/expectations/gm/ignored-tests.txt +++ b/expectations/gm/ignored-tests.txt @@ -57,3 +57,34 @@ imagefiltersbase # jvanverth - adding color emoji to df text dftext + +# senorblanco https://codereview.chromium.org/644323006/ +# PDF backend now supports image filters +bitmapsource +colorfilterimagefilter +displacement +dropshadowimagefilter +imagealphathreshold +imageblur +imageblur2 +imageblur_large +imageblurtiled +imagefiltersbase +imagefiltersclipped +imagefilterscropexpand +imagefilterscropped +imagefiltersgraph +imagefiltersscaled +imagemagnifier +imageresizetiled +lighting +matrixconvolution +matriximagefilter +morphology +offsetimagefilter +pictureimagefilter +resizeimagefilter +spritebitmap +testimagefilters +tileimagefilter +xfermodeimagefilter diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h index fb3c206e9e..5984681622 100644 --- a/include/core/SkDevice.h +++ b/include/core/SkDevice.h @@ -121,7 +121,8 @@ public: protected: enum Usage { kGeneral_Usage, - kSaveLayer_Usage // <! internal use only + kSaveLayer_Usage, // <! internal use only + kImageFilter_Usage // <! internal use only }; struct TextFlags { @@ -368,6 +369,8 @@ private: void setOrigin(int x, int y) { fOrigin.set(x, y); } // just called by SkCanvas for saveLayer SkBaseDevice* createCompatibleDeviceForSaveLayer(const SkImageInfo&); + // just called by SkCanvas for imagefilter + SkBaseDevice* createCompatibleDeviceForImageFilter(const SkImageInfo&); virtual SkBaseDevice* onCreateDevice(const SkImageInfo&, Usage) { return NULL; diff --git a/include/pdf/SkPDFDevice.h b/include/pdf/SkPDFDevice.h index 0ada5312ae..f6f782b99a 100644 --- a/include/pdf/SkPDFDevice.h +++ b/include/pdf/SkPDFDevice.h @@ -213,10 +213,6 @@ protected: return fLegacyBitmap; } - virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { - return false; - } - virtual SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) SK_OVERRIDE; private: diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 709cb4c0be..2f7fcf4d4b 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -933,7 +933,7 @@ int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Save if (paint && paint->getImageFilter()) { device = this->getDevice(); if (device) { - device = device->createCompatibleDevice(info); + device = device->createCompatibleDeviceForImageFilter(info); } } else { device = this->createLayerDevice(info); diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 0623f9909e..b912e6aef0 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -36,6 +36,10 @@ SkBaseDevice* SkBaseDevice::createCompatibleDeviceForSaveLayer(const SkImageInfo return this->onCreateDevice(info, kSaveLayer_Usage); } +SkBaseDevice* SkBaseDevice::createCompatibleDeviceForImageFilter(const SkImageInfo& info) { + return this->onCreateDevice(info, kImageFilter_Usage); +} + SkMetaData& SkBaseDevice::getMetaData() { // metadata users are rare, so we lazily allocate it. If that changes we // can decide to just make it a field in the device (rather than a ptr) diff --git a/src/core/SkDeviceImageFilterProxy.h b/src/core/SkDeviceImageFilterProxy.h index 5ee563484e..0b83b1a81e 100644 --- a/src/core/SkDeviceImageFilterProxy.h +++ b/src/core/SkDeviceImageFilterProxy.h @@ -15,7 +15,7 @@ public: SkDeviceImageFilterProxy(SkBaseDevice* device) : fDevice(device) {} virtual SkBaseDevice* createDevice(int w, int h) SK_OVERRIDE { - return fDevice->createCompatibleDevice(SkImageInfo::MakeN32Premul(w, h)); + return fDevice->createCompatibleDeviceForImageFilter(SkImageInfo::MakeN32Premul(w, h)); } virtual bool canHandleImageFilter(const SkImageFilter* filter) SK_OVERRIDE { return fDevice->canHandleImageFilter(filter); diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index 736c50b9a6..8509de86fc 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -8,6 +8,7 @@ #include "SkPDFDevice.h" #include "SkAnnotation.h" +#include "SkBitmapDevice.h" #include "SkColor.h" #include "SkClipStack.h" #include "SkData.h" @@ -567,6 +568,15 @@ void GraphicStackState::updateDrawingState(const GraphicStateEntry& state) { } SkBaseDevice* SkPDFDevice::onCreateDevice(const SkImageInfo& info, Usage usage) { + // PDF does not support image filters, so render them on CPU. + // Note that this rendering is done at "screen" resolution (100dpi), not + // printer resolution. + // FIXME: It may be possible to express some filters natively using PDF + // to improve quality and file size (http://skbug.com/3043) + if (kImageFilter_Usage == usage) { + return SkBitmapDevice::Create(info); + } + SkMatrix initialTransform; initialTransform.reset(); SkISize size = SkISize::Make(info.width(), info.height()); diff --git a/tests/PDFPrimitivesTest.cpp b/tests/PDFPrimitivesTest.cpp index b1d482ffa2..05677cd1ab 100644 --- a/tests/PDFPrimitivesTest.cpp +++ b/tests/PDFPrimitivesTest.cpp @@ -15,6 +15,7 @@ #include "SkPDFDevice.h" #include "SkPDFStream.h" #include "SkPDFTypes.h" +#include "SkReadBuffer.h" #include "SkScalar.h" #include "SkStream.h" #include "SkTypes.h" @@ -428,3 +429,54 @@ DEF_TEST(PDFPrimitives, reporter) { TestImages(reporter); } + +namespace { + +class DummyImageFilter : public SkImageFilter { +public: + DummyImageFilter(bool visited = false) : SkImageFilter(0, NULL), fVisited(visited) {} + virtual ~DummyImageFilter() SK_OVERRIDE {} + virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&, + SkBitmap* result, SkIPoint* offset) const { + fVisited = true; + offset->fX = offset->fY = 0; + *result = src; + return true; + } + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(DummyImageFilter) +#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING + explicit DummyImageFilter(SkReadBuffer& buffer) : SkImageFilter(0, NULL) { + fVisited = buffer.readBool(); + } +#endif + bool visited() const { return fVisited; } + +private: + mutable bool fVisited; +}; + +SkFlattenable* DummyImageFilter::CreateProc(SkReadBuffer& buffer) { + SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0); + bool visited = buffer.readBool(); + return SkNEW_ARGS(DummyImageFilter, (visited)); +} + +}; + +// Check that PDF rendering of image filters successfully falls back to +// CPU rasterization. +DEF_TEST(PDFImageFilter, reporter) { + SkISize pageSize = SkISize::Make(100, 100); + SkAutoTUnref<SkPDFDevice> device(new SkPDFDevice(pageSize, pageSize, SkMatrix::I())); + SkCanvas canvas(device.get()); + SkAutoTUnref<DummyImageFilter> filter(new DummyImageFilter()); + + // Filter just created; should be unvisited. + REPORTER_ASSERT(reporter, !filter->visited()); + SkPaint paint; + paint.setImageFilter(filter.get()); + canvas.drawRect(SkRect::MakeWH(100, 100), paint); + + // Filter was used in rendering; should be visited. + REPORTER_ASSERT(reporter, filter->visited()); +} |