Adding a PictureResolution option to SkPictureImageFilter
This change adds an option to SkPictureImageFilter to make it rasterize SkPicture in a resolution that matches the local coordinate space (equivalent to the record-time device space). BUG=skia:3176 R=reed@google.com, senorblanco@chromium.org Review URL: https://codereview.chromium.org/753073010
This commit is contained in:
parent
367e1867b2
commit
5234075b1c
@ -63,3 +63,6 @@ multipicturedraw_sierpinski_tiled
|
||||
|
||||
#derekf
|
||||
drawbitmapmatrix
|
||||
|
||||
#junov skbug.com/3176
|
||||
pictureimagefilter
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -53,6 +53,7 @@ public:
|
||||
*/
|
||||
kRemoveColorTableAlpha_Version = 36,
|
||||
kDropShadowMode_Version = 37,
|
||||
kPictureImageFilterResolution_Version = 38,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
canvas.translate(-SkIntToScalar(bounds.fLeft), -SkIntToScalar(bounds.fTop));
|
||||
canvas.concat(ctx.ctm());
|
||||
canvas.drawPicture(fPicture);
|
||||
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, proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
|
||||
|
||||
canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
|
||||
canvas.concat(ctx.ctm());
|
||||
canvas.drawPicture(fPicture);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user