From 9a264107fbffd9d029fb74e4dea6bc57beb22254 Mon Sep 17 00:00:00 2001 From: robertphillips Date: Mon, 8 Dec 2014 09:18:58 -0800 Subject: [PATCH] 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 --- gm/filterfastbounds.cpp | 336 ++++++++++++++++++++++++++++++++++++++++++++++++ gyp/gmslides.gypi | 1 + 2 files changed, 337 insertions(+) create mode 100644 gm/filterfastbounds.cpp diff --git a/gm/filterfastbounds.cpp b/gm/filterfastbounds.cpp new file mode 100644 index 0000000..6d4d3f1 --- /dev/null +++ b/gm/filterfastbounds.cpp @@ -0,0 +1,336 @@ +/* + * 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* 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* paints) { + { + SkMatrix scale; + scale.setScale(2.0f, 2.0f); + + SkAutoTUnref scaleMIF( + SkMatrixImageFilter::Create(scale, SkPaint::kLow_FilterLevel, source)); + + add_paint(scaleMIF, paints); + } + + { + SkMatrix rot; + rot.setRotate(-33.3f); + + SkAutoTUnref rotMIF( + SkMatrixImageFilter::Create(rot, SkPaint::kLow_FilterLevel, source)); + + add_paint(rotMIF, paints); + } + + { + static const SkDropShadowImageFilter::ShadowMode kBoth = + SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode; + + SkAutoTUnref dsif( + SkDropShadowImageFilter::Create(10.0f, 10.0f, + 3.0f, 3.0f, + SK_ColorRED, kBoth, + source, NULL, 0)); + + add_paint(dsif, paints); + } + + { + SkAutoTUnref dsif( + SkDropShadowImageFilter::Create(27.0f, 27.0f, + 3.0f, 3.0f, + SK_ColorRED, + SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode, + source, NULL, 0)); + + add_paint(dsif, paints); + } + + { + SkAutoTUnref bif(SkBlurImageFilter::Create(3, 3, source)); + + add_paint(bif, paints); + } + + { + SkAutoTUnref 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 paints; + create_paints(NULL, &paints); + + //----------- + // Paints with a PictureImageFilter as a source + SkAutoTUnref pic; + + { + SkPictureRecorder rec; + + SkCanvas* c = rec.beginRecording(10, 10); + c->drawRect(SkRect::MakeWH(10, 10), blackFill); + pic.reset(rec.endRecording()); + } + + SkAutoTUnref pif(SkPictureImageFilter::Create(pic)); + + SkTArray 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 bms(SkBitmapSource::Create(bm)); + + SkTArray 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);) + +} diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi index bba3ea0..35f027e 100644 --- a/gyp/gmslides.gypi +++ b/gyp/gmslides.gypi @@ -84,6 +84,7 @@ '../gm/filltypes.cpp', '../gm/filltypespersp.cpp', '../gm/filterbitmap.cpp', + '../gm/filterfastbounds.cpp', '../gm/filterindiabox.cpp', '../gm/fontcache.cpp', '../gm/fontmgr.cpp', -- 2.7.4