|  | /* | 
|  | * 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> make_radial() { | 
|  | 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(make_radial()); | 
|  |  | 
|  | 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);) |