Implement an SkPicture image filter source. This is required for the external-SVG reference feature of feImage. It simply plays back an SkPicture to a given destination rect.

R=reed@google.com

Review URL: https://codereview.chromium.org/114263002

git-svn-id: http://skia.googlecode.com/svn/trunk@12661 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
senorblanco@chromium.org 2013-12-12 23:28:52 +00:00
parent 6b8dbb668f
commit 533330065a
5 changed files with 203 additions and 0 deletions

82
gm/pictureimagefilter.cpp Normal file
View File

@ -0,0 +1,82 @@
/*
* 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 "SkPictureImageFilter.h"
// This GM exercises the SkPictureImageFilter ImageFilter class.
class PictureImageFilterGM : public skiagm::GM {
public:
PictureImageFilterGM() {
}
protected:
virtual SkString onShortName() SK_OVERRIDE {
return SkString("pictureimagefilter");
}
void makePicture() {
SkCanvas* canvas = fPicture.beginRecording(100, 100);
canvas->clear(0x00000000);
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(0xFFFFFFFF);
paint.setTextSize(SkIntToScalar(96));
const char* str = "e";
canvas->drawText(str, strlen(str), SkIntToScalar(20), SkIntToScalar(70), paint);
fPicture.endRecording();
}
virtual SkISize onISize() SK_OVERRIDE { return SkISize::Make(500, 150); }
virtual void onOnceBeforeDraw() SK_OVERRIDE {
this->makePicture();
}
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();
}
virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
canvas->clear(0x00000000);
{
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(new SkPictureImageFilter(&fPicture));
SkAutoTUnref<SkImageFilter> pictureSourceSrcRect(new SkPictureImageFilter(&fPicture, srcRect));
SkAutoTUnref<SkImageFilter> pictureSourceEmptyRect(new SkPictureImageFilter(&fPicture, emptyRect));
// Draw the picture unscaled.
fillRectFiltered(canvas, bounds, pictureSource);
canvas->translate(SkIntToScalar(100), 0);
// Draw an unscaled subset of the source picture.
fillRectFiltered(canvas, bounds, pictureSourceSrcRect);
canvas->translate(SkIntToScalar(100), 0);
// Draw the picture to an empty rect (should draw nothing).
fillRectFiltered(canvas, bounds, pictureSourceEmptyRect);
canvas->translate(SkIntToScalar(100), 0);
}
}
private:
SkPicture fPicture;
typedef GM INHERITED;
};
///////////////////////////////////////////////////////////////////////////////
DEF_GM( return new PictureImageFilterGM; )

View File

@ -48,6 +48,7 @@
'<(skia_src_path)/effects/SkOffsetImageFilter.cpp',
'<(skia_src_path)/effects/SkPaintFlagsDrawFilter.cpp',
'<(skia_src_path)/effects/SkPerlinNoiseShader.cpp',
'<(skia_src_path)/effects/SkPictureImageFilter.cpp',
'<(skia_src_path)/effects/SkPixelXorXfermode.cpp',
'<(skia_src_path)/effects/SkPorterDuff.cpp',
'<(skia_src_path)/effects/SkRectShaderImageFilter.cpp',

View File

@ -105,6 +105,7 @@
'../gm/pathopsskpclip.cpp',
'../gm/pathreverse.cpp',
'../gm/perlinnoise.cpp',
'../gm/pictureimagefilter.cpp',
'../gm/points.cpp',
'../gm/poly2poly.cpp',
'../gm/polygons.cpp',

View File

@ -0,0 +1,42 @@
/*
* Copyright 2013 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPictureImageFilter_DEFINED
#define SkPictureImageFilter_DEFINED
#include "SkImageFilter.h"
#include "SkPicture.h"
class SK_API SkPictureImageFilter : public SkImageFilter {
public:
/**
* Refs the passed-in picture.
*/
explicit SkPictureImageFilter(SkPicture* picture);
/**
* Refs the passed-in picture. rect 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.)
*/
SkPictureImageFilter(SkPicture* picture, const SkRect& rect);
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPictureImageFilter)
protected:
virtual ~SkPictureImageFilter();
explicit SkPictureImageFilter(SkFlattenableReadBuffer& buffer);
virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
private:
SkPicture* fPicture;
SkRect fRect;
typedef SkImageFilter INHERITED;
};
#endif

View File

@ -0,0 +1,77 @@
/*
* Copyright 2013 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkPictureImageFilter.h"
#include "SkDevice.h"
#include "SkCanvas.h"
#include "SkFlattenableBuffers.h"
#include "SkValidationUtils.h"
SkPictureImageFilter::SkPictureImageFilter(SkPicture* picture)
: INHERITED(0, 0),
fPicture(picture),
fRect(SkRect::MakeWH(picture ? SkIntToScalar(picture->width()) : 0,
picture ? SkIntToScalar(picture->height()) : 0)) {
SkSafeRef(fPicture);
}
SkPictureImageFilter::SkPictureImageFilter(SkPicture* picture, const SkRect& rect)
: INHERITED(0, 0),
fPicture(picture),
fRect(rect) {
SkSafeRef(fPicture);
}
SkPictureImageFilter::~SkPictureImageFilter() {
SkSafeUnref(fPicture);
}
SkPictureImageFilter::SkPictureImageFilter(SkFlattenableReadBuffer& buffer)
: INHERITED(0, buffer),
fPicture(NULL) {
// FIXME: unflatten picture here.
buffer.readRect(&fRect);
}
void SkPictureImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
// FIXME: flatten picture here.
buffer.writeRect(fRect);
}
bool SkPictureImageFilter::onFilterImage(Proxy* proxy, const SkBitmap&, const SkMatrix& matrix,
SkBitmap* result, SkIPoint* offset) {
if (!fPicture) {
return true;
}
SkRect floatBounds;
SkIRect bounds;
matrix.mapRect(&floatBounds, fRect);
floatBounds.roundOut(&bounds);
if (bounds.isEmpty()) {
return true;
}
SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
if (NULL == device.get()) {
return false;
}
SkCanvas canvas(device.get());
SkPaint paint;
canvas.translate(-SkIntToScalar(bounds.fLeft), -SkIntToScalar(bounds.fTop));
canvas.concat(matrix);
canvas.drawPicture(*fPicture);
*result = device.get()->accessBitmap(false);
offset->fX += bounds.fLeft;
offset->fY += bounds.fTop;
return true;
}