skia2/gm/filterfastbounds.cpp
Ben Wagner 7fde8e1728 IWYU for gms.
This almost gets gms to be iwyu clean. The last bit is around gm.cpp
and the tracing framework and its use of atomic. Will also need a way
of keeping things from regressing, which is difficult due to needing to
do this outside-in.

Change-Id: I1393531e99da8b0f1a29f55c53c86d53f459af7d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/211593
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
2019-05-02 17:48:53 +00:00

343 lines
11 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/gm.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkFilterQuality.h"
#include "include/core/SkImage.h"
#include "include/core/SkImageFilter.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPath.h"
#include "include/core/SkPicture.h"
#include "include/core/SkPictureRecorder.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRRect.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
#include "include/core/SkSurface.h"
#include "include/core/SkTypes.h"
#include "include/effects/SkBlurImageFilter.h"
#include "include/effects/SkDropShadowImageFilter.h"
#include "include/effects/SkImageSource.h"
#include "include/effects/SkOffsetImageFilter.h"
#include "include/effects/SkPictureImageFilter.h"
#include "include/effects/SkTileImageFilter.h"
#include "include/private/SkTArray.h"
#include <utility>
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);
}
constexpr drawMth gDrawMthds[] = {
draw_rect, draw_oval, draw_rrect, draw_drrect, draw_path, draw_points, draw_bitmap
};
static void add_paint(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> filter) {
SkPaint& p = paints->push_back();
p.setImageFilter(std::move(filter));
SkASSERT(p.canComputeFastBounds());
}
// Create a selection of imagefilter-based paints to test
static void create_paints(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> source) {
{
SkMatrix scale;
scale.setScale(2.0f, 2.0f);
sk_sp<SkImageFilter> scaleMIF(
SkImageFilter::MakeMatrixFilter(scale, kLow_SkFilterQuality, source));
add_paint(paints, std::move(scaleMIF));
}
{
SkMatrix rot;
rot.setRotate(-33.3f);
sk_sp<SkImageFilter> rotMIF(
SkImageFilter::MakeMatrixFilter(rot, kLow_SkFilterQuality, source));
add_paint(paints, std::move(rotMIF));
}
{
SkRect src = SkRect::MakeXYWH(20, 20, 10, 10);
SkRect dst = SkRect::MakeXYWH(30, 30, 30, 30);
sk_sp<SkImageFilter> tileIF(SkTileImageFilter::Make(src, dst, nullptr));
add_paint(paints, std::move(tileIF));
}
{
constexpr SkDropShadowImageFilter::ShadowMode kBoth =
SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode;
sk_sp<SkImageFilter> dsif(SkDropShadowImageFilter::Make(10.0f, 10.0f,
3.0f, 3.0f,
SK_ColorRED, kBoth,
source));
add_paint(paints, std::move(dsif));
}
{
sk_sp<SkImageFilter> dsif(
SkDropShadowImageFilter::Make(27.0f, 27.0f,
3.0f, 3.0f,
SK_ColorRED,
SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode,
source));
add_paint(paints, std::move(dsif));
}
add_paint(paints, SkBlurImageFilter::Make(3, 3, source));
add_paint(paints, SkOffsetImageFilter::Make(15, 15, source));
}
// 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 constexpr int kTileWidth = 100;
static constexpr int kTileHeight = 100;
static constexpr int kNumVertTiles = 7;
static constexpr int kNumXtraCols = 2;
SkString onShortName() override{ return SkString("filterfastbounds"); }
SkISize onISize() 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) override{
SkPaint blackFill;
//-----------
// Normal paints (no source)
SkTArray<SkPaint> paints;
create_paints(&paints, nullptr);
//-----------
// Paints with a PictureImageFilter as a source
sk_sp<SkPicture> pic;
{
SkPictureRecorder rec;
SkCanvas* c = rec.beginRecording(10, 10);
c->drawRect(SkRect::MakeWH(10, 10), blackFill);
pic = rec.finishRecordingAsPicture();
}
SkTArray<SkPaint> pifPaints;
create_paints(&pifPaints, SkPictureImageFilter::Make(pic));
//-----------
// Paints with a SkImageSource as a source
auto surface(SkSurface::MakeRasterN32Premul(10, 10));
{
SkPaint p;
SkCanvas* temp = surface->getCanvas();
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);
}
sk_sp<SkImage> image(surface->makeImageSnapshot());
sk_sp<SkImageFilter> imageSource(SkImageSource::Make(std::move(image)));
SkTArray<SkPaint> bmsPaints;
create_paints(&bmsPaints, std::move(imageSource));
//-----------
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 new ImageFilterFastBoundGM;)
}