skia2/gm/filterfastbounds.cpp
robertphillips 9a264107fb Add new GM (filterfastbounds)
This new GM visualizes the fast bounds computed by various image-filter-based SkPaints. This is lead up to fixing some issues in fast bound computation.

BUG=418417

Review URL: https://codereview.chromium.org/788613003
2014-12-08 09:18:58 -08:00

337 lines
10 KiB
C++

/*
* Copyright 2014 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 "SkBitmapSource.h"
#include "SkBlurImageFilter.h"
#include "SkDropShadowImageFilter.h"
#include "SkMatrixImageFilter.h"
#include "SkOffsetImageFilter.h"
#include "SkPictureImageFilter.h"
#include "SkPictureRecorder.h"
#include "SkRandom.h"
namespace skiagm {
// Each method of this type must draw its geometry inside 'r' using 'p'
typedef void(*drawMth)(SkCanvas* canvas, const SkRect& r, const SkPaint& p);
static void draw_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
canvas->drawRect(r, p);
}
static void draw_oval(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
canvas->drawOval(r, p);
}
static void draw_rrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
SkScalar xRad = r.width() / 4.0f;
SkScalar yRad = r.height() / 4.0f;
SkRRect rr;
rr.setRectXY(r, xRad, yRad);
canvas->drawRRect(rr, p);
}
static void draw_drrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
SkScalar xRad = r.width() / 4.0f;
SkScalar yRad = r.height() / 4.0f;
SkRRect outer;
outer.setRectXY(r, xRad, yRad);
SkRRect inner = outer;
inner.inset(xRad, yRad);
canvas->drawDRRect(outer, inner, p);
}
static void draw_path(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
SkPath path;
path.moveTo(r.fLeft, r.fTop);
path.lineTo(r.fLeft, r.fBottom);
path.lineTo(r.fRight, r.fBottom);
path.close();
canvas->drawPath(path, p);
}
static void draw_points(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
SkPoint pts0[2] = { { r.fLeft, r.fTop }, { r.fRight, r.fBottom } };
SkPoint pts1[2] = { { r.fLeft, r.fBottom }, { r.fRight, r.fTop } };
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts0, p);
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts1, p);
}
static void draw_bitmap(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
SkBitmap bm;
bm.allocN32Pixels(64, 64);
SkCanvas temp(bm);
temp.clear(SK_ColorMAGENTA);
canvas->drawBitmapRect(bm, r, &p);
}
static const drawMth gDrawMthds[] = {
draw_rect, draw_oval, draw_rrect, draw_drrect, draw_path, draw_points, draw_bitmap
};
static void add_paint(SkImageFilter* filter, SkTArray<SkPaint>* paints) {
SkPaint& p = paints->push_back();
p.setImageFilter(filter);
SkASSERT(p.canComputeFastBounds());
}
// Create a selection of imagefilter-based paints to test
static void create_paints(SkImageFilter* source, SkTArray<SkPaint>* paints) {
{
SkMatrix scale;
scale.setScale(2.0f, 2.0f);
SkAutoTUnref<SkMatrixImageFilter> scaleMIF(
SkMatrixImageFilter::Create(scale, SkPaint::kLow_FilterLevel, source));
add_paint(scaleMIF, paints);
}
{
SkMatrix rot;
rot.setRotate(-33.3f);
SkAutoTUnref<SkMatrixImageFilter> rotMIF(
SkMatrixImageFilter::Create(rot, SkPaint::kLow_FilterLevel, source));
add_paint(rotMIF, paints);
}
{
static const SkDropShadowImageFilter::ShadowMode kBoth =
SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode;
SkAutoTUnref<SkDropShadowImageFilter> dsif(
SkDropShadowImageFilter::Create(10.0f, 10.0f,
3.0f, 3.0f,
SK_ColorRED, kBoth,
source, NULL, 0));
add_paint(dsif, paints);
}
{
SkAutoTUnref<SkDropShadowImageFilter> dsif(
SkDropShadowImageFilter::Create(27.0f, 27.0f,
3.0f, 3.0f,
SK_ColorRED,
SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode,
source, NULL, 0));
add_paint(dsif, paints);
}
{
SkAutoTUnref<SkBlurImageFilter> bif(SkBlurImageFilter::Create(3, 3, source));
add_paint(bif, paints);
}
{
SkAutoTUnref<SkOffsetImageFilter> oif(SkOffsetImageFilter::Create(15, 15, source));
add_paint(oif, paints);
}
}
// This GM visualizes the fast bounds for various combinations of geometry
// and image filter
class ImageFilterFastBoundGM : public GM {
public:
ImageFilterFastBoundGM() {
this->setBGColor(0xFFCCCCCC);
}
protected:
static const int kTileWidth = 100;
static const int kTileHeight = 100;
static const int kNumVertTiles = 6;
static const int kNumXtraCols = 2;
// SkPictureImageFilter doesn't support serialization yet.
uint32_t onGetFlags() const SK_OVERRIDE {
return kSkipPicture_Flag |
kSkipPipe_Flag |
kSkipPipeCrossProcess_Flag |
kSkipTiled_Flag |
kSkipScaledReplay_Flag;
}
SkString onShortName() SK_OVERRIDE{ return SkString("filterfastbounds"); }
SkISize onISize() SK_OVERRIDE{
return SkISize::Make((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols) * kTileWidth,
kNumVertTiles * kTileHeight);
}
static void draw_geom_with_paint(drawMth draw, const SkIPoint& off,
SkCanvas* canvas, const SkPaint& p) {
SkPaint redStroked;
redStroked.setColor(SK_ColorRED);
redStroked.setStyle(SkPaint::kStroke_Style);
SkPaint blueStroked;
blueStroked.setColor(SK_ColorBLUE);
blueStroked.setStyle(SkPaint::kStroke_Style);
const SkRect r = SkRect::MakeLTRB(20, 20, 30, 30);
SkRect storage;
canvas->save();
canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY));
canvas->scale(1.5f, 1.5f);
const SkRect& fastBound = p.computeFastBounds(r, &storage);
canvas->save();
canvas->clipRect(fastBound);
(*draw)(canvas, r, p);
canvas->restore();
canvas->drawRect(r, redStroked);
canvas->drawRect(fastBound, blueStroked);
canvas->restore();
}
static void draw_savelayer_with_paint(const SkIPoint& off,
SkCanvas* canvas,
const SkPaint& p) {
SkPaint redStroked;
redStroked.setColor(SK_ColorRED);
redStroked.setStyle(SkPaint::kStroke_Style);
SkPaint blueStroked;
blueStroked.setColor(SK_ColorBLUE);
blueStroked.setStyle(SkPaint::kStroke_Style);
const SkRect bounds = SkRect::MakeWH(10, 10);
SkRect storage;
canvas->save();
canvas->translate(30, 30);
canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY));
canvas->scale(1.5f, 1.5f);
const SkRect& fastBound = p.computeFastBounds(bounds, &storage);
canvas->saveLayer(&fastBound, &p);
canvas->restore();
canvas->drawRect(bounds, redStroked);
canvas->drawRect(fastBound, blueStroked);
canvas->restore();
}
void onDraw(SkCanvas* canvas) SK_OVERRIDE{
SkPaint blackFill;
//-----------
// Normal paints (no source)
SkTArray<SkPaint> paints;
create_paints(NULL, &paints);
//-----------
// Paints with a PictureImageFilter as a source
SkAutoTUnref<SkPicture> pic;
{
SkPictureRecorder rec;
SkCanvas* c = rec.beginRecording(10, 10);
c->drawRect(SkRect::MakeWH(10, 10), blackFill);
pic.reset(rec.endRecording());
}
SkAutoTUnref<SkPictureImageFilter> pif(SkPictureImageFilter::Create(pic));
SkTArray<SkPaint> pifPaints;
create_paints(pif, &pifPaints);
//-----------
// Paints with a BitmapSource as a source
SkBitmap bm;
{
SkPaint p;
bm.allocN32Pixels(10, 10);
SkCanvas temp(bm);
temp.clear(SK_ColorYELLOW);
p.setColor(SK_ColorBLUE);
temp.drawRect(SkRect::MakeLTRB(5, 5, 10, 10), p);
p.setColor(SK_ColorGREEN);
temp.drawRect(SkRect::MakeLTRB(5, 0, 10, 5), p);
}
SkAutoTUnref<SkBitmapSource> bms(SkBitmapSource::Create(bm));
SkTArray<SkPaint> bmsPaints;
create_paints(bms, &bmsPaints);
//-----------
SkASSERT(paints.count() == kNumVertTiles);
SkASSERT(paints.count() == pifPaints.count());
SkASSERT(paints.count() == bmsPaints.count());
// horizontal separators
for (int i = 1; i < paints.count(); ++i) {
canvas->drawLine(0,
i*SkIntToScalar(kTileHeight),
SkIntToScalar((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols)*kTileWidth),
i*SkIntToScalar(kTileHeight),
blackFill);
}
// vertical separators
for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols; ++i) {
canvas->drawLine(SkIntToScalar(i * kTileWidth),
0,
SkIntToScalar(i * kTileWidth),
SkIntToScalar(paints.count() * kTileWidth),
blackFill);
}
// A column of saveLayers with PictureImageFilters
for (int i = 0; i < pifPaints.count(); ++i) {
draw_savelayer_with_paint(SkIPoint::Make(0, i*kTileHeight),
canvas, pifPaints[i]);
}
// A column of saveLayers with BitmapSources
for (int i = 0; i < pifPaints.count(); ++i) {
draw_savelayer_with_paint(SkIPoint::Make(kTileWidth, i*kTileHeight),
canvas, bmsPaints[i]);
}
// Multiple columns with different geometry
for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds); ++i) {
for (int j = 0; j < paints.count(); ++j) {
draw_geom_with_paint(*gDrawMthds[i],
SkIPoint::Make((i+kNumXtraCols) * kTileWidth, j*kTileHeight),
canvas, paints[j]);
}
}
}
private:
typedef GM INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
DEF_GM(return SkNEW(ImageFilterFastBoundGM);)
}