skia2/gm/filterfastbounds.cpp
mtklein dbfd7ab108 Replace a lot of 'static const' with 'constexpr' or 'const'.
'static const' means, there must be at most one of these, and initialize it at
compile time if possible or runtime if necessary.  This leads to unexpected
code execution, and TSAN* will complain about races on the guard variables.

Generally 'constexpr' or 'const' are better choices.  Neither can cause races:
they're either intialized at compile time (constexpr) or intialized each time
independently (const).

This CL prefers constexpr where possible, and uses const where not.  It even
prefers constexpr over const where they don't make a difference... I want to have
lots of examples of constexpr for people to see and mimic.

The scoped-to-class static has nothing to do with any of this, and is not changed.

* Not yet on the bots, which use an older TSAN.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2300623005

Review-Url: https://codereview.chromium.org/2300623005
2016-09-01 11:24:54 -07:00

323 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 "SkBlurImageFilter.h"
#include "SkDropShadowImageFilter.h"
#include "SkImageSource.h"
#include "SkOffsetImageFilter.h"
#include "SkPictureImageFilter.h"
#include "SkPictureRecorder.h"
#include "SkRandom.h"
#include "SkSurface.h"
#include "SkTileImageFilter.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);
}
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(sk_tool_utils::color_to_565(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;)
}