aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--expectations/gm/ignored-tests.txt3
-rw-r--r--gm/pictureimagefilter.cpp28
-rw-r--r--include/core/SkPicture.h3
-rw-r--r--include/effects/SkPictureImageFilter.h40
-rw-r--r--src/core/SkReadBuffer.h1
-rw-r--r--src/effects/SkPictureImageFilter.cpp74
6 files changed, 129 insertions, 20 deletions
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt
index 77651cca64..eec9c974fc 100644
--- a/expectations/gm/ignored-tests.txt
+++ b/expectations/gm/ignored-tests.txt
@@ -63,3 +63,6 @@ multipicturedraw_sierpinski_tiled
#derekf
drawbitmapmatrix
+
+#junov skbug.com/3176
+pictureimagefilter
diff --git a/gm/pictureimagefilter.cpp b/gm/pictureimagefilter.cpp
index 4e169f77da..712e059a6d 100644
--- a/gm/pictureimagefilter.cpp
+++ b/gm/pictureimagefilter.cpp
@@ -36,7 +36,7 @@ protected:
fPicture.reset(recorder.endRecording());
}
- virtual SkISize onISize() SK_OVERRIDE { return SkISize::Make(500, 150); }
+ virtual SkISize onISize() SK_OVERRIDE { return SkISize::Make(400, 300); }
virtual void onOnceBeforeDraw() SK_OVERRIDE {
this->makePicture();
@@ -57,10 +57,16 @@ protected:
SkRect srcRect = SkRect::MakeXYWH(20, 20, 30, 30);
SkRect emptyRect = SkRect::MakeXYWH(20, 20, 0, 0);
SkRect bounds = SkRect::MakeXYWH(0, 0, 100, 100);
- SkAutoTUnref<SkImageFilter> pictureSource(SkPictureImageFilter::Create(fPicture));
- SkAutoTUnref<SkImageFilter> pictureSourceSrcRect(SkPictureImageFilter::Create(fPicture, srcRect));
- SkAutoTUnref<SkImageFilter> pictureSourceEmptyRect(SkPictureImageFilter::Create(fPicture, emptyRect));
-
+ SkAutoTUnref<SkPictureImageFilter> pictureSource(
+ SkPictureImageFilter::Create(fPicture));
+ SkAutoTUnref<SkPictureImageFilter> pictureSourceSrcRect(
+ SkPictureImageFilter::Create(fPicture, srcRect));
+ SkAutoTUnref<SkPictureImageFilter> pictureSourceEmptyRect(
+ SkPictureImageFilter::Create(fPicture, emptyRect));
+ SkAutoTUnref<SkPictureImageFilter> pictureSourceResampled(
+ SkPictureImageFilter::CreateForLocalSpace(fPicture, fPicture->cullRect()));
+
+ canvas->save();
// Draw the picture unscaled.
fillRectFiltered(canvas, bounds, pictureSource);
canvas->translate(SkIntToScalar(100), 0);
@@ -72,6 +78,18 @@ protected:
// Draw the picture to an empty rect (should draw nothing).
fillRectFiltered(canvas, bounds, pictureSourceEmptyRect);
canvas->translate(SkIntToScalar(100), 0);
+
+ canvas->restore();
+
+ // Draw the picture scaled
+ canvas->translate(0, SkIntToScalar(100));
+ canvas->scale(200 / srcRect.width(), 200 / srcRect.height());
+ canvas->translate(-srcRect.fLeft, -srcRect.fTop);
+ fillRectFiltered(canvas, srcRect, pictureSource);
+
+ // Draw the picture scaled, but rasterized at original resolution
+ canvas->translate(srcRect.width(), 0);
+ fillRectFiltered(canvas, srcRect, pictureSourceResampled);
}
}
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index b3bdda1354..f764d346cc 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -246,13 +246,14 @@ private:
// V35: Store SkRect (rather then width & height) in header
// V36: Remove (obsolete) alphatype from SkColorTable
// V37: Added shadow only option to SkDropShadowImageFilter (last version to record CLEAR)
+ // V37: Added PictureResolution and FilterLevel options to SkPictureImageFilter
// Note: If the picture version needs to be increased then please follow the
// steps to generate new SKPs in (only accessible to Googlers): http://goo.gl/qATVcw
// Only SKPs within the min/current picture version range (inclusive) can be read.
static const uint32_t MIN_PICTURE_VERSION = 35; // Produced by Chrome M39.
- static const uint32_t CURRENT_PICTURE_VERSION = 37;
+ static const uint32_t CURRENT_PICTURE_VERSION = 38;
void createHeader(SkPictInfo* info) const;
static bool IsValidPictInfo(const SkPictInfo& info);
diff --git a/include/effects/SkPictureImageFilter.h b/include/effects/SkPictureImageFilter.h
index f4f1fff4ef..8c3c9c46ec 100644
--- a/include/effects/SkPictureImageFilter.h
+++ b/include/effects/SkPictureImageFilter.h
@@ -24,15 +24,37 @@ public:
* Refs the passed-in picture. cropRect can be used to crop or expand the destination rect when
* the picture is drawn. (No scaling is implied by the dest rect; only the CTM is applied.)
*/
- static SkPictureImageFilter* Create(const SkPicture* picture, const SkRect& cropRect, uint32_t uniqueID = 0) {
- return SkNEW_ARGS(SkPictureImageFilter, (picture, cropRect, uniqueID));
+ static SkPictureImageFilter* Create(const SkPicture* picture, const SkRect& cropRect,
+ uint32_t uniqueID = 0) {
+ return SkNEW_ARGS(SkPictureImageFilter, (picture, cropRect, uniqueID,
+ kDeviceSpace_PictureResolution));
+ }
+
+ /**
+ * Refs the passed-in picture. The picture is rasterized at a resolution that matches the
+ * local coordinate space. If the picture needs to be resampled for drawing it into the
+ * destination canvas, bilinear filtering will be used. cropRect can be used to crop or
+ * expand the destination rect when the picture is drawn. (No scaling is implied by the
+ * dest rect; only the CTM is applied.)
+ */
+ static SkPictureImageFilter* CreateForLocalSpace(const SkPicture* picture,
+ const SkRect& cropRect,
+ uint32_t uniqueID = 0) {
+ return SkNEW_ARGS(SkPictureImageFilter, (picture, cropRect, uniqueID,
+ kLocalSpace_PictureResolution));
}
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPictureImageFilter)
protected:
+ enum PictureResolution {
+ kDeviceSpace_PictureResolution,
+ kLocalSpace_PictureResolution
+ };
+
explicit SkPictureImageFilter(const SkPicture* picture, uint32_t uniqueID);
- SkPictureImageFilter(const SkPicture* picture, const SkRect& cropRect, uint32_t uniqueID);
+ SkPictureImageFilter(const SkPicture* picture, const SkRect& cropRect, uint32_t uniqueID,
+ PictureResolution);
virtual ~SkPictureImageFilter();
/* Constructs an SkPictureImageFilter object from an SkReadBuffer.
* Note: If the SkPictureImageFilter object construction requires bitmap
@@ -45,8 +67,16 @@ protected:
SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
private:
- const SkPicture* fPicture;
- SkRect fCropRect;
+
+
+ void drawPictureAtDeviceResolution(Proxy*, SkBaseDevice*, const SkIRect& deviceBounds,
+ const Context&) const;
+ void drawPictureAtLocalResolution(Proxy*, SkBaseDevice*, const SkIRect& deviceBounds,
+ const Context&) const;
+
+ const SkPicture* fPicture;
+ SkRect fCropRect;
+ PictureResolution fPictureResolution;
typedef SkImageFilter INHERITED;
};
diff --git a/src/core/SkReadBuffer.h b/src/core/SkReadBuffer.h
index 4b14117964..9056b07576 100644
--- a/src/core/SkReadBuffer.h
+++ b/src/core/SkReadBuffer.h
@@ -53,6 +53,7 @@ public:
*/
kRemoveColorTableAlpha_Version = 36,
kDropShadowMode_Version = 37,
+ kPictureImageFilterResolution_Version = 38,
};
/**
diff --git a/src/effects/SkPictureImageFilter.cpp b/src/effects/SkPictureImageFilter.cpp
index 5399ea7476..e18600db6e 100644
--- a/src/effects/SkPictureImageFilter.cpp
+++ b/src/effects/SkPictureImageFilter.cpp
@@ -16,14 +16,16 @@
SkPictureImageFilter::SkPictureImageFilter(const SkPicture* picture, uint32_t uniqueID)
: INHERITED(0, 0, NULL, uniqueID)
, fPicture(SkSafeRef(picture))
- , fCropRect(picture ? picture->cullRect() : SkRect::MakeEmpty()) {
+ , fCropRect(picture ? picture->cullRect() : SkRect::MakeEmpty())
+ , fPictureResolution(kDeviceSpace_PictureResolution) {
}
SkPictureImageFilter::SkPictureImageFilter(const SkPicture* picture, const SkRect& cropRect,
- uint32_t uniqueID)
+ uint32_t uniqueID, PictureResolution pictureResolution)
: INHERITED(0, 0, NULL, uniqueID)
, fPicture(SkSafeRef(picture))
- , fCropRect(cropRect) {
+ , fCropRect(cropRect)
+ , fPictureResolution(pictureResolution) {
}
SkPictureImageFilter::~SkPictureImageFilter() {
@@ -42,7 +44,16 @@ SkFlattenable* SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) {
buffer.validate(!buffer.readBool());
}
buffer.readRect(&cropRect);
+ PictureResolution pictureResolution;
+ if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterResolution_Version)) {
+ pictureResolution = kDeviceSpace_PictureResolution;
+ } else {
+ pictureResolution = (PictureResolution)buffer.readInt();
+ }
+ if (pictureResolution == kLocalSpace_PictureResolution) {
+ return CreateForLocalSpace(picture, cropRect);
+ }
return Create(picture, cropRect);
}
@@ -57,6 +68,7 @@ void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const {
buffer.writeBool(false);
}
buffer.writeRect(fCropRect);
+ buffer.writeInt(fPictureResolution);
}
bool SkPictureImageFilter::onFilterImage(Proxy* proxy, const SkBitmap&, const Context& ctx,
@@ -83,17 +95,61 @@ bool SkPictureImageFilter::onFilterImage(Proxy* proxy, const SkBitmap&, const Co
return false;
}
+ if (kLocalSpace_PictureResolution == fPictureResolution &&
+ (ctx.ctm().getType() & ~SkMatrix::kTranslate_Mask)) {
+ drawPictureAtLocalResolution(proxy, device.get(), bounds, ctx);
+ } else {
+ drawPictureAtDeviceResolution(proxy, device.get(), bounds, ctx);
+ }
+
+ *result = device.get()->accessBitmap(false);
+ offset->fX = bounds.fLeft;
+ offset->fY = bounds.fTop;
+ return true;
+}
+
+void SkPictureImageFilter::drawPictureAtDeviceResolution(Proxy* proxy, SkBaseDevice* device,
+ const SkIRect& deviceBounds,
+ const Context& ctx) const {
// Pass explicit surface props, as the simplified canvas constructor discards device properties.
// FIXME: switch back to the public constructor (and unfriend) after
// https://code.google.com/p/skia/issues/detail?id=3142 is fixed.
- SkCanvas canvas(device.get(), proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
+ SkCanvas canvas(device, proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
- canvas.translate(-SkIntToScalar(bounds.fLeft), -SkIntToScalar(bounds.fTop));
+ canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
canvas.concat(ctx.ctm());
canvas.drawPicture(fPicture);
+}
- *result = device.get()->accessBitmap(false);
- offset->fX = bounds.fLeft;
- offset->fY = bounds.fTop;
- return true;
+void SkPictureImageFilter::drawPictureAtLocalResolution(Proxy* proxy, SkBaseDevice* device,
+ const SkIRect& deviceBounds,
+ const Context& ctx) const {
+ SkMatrix inverseCtm;
+ if (!ctx.ctm().invert(&inverseCtm))
+ return;
+ SkRect localBounds = SkRect::Make(ctx.clipBounds());
+ inverseCtm.mapRect(&localBounds);
+ if (!localBounds.intersect(fCropRect))
+ return;
+ SkIRect localIBounds = localBounds.roundOut();
+ SkAutoTUnref<SkBaseDevice> localDevice(proxy->createDevice(localIBounds.width(), localIBounds.height()));
+
+ // Pass explicit surface props, as the simplified canvas constructor discards device properties.
+ // FIXME: switch back to the public constructor (and unfriend) after
+ // https://code.google.com/p/skia/issues/detail?id=3142 is fixed.
+ SkCanvas localCanvas(localDevice, proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
+ localCanvas.translate(-SkIntToScalar(localIBounds.fLeft), -SkIntToScalar(localIBounds.fTop));
+ localCanvas.drawPicture(fPicture);
+
+ // Pass explicit surface props, as the simplified canvas constructor discards device properties.
+ // FIXME: switch back to the public constructor (and unfriend) after
+ // https://code.google.com/p/skia/issues/detail?id=3142 is fixed.
+ SkCanvas canvas(device, proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
+
+ canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
+ canvas.concat(ctx.ctm());
+ SkPaint paint;
+ paint.setFilterLevel(SkPaint::kLow_FilterLevel);
+ canvas.drawBitmap(localDevice.get()->accessBitmap(false), SkIntToScalar(localIBounds.fLeft), SkIntToScalar(localIBounds.fTop), &paint);
+ //canvas.drawPicture(fPicture);
}