dbfd7ab108
'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
235 lines
7.6 KiB
C++
235 lines
7.6 KiB
C++
/*
|
|
* Copyright 2012 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 "SkBlurMask.h"
|
|
#include "SkBlurMaskFilter.h"
|
|
#include "SkCanvas.h"
|
|
#include "SkPath.h"
|
|
|
|
#define STROKE_WIDTH SkIntToScalar(10)
|
|
|
|
typedef void (*Proc)(SkCanvas*, const SkRect&, const SkPaint&);
|
|
|
|
static void fill_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
|
|
canvas->drawRect(r, p);
|
|
}
|
|
|
|
static void draw_donut(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
|
|
SkRect rect;
|
|
SkPath path;
|
|
|
|
rect = r;
|
|
rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2);
|
|
path.addRect(rect);
|
|
rect = r;
|
|
rect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
|
|
|
|
path.addRect(rect);
|
|
path.setFillType(SkPath::kEvenOdd_FillType);
|
|
|
|
canvas->drawPath(path, p);
|
|
}
|
|
|
|
static void draw_donut_skewed(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
|
|
SkRect rect;
|
|
SkPath path;
|
|
|
|
rect = r;
|
|
rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2);
|
|
path.addRect(rect);
|
|
rect = r;
|
|
rect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
|
|
|
|
rect.offset(7, -7);
|
|
|
|
path.addRect(rect);
|
|
path.setFillType(SkPath::kEvenOdd_FillType);
|
|
|
|
canvas->drawPath(path, p);
|
|
}
|
|
|
|
#include "SkGradientShader.h"
|
|
|
|
/*
|
|
* Spits out a dummy gradient to test blur with shader on paint
|
|
*/
|
|
static sk_sp<SkShader> MakeRadial() {
|
|
SkPoint pts[2] = {
|
|
{ 0, 0 },
|
|
{ SkIntToScalar(100), SkIntToScalar(100) }
|
|
};
|
|
SkShader::TileMode tm = SkShader::kClamp_TileMode;
|
|
const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, };
|
|
const SkScalar pos[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
|
|
SkMatrix scale;
|
|
scale.setScale(0.5f, 0.5f);
|
|
scale.postTranslate(25.f, 25.f);
|
|
SkPoint center0, center1;
|
|
center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
|
|
SkScalarAve(pts[0].fY, pts[1].fY));
|
|
center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
|
|
SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
|
|
return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7,
|
|
center0, (pts[1].fX - pts[0].fX) / 2,
|
|
colors, pos, SK_ARRAY_COUNT(colors), tm,
|
|
0, &scale);
|
|
}
|
|
|
|
typedef void (*PaintProc)(SkPaint*, SkScalar width);
|
|
|
|
class BlurRectGM : public skiagm::GM {
|
|
sk_sp<SkMaskFilter> fMaskFilters[kLastEnum_SkBlurStyle + 1];
|
|
SkString fName;
|
|
SkAlpha fAlpha;
|
|
public:
|
|
BlurRectGM(const char name[], U8CPU alpha)
|
|
: fName(name)
|
|
, fAlpha(SkToU8(alpha)) {
|
|
}
|
|
|
|
protected:
|
|
void onOnceBeforeDraw() override {
|
|
for (int i = 0; i <= kLastEnum_SkBlurStyle; ++i) {
|
|
fMaskFilters[i] = SkBlurMaskFilter::Make((SkBlurStyle)i,
|
|
SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(STROKE_WIDTH/2)),
|
|
SkBlurMaskFilter::kHighQuality_BlurFlag);
|
|
}
|
|
}
|
|
|
|
SkString onShortName() override {
|
|
return fName;
|
|
}
|
|
|
|
SkISize onISize() override {
|
|
return SkISize::Make(860, 820);
|
|
}
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
canvas->translate(STROKE_WIDTH*3/2, STROKE_WIDTH*3/2);
|
|
|
|
SkRect r = { 0, 0, 100, 50 };
|
|
SkScalar scales[] = { SK_Scalar1, 0.6f };
|
|
|
|
for (size_t s = 0; s < SK_ARRAY_COUNT(scales); ++s) {
|
|
canvas->save();
|
|
for (size_t f = 0; f < SK_ARRAY_COUNT(fMaskFilters); ++f) {
|
|
SkPaint paint;
|
|
paint.setMaskFilter(fMaskFilters[f]);
|
|
paint.setAlpha(fAlpha);
|
|
|
|
SkPaint paintWithRadial = paint;
|
|
paintWithRadial.setShader(MakeRadial());
|
|
|
|
constexpr Proc procs[] = {
|
|
fill_rect, draw_donut, draw_donut_skewed
|
|
};
|
|
|
|
canvas->save();
|
|
canvas->scale(scales[s], scales[s]);
|
|
this->drawProcs(canvas, r, paint, false, procs, SK_ARRAY_COUNT(procs));
|
|
canvas->translate(r.width() * 4/3, 0);
|
|
this->drawProcs(canvas, r, paintWithRadial, false, procs, SK_ARRAY_COUNT(procs));
|
|
canvas->translate(r.width() * 4/3, 0);
|
|
this->drawProcs(canvas, r, paint, true, procs, SK_ARRAY_COUNT(procs));
|
|
canvas->translate(r.width() * 4/3, 0);
|
|
this->drawProcs(canvas, r, paintWithRadial, true, procs, SK_ARRAY_COUNT(procs));
|
|
canvas->restore();
|
|
|
|
canvas->translate(0, SK_ARRAY_COUNT(procs) * r.height() * 4/3 * scales[s]);
|
|
}
|
|
canvas->restore();
|
|
canvas->translate(4 * r.width() * 4/3 * scales[s], 0);
|
|
}
|
|
}
|
|
|
|
private:
|
|
void drawProcs(SkCanvas* canvas, const SkRect& r, const SkPaint& paint,
|
|
bool doClip, const Proc procs[], size_t procsCount) {
|
|
SkAutoCanvasRestore acr(canvas, true);
|
|
for (size_t i = 0; i < procsCount; ++i) {
|
|
if (doClip) {
|
|
SkRect clipRect(r);
|
|
clipRect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
|
|
canvas->save();
|
|
canvas->clipRect(r);
|
|
}
|
|
procs[i](canvas, r, paint);
|
|
if (doClip) {
|
|
canvas->restore();
|
|
}
|
|
canvas->translate(0, r.height() * 4/3);
|
|
}
|
|
}
|
|
private:
|
|
typedef GM INHERITED;
|
|
};
|
|
|
|
DEF_SIMPLE_GM(blurrect_gallery, canvas, 1200, 1024) {
|
|
const int fGMWidth = 1200;
|
|
const int fPadding = 10;
|
|
const int fMargin = 100;
|
|
|
|
const int widths[] = {25, 5, 5, 100, 150, 25};
|
|
const int heights[] = {100, 100, 5, 25, 150, 25};
|
|
const SkBlurStyle styles[] = {kNormal_SkBlurStyle, kInner_SkBlurStyle, kOuter_SkBlurStyle};
|
|
const float radii[] = {20, 5, 10};
|
|
|
|
canvas->translate(50,20);
|
|
|
|
int cur_x = 0;
|
|
int cur_y = 0;
|
|
|
|
int max_height = 0;
|
|
|
|
for (size_t i = 0 ; i < SK_ARRAY_COUNT(widths) ; i++) {
|
|
int width = widths[i];
|
|
int height = heights[i];
|
|
SkRect r;
|
|
r.setWH(SkIntToScalar(width), SkIntToScalar(height));
|
|
SkAutoCanvasRestore autoRestore(canvas, true);
|
|
|
|
for (size_t j = 0 ; j < SK_ARRAY_COUNT(radii) ; j++) {
|
|
float radius = radii[j];
|
|
for (size_t k = 0 ; k < SK_ARRAY_COUNT(styles) ; k++) {
|
|
SkBlurStyle style = styles[k];
|
|
|
|
SkMask mask;
|
|
if (!SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(radius),
|
|
&mask, r, style)) {
|
|
continue;
|
|
}
|
|
|
|
SkAutoMaskFreeImage amfi(mask.fImage);
|
|
|
|
SkBitmap bm;
|
|
bm.installMaskPixels(mask);
|
|
|
|
if (cur_x + bm.width() >= fGMWidth - fMargin) {
|
|
cur_x = 0;
|
|
cur_y += max_height + fPadding;
|
|
max_height = 0;
|
|
}
|
|
|
|
canvas->save();
|
|
canvas->translate((SkScalar)cur_x, (SkScalar)cur_y);
|
|
canvas->translate(-(bm.width() - r.width())/2, -(bm.height()-r.height())/2);
|
|
canvas->drawBitmap(bm, 0.f, 0.f, nullptr);
|
|
canvas->restore();
|
|
|
|
cur_x += bm.width() + fPadding;
|
|
if (bm.height() > max_height)
|
|
max_height = bm.height();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
DEF_GM(return new BlurRectGM("blurrects", 0xFF);)
|