aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen White <senorblanco@chromium.org>2014-10-27 17:45:31 -0400
committerStephen White <senorblanco@chromium.org>2014-10-27 17:45:31 -0400
commitc38dee4f2c4cac24fa926a51069f04df272b1516 (patch)
tree13f588b1d19e262e43769257eb7cb3ee9baa3c25
parent139c136944f3af0cba3a25ac65c642c05fe46ac8 (diff)
downloadskia-c38dee4f2c4cac24fa926a51069f04df272b1516.tar.gz
[Cherry pick of b0e89dcc1d8c1c2f9f7ffb45e8609cdb4a68104b to M39.]
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 TBR=reed@google.com Review URL: https://codereview.chromium.org/644323006 Review URL: https://codereview.chromium.org/679083004
-rw-r--r--include/core/SkDevice.h5
-rw-r--r--include/pdf/SkPDFDevice.h4
-rw-r--r--src/core/SkCanvas.cpp2
-rw-r--r--src/core/SkDevice.cpp4
-rw-r--r--src/core/SkDeviceImageFilterProxy.h2
-rw-r--r--src/pdf/SkPDFDevice.cpp10
-rw-r--r--tests/PDFPrimitivesTest.cpp52
7 files changed, 72 insertions, 7 deletions
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index 08320bf7b..b19177a31 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 0bfbc36d1..6f770aff6 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 afd7fbef8..75c0b291a 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 63a763364..0ce119b04 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 5ee563484..0b83b1a81 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 43d472702..7369ff853 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 b1d482ffa..05677cd1a 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());
+}