• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7 
8 #include "gm/gm.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkBlurTypes.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkMaskFilter.h"
14 #include "include/core/SkMatrix.h"
15 #include "include/core/SkPaint.h"
16 #include "include/core/SkPath.h"
17 #include "include/core/SkPoint.h"
18 #include "include/core/SkRect.h"
19 #include "include/core/SkRefCnt.h"
20 #include "include/core/SkScalar.h"
21 #include "include/core/SkShader.h"
22 #include "include/core/SkSize.h"
23 #include "include/core/SkString.h"
24 #include "include/core/SkTileMode.h"
25 #include "include/core/SkTypes.h"
26 #include "include/effects/SkGradientShader.h"
27 #include "include/private/SkTo.h"
28 #include "src/core/SkBlurMask.h"
29 #include "src/core/SkMask.h"
30 
31 #define STROKE_WIDTH    SkIntToScalar(10)
32 
33 typedef void (*Proc)(SkCanvas*, const SkRect&, const SkPaint&);
34 
fill_rect(SkCanvas * canvas,const SkRect & r,const SkPaint & p)35 static void fill_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
36     canvas->drawRect(r, p);
37 }
38 
draw_donut(SkCanvas * canvas,const SkRect & r,const SkPaint & p)39 static void draw_donut(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
40     SkRect  rect;
41     SkPath  path;
42 
43     rect = r;
44     rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2);
45     path.addRect(rect);
46     rect = r;
47     rect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
48 
49     path.addRect(rect);
50     path.setFillType(SkPath::kEvenOdd_FillType);
51 
52     canvas->drawPath(path, p);
53 }
54 
draw_donut_skewed(SkCanvas * canvas,const SkRect & r,const SkPaint & p)55 static void draw_donut_skewed(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
56     SkRect  rect;
57     SkPath  path;
58 
59     rect = r;
60     rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2);
61     path.addRect(rect);
62     rect = r;
63     rect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
64 
65     rect.offset(7, -7);
66 
67     path.addRect(rect);
68     path.setFillType(SkPath::kEvenOdd_FillType);
69 
70     canvas->drawPath(path, p);
71 }
72 
73 /*
74  * Spits out a dummy gradient to test blur with shader on paint
75  */
make_radial()76 static sk_sp<SkShader> make_radial() {
77     SkPoint pts[2] = {
78         { 0, 0 },
79         { SkIntToScalar(100), SkIntToScalar(100) }
80     };
81     SkTileMode tm = SkTileMode::kClamp;
82     const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, };
83     const SkScalar pos[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
84     SkMatrix scale;
85     scale.setScale(0.5f, 0.5f);
86     scale.postTranslate(25.f, 25.f);
87     SkPoint center0, center1;
88     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
89                 SkScalarAve(pts[0].fY, pts[1].fY));
90     center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
91                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
92     return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7,
93                                                  center0, (pts[1].fX - pts[0].fX) / 2,
94                                                  colors, pos, SK_ARRAY_COUNT(colors), tm,
95                                                  0, &scale);
96 }
97 
98 typedef void (*PaintProc)(SkPaint*, SkScalar width);
99 
100 class BlurRectGM : public skiagm::GM {
101 public:
BlurRectGM(const char name[],U8CPU alpha)102     BlurRectGM(const char name[], U8CPU alpha) : fName(name), fAlpha(SkToU8(alpha)) {}
103 
104 private:
105     sk_sp<SkMaskFilter> fMaskFilters[kLastEnum_SkBlurStyle + 1];
106     const char* fName;
107     SkAlpha fAlpha;
108 
onOnceBeforeDraw()109     void onOnceBeforeDraw() override {
110         for (int i = 0; i <= kLastEnum_SkBlurStyle; ++i) {
111             fMaskFilters[i] = SkMaskFilter::MakeBlur((SkBlurStyle)i,
112                                   SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(STROKE_WIDTH/2)));
113         }
114     }
115 
onShortName()116     SkString onShortName() override { return SkString(fName); }
117 
onISize()118     SkISize onISize() override { return {860, 820}; }
119 
onDraw(SkCanvas * canvas)120     void onDraw(SkCanvas* canvas) override {
121         canvas->translate(STROKE_WIDTH*3/2, STROKE_WIDTH*3/2);
122 
123         SkRect  r = { 0, 0, 100, 50 };
124         SkScalar scales[] = { SK_Scalar1, 0.6f };
125 
126         for (size_t s = 0; s < SK_ARRAY_COUNT(scales); ++s) {
127             canvas->save();
128             for (size_t f = 0; f < SK_ARRAY_COUNT(fMaskFilters); ++f) {
129                 SkPaint paint;
130                 paint.setMaskFilter(fMaskFilters[f]);
131                 paint.setAlpha(fAlpha);
132 
133                 SkPaint paintWithRadial = paint;
134                 paintWithRadial.setShader(make_radial());
135 
136                 constexpr Proc procs[] = {
137                     fill_rect, draw_donut, draw_donut_skewed
138                 };
139 
140                 canvas->save();
141                 canvas->scale(scales[s], scales[s]);
142                 this->drawProcs(canvas, r, paint, false, procs, SK_ARRAY_COUNT(procs));
143                 canvas->translate(r.width() * 4/3, 0);
144                 this->drawProcs(canvas, r, paintWithRadial, false, procs, SK_ARRAY_COUNT(procs));
145                 canvas->translate(r.width() * 4/3, 0);
146                 this->drawProcs(canvas, r, paint, true, procs, SK_ARRAY_COUNT(procs));
147                 canvas->translate(r.width() * 4/3, 0);
148                 this->drawProcs(canvas, r, paintWithRadial, true, procs, SK_ARRAY_COUNT(procs));
149                 canvas->restore();
150 
151                 canvas->translate(0, SK_ARRAY_COUNT(procs) * r.height() * 4/3 * scales[s]);
152             }
153             canvas->restore();
154             canvas->translate(4 * r.width() * 4/3 * scales[s], 0);
155         }
156     }
157 
drawProcs(SkCanvas * canvas,const SkRect & r,const SkPaint & paint,bool doClip,const Proc procs[],size_t procsCount)158     void drawProcs(SkCanvas* canvas, const SkRect& r, const SkPaint& paint,
159                    bool doClip, const Proc procs[], size_t procsCount) {
160         SkAutoCanvasRestore acr(canvas, true);
161         for (size_t i = 0; i < procsCount; ++i) {
162             if (doClip) {
163                 SkRect clipRect(r);
164                 clipRect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
165                 canvas->save();
166                 canvas->clipRect(r);
167             }
168             procs[i](canvas, r, paint);
169             if (doClip) {
170                 canvas->restore();
171             }
172             canvas->translate(0, r.height() * 4/3);
173         }
174     }
175 };
176 
177 DEF_SIMPLE_GM(blurrect_gallery, canvas, 1200, 1024) {
178         const int fGMWidth = 1200;
179         const int fPadding = 10;
180         const int fMargin = 100;
181 
182         const int widths[] = {25, 5, 5, 100, 150, 25};
183         const int heights[] = {100, 100, 5, 25, 150, 25};
184         const SkBlurStyle styles[] = {kNormal_SkBlurStyle, kInner_SkBlurStyle, kOuter_SkBlurStyle};
185         const float radii[] = {20, 5, 10};
186 
187         canvas->translate(50,20);
188 
189         int cur_x = 0;
190         int cur_y = 0;
191 
192         int max_height = 0;
193 
194         for (size_t i = 0 ; i < SK_ARRAY_COUNT(widths) ; i++) {
195             int width = widths[i];
196             int height = heights[i];
197             SkRect r;
198             r.setWH(SkIntToScalar(width), SkIntToScalar(height));
199             SkAutoCanvasRestore autoRestore(canvas, true);
200 
201             for (size_t j = 0 ; j < SK_ARRAY_COUNT(radii) ; j++) {
202                 float radius = radii[j];
203                 for (size_t k = 0 ; k < SK_ARRAY_COUNT(styles) ; k++) {
204                     SkBlurStyle style = styles[k];
205 
206                     SkMask mask;
207                     if (!SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(radius),
208                                               &mask, r, style)) {
209                         continue;
210                     }
211 
212                     SkAutoMaskFreeImage amfi(mask.fImage);
213 
214                     SkBitmap bm;
215                     bm.installMaskPixels(mask);
216 
217                     if (cur_x + bm.width() >= fGMWidth - fMargin) {
218                         cur_x = 0;
219                         cur_y += max_height + fPadding;
220                         max_height = 0;
221                     }
222 
223                     canvas->save();
224                     canvas->translate((SkScalar)cur_x, (SkScalar)cur_y);
225                     canvas->translate(-(bm.width() - r.width())/2, -(bm.height()-r.height())/2);
226                     canvas->drawBitmap(bm, 0.f, 0.f, nullptr);
227                     canvas->restore();
228 
229                     cur_x += bm.width() + fPadding;
230                     if (bm.height() > max_height)
231                         max_height = bm.height();
232                 }
233             }
234         }
235 }
236 
237 //////////////////////////////////////////////////////////////////////////////
238 
239 DEF_GM(return new BlurRectGM("blurrects", 0xFF);)
240