blurrect.cpp revision dac522589e9395b4654a1a708f1bd971f37f95a5
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.h"
9#include "SkBlurMask.h"
10#include "SkBlurMaskFilter.h"
11#include "SkCanvas.h"
12#include "SkPath.h"
13
14#define STROKE_WIDTH    SkIntToScalar(10)
15
16typedef void (*Proc)(SkCanvas*, const SkRect&, const SkPaint&);
17
18static void fill_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
19    canvas->drawRect(r, p);
20}
21
22static void draw_donut(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
23    SkRect  rect;
24    SkPath  path;
25
26    rect = r;
27    rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2);
28    path.addRect(rect);
29    rect = r;
30    rect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
31
32    path.addRect(rect);
33    path.setFillType(SkPath::kEvenOdd_FillType);
34
35    canvas->drawPath(path, p);
36}
37
38static void draw_donut_skewed(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
39    SkRect  rect;
40    SkPath  path;
41
42    rect = r;
43    rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2);
44    path.addRect(rect);
45    rect = r;
46    rect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
47
48    rect.offset(7, -7);
49
50    path.addRect(rect);
51    path.setFillType(SkPath::kEvenOdd_FillType);
52
53    canvas->drawPath(path, p);
54}
55
56#include "SkGradientShader.h"
57
58typedef void (*PaintProc)(SkPaint*, SkScalar width);
59
60class BlurRectGM : public skiagm::GM {
61      SkAutoTUnref<SkMaskFilter> fMaskFilters[SkBlurMaskFilter::kBlurStyleCount];
62      SkString  fName;
63      SkAlpha   fAlpha;
64public:
65    BlurRectGM(const char name[], U8CPU alpha)
66        : fName(name)
67        , fAlpha(SkToU8(alpha)) {
68    }
69
70protected:
71    virtual void onOnceBeforeDraw() SK_OVERRIDE {
72        for (int i = 0; i < SkBlurMaskFilter::kBlurStyleCount; ++i) {
73            fMaskFilters[i].reset(SkBlurMaskFilter::Create((SkBlurMaskFilter::BlurStyle) i,
74                                  SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(STROKE_WIDTH/2)),
75                                  SkBlurMaskFilter::kHighQuality_BlurFlag));
76        }
77    }
78
79    virtual SkString onShortName() {
80        return fName;
81    }
82
83    virtual SkISize onISize() {
84        return SkISize::Make(440, 820);
85    }
86
87    virtual void onDraw(SkCanvas* canvas) {
88        canvas->translate(STROKE_WIDTH*3/2, STROKE_WIDTH*3/2);
89
90        SkRect  r = { 0, 0, 100, 50 };
91        SkScalar scales[] = { SK_Scalar1, 0.6f };
92
93        for (size_t s = 0; s < SK_ARRAY_COUNT(scales); ++s) {
94            canvas->save();
95            for (size_t f = 0; f < SK_ARRAY_COUNT(fMaskFilters); ++f) {
96                SkPaint paint;
97                paint.setMaskFilter(fMaskFilters[f]);
98                paint.setAlpha(fAlpha);
99
100                static const Proc procs[] = {
101                    fill_rect, draw_donut, draw_donut_skewed
102                };
103
104                canvas->save();
105                canvas->scale(scales[s], scales[s]);
106                this->drawProcs(canvas, r, paint, false, procs, SK_ARRAY_COUNT(procs));
107                canvas->translate(r.width() * 4/3, 0);
108                this->drawProcs(canvas, r, paint, true, procs, SK_ARRAY_COUNT(procs));
109                canvas->restore();
110
111                canvas->translate(0, SK_ARRAY_COUNT(procs) * r.height() * 4/3 * scales[s]);
112            }
113            canvas->restore();
114            canvas->translate(2 * r.width() * 4/3 * scales[s], 0);
115        }
116    }
117
118    virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; }
119
120private:
121    void drawProcs(SkCanvas* canvas, const SkRect& r, const SkPaint& paint,
122                   bool doClip, const Proc procs[], size_t procsCount) {
123        SkAutoCanvasRestore acr(canvas, true);
124        for (size_t i = 0; i < procsCount; ++i) {
125            if (doClip) {
126                SkRect clipRect(r);
127                clipRect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
128                canvas->save();
129                canvas->clipRect(r);
130            }
131            procs[i](canvas, r, paint);
132            if (doClip) {
133                canvas->restore();
134            }
135            canvas->translate(0, r.height() * 4/3);
136        }
137    }
138private:
139    typedef GM INHERITED;
140};
141
142class BlurRectCompareGM : public skiagm::GM {
143    SkString  fName;
144    unsigned int fRectWidth, fRectHeight;
145    SkScalar fRadius;
146    SkBlurMask::Style fStyle;
147public:
148    BlurRectCompareGM(const char name[], unsigned int rectWidth,
149                      unsigned int rectHeight, float radius,
150                      SkBlurMask::Style style)
151        : fName(name)
152        , fRectWidth(rectWidth)
153        , fRectHeight(rectHeight)
154        , fRadius(radius)
155        , fStyle(style) {
156    }
157    int width() const {
158        return fRectWidth;
159    }
160    int height() const {
161        return fRectHeight;
162    }
163    SkScalar radius() const {
164        return fRadius;
165    }
166    SkBlurMask::Style style() const {
167        return fStyle;
168    }
169
170protected:
171    virtual SkString onShortName() {
172        return fName;
173    }
174
175    virtual SkISize onISize() {
176        return SkISize::Make(640, 480);
177    }
178
179    virtual bool makeMask(SkMask *m, const SkRect&) = 0;
180
181    virtual void onDraw(SkCanvas* canvas) {
182        SkRect r;
183        r.setWH(SkIntToScalar(fRectWidth), SkIntToScalar(fRectHeight));
184
185        SkISize canvas_size = canvas->getDeviceSize();
186        int center_x = (canvas_size.fWidth - (int)(r.width()))/2;
187        int center_y = (canvas_size.fHeight - (int)(r.height()))/2;
188
189        SkMask mask;
190
191        if (!this->makeMask(&mask, r)) {
192            SkPaint paint;
193            r.offset( SkIntToScalar(center_x), SkIntToScalar(center_y) );
194            canvas->drawRect(r,paint);
195            return;
196        }
197        SkAutoMaskFreeImage amfi(mask.fImage);
198
199        SkBitmap bm;
200        bm.installMaskPixels(mask);
201
202        center_x = (canvas_size.fWidth - mask.fBounds.width())/2;
203        center_y = (canvas_size.fHeight - mask.fBounds.height())/2;
204
205        canvas->drawBitmap(bm, SkIntToScalar(center_x), SkIntToScalar(center_y), NULL);
206    }
207
208    virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; }
209
210private:
211    typedef GM INHERITED;
212};
213
214class BlurRectFastGM: public BlurRectCompareGM {
215public:
216    BlurRectFastGM(const char name[], unsigned int rectWidth,
217                   unsigned int rectHeight, float blurRadius,
218                   SkBlurMask::Style style) :
219        INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
220        }
221
222protected:
223    virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
224        return SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(this->radius()),
225                                    m, r, this->style());
226    }
227private:
228    typedef BlurRectCompareGM INHERITED;
229};
230
231class BlurRectSlowGM: public BlurRectCompareGM {
232public:
233    BlurRectSlowGM(const char name[], unsigned int rectWidth, unsigned int rectHeight,
234                   float blurRadius, SkBlurMask::Style style)
235        : INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
236        }
237
238protected:
239    virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
240        SkMask src;
241        r.roundOut(&src.fBounds);
242        src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop);  // move to origin
243        src.fFormat = SkMask::kA8_Format;
244        src.fRowBytes = src.fBounds.width();
245        src.fImage = SkMask::AllocImage(src.computeTotalImageSize());
246        SkAutoMaskFreeImage amfi(src.fImage);
247
248        memset(src.fImage, 0xff, src.computeTotalImageSize());
249
250        return SkBlurMask::BoxBlur(m, src,
251                                   SkBlurMask::ConvertRadiusToSigma(this->radius()),
252                                   this->style(), this->getQuality());
253    }
254
255    virtual SkBlurMask::Quality getQuality() {
256        return SkBlurMask::kHigh_Quality;
257    }
258private:
259    typedef BlurRectCompareGM INHERITED;
260};
261
262class BlurRectSlowLowGM: public BlurRectSlowGM {
263public:
264    BlurRectSlowLowGM(const char name[], unsigned int rectWidth, unsigned int rectHeight,
265                      float blurRadius, SkBlurMask::Style style)
266        : INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
267        }
268
269protected:
270    virtual SkBlurMask::Quality getQuality() SK_OVERRIDE {
271        return SkBlurMask::kLow_Quality;
272    }
273private:
274    typedef BlurRectSlowGM INHERITED;
275};
276
277class BlurRectGroundTruthGM: public BlurRectCompareGM {
278public:
279    BlurRectGroundTruthGM(const char name[], unsigned int rectWidth, unsigned int rectHeight,
280                          float blurRadius, SkBlurMask::Style style)
281        : INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
282        }
283
284protected:
285    virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
286        SkMask src;
287        r.roundOut(&src.fBounds);
288        src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop);  // move to origin
289        src.fFormat = SkMask::kA8_Format;
290        src.fRowBytes = src.fBounds.width();
291        src.fImage = SkMask::AllocImage(src.computeTotalImageSize());
292        SkAutoMaskFreeImage amfi(src.fImage);
293
294        memset(src.fImage, 0xff, src.computeTotalImageSize());
295
296        return SkBlurMask::BlurGroundTruth(SkBlurMask::ConvertRadiusToSigma(this->radius()),
297                                           m, src, this->style());
298    }
299
300    virtual SkBlurMask::Quality getQuality() {
301        return SkBlurMask::kHigh_Quality;
302    }
303private:
304    typedef BlurRectCompareGM INHERITED;
305};
306
307
308//////////////////////////////////////////////////////////////////////////////
309
310DEF_GM(return new BlurRectGM("blurrects", 0xFF);)
311
312static const SkScalar kBig = 20;
313static const SkScalar kSmall = 2;
314
315// regular size rects, blurs should be small enough not to completely overlap.
316
317DEF_GM(return new BlurRectFastGM( "blurrect_25_100_2_normal_fast", 25, 100, kSmall, SkBlurMask::kNormal_Style);)
318DEF_GM(return new BlurRectFastGM("blurrect_25_100_20_normal_fast", 25, 100, kBig, SkBlurMask::kNormal_Style);)
319DEF_GM(return new BlurRectSlowGM( "blurrect_25_100_2_normal_slow", 25, 100, kSmall, SkBlurMask::kNormal_Style);)
320DEF_GM(return new BlurRectSlowGM("blurrect_25_100_20_normal_slow", 25, 100, kBig, SkBlurMask::kNormal_Style);)
321DEF_GM(return new BlurRectFastGM( "blurrect_25_100_2_inner_fast", 25, 100, kSmall, SkBlurMask::kInner_Style);)
322DEF_GM(return new BlurRectFastGM("blurrect_25_100_20_inner_fast", 25, 100, kBig, SkBlurMask::kInner_Style);)
323DEF_GM(return new BlurRectSlowGM( "blurrect_25_100_2_inner_slow", 25, 100, kSmall, SkBlurMask::kInner_Style);)
324DEF_GM(return new BlurRectSlowGM("blurrect_25_100_20_inner_slow", 25, 100, kBig, SkBlurMask::kInner_Style);)
325DEF_GM(return new BlurRectFastGM( "blurrect_25_100_2_outer_fast", 25, 100, kSmall, SkBlurMask::kOuter_Style);)
326DEF_GM(return new BlurRectFastGM("blurrect_25_100_20_outer_fast", 25, 100, kBig, SkBlurMask::kOuter_Style);)
327DEF_GM(return new BlurRectSlowGM( "blurrect_25_100_2_outer_slow", 25, 100, kSmall, SkBlurMask::kOuter_Style);)
328DEF_GM(return new BlurRectSlowGM("blurrect_25_100_20_outer_slow", 25, 100, kBig, SkBlurMask::kOuter_Style);)
329
330// skinny tall rects, blurs overlap in X but not y
331
332DEF_GM(return new BlurRectFastGM( "blurrect_5_100_2_normal_fast", 5, 100, kSmall, SkBlurMask::kNormal_Style);)
333DEF_GM(return new BlurRectFastGM("blurrect_5_100_20_normal_fast", 5, 100, kBig, SkBlurMask::kNormal_Style);)
334DEF_GM(return new BlurRectSlowGM( "blurrect_5_100_2_normal_slow", 5, 100, kSmall, SkBlurMask::kNormal_Style);)
335DEF_GM(return new BlurRectSlowGM("blurrect_5_100_20_normal_slow", 5, 100, kBig, SkBlurMask::kNormal_Style);)
336DEF_GM(return new BlurRectFastGM( "blurrect_5_100_2_inner_fast", 5, 100, kSmall, SkBlurMask::kInner_Style);)
337DEF_GM(return new BlurRectFastGM("blurrect_5_100_20_inner_fast", 5, 100, kBig, SkBlurMask::kInner_Style);)
338DEF_GM(return new BlurRectSlowGM( "blurrect_5_100_2_inner_slow", 5, 100, kSmall, SkBlurMask::kInner_Style);)
339DEF_GM(return new BlurRectSlowGM("blurrect_5_100_20_inner_slow", 5, 100, kBig, SkBlurMask::kInner_Style);)
340DEF_GM(return new BlurRectFastGM( "blurrect_5_100_2_outer_fast", 5, 100, kSmall, SkBlurMask::kOuter_Style);)
341DEF_GM(return new BlurRectFastGM("blurrect_5_100_20_outer_fast", 5, 100, kBig, SkBlurMask::kOuter_Style);)
342DEF_GM(return new BlurRectSlowGM( "blurrect_5_100_2_outer_slow", 5, 100, kSmall, SkBlurMask::kOuter_Style);)
343DEF_GM(return new BlurRectSlowGM("blurrect_5_100_20_outer_slow", 5, 100, kBig, SkBlurMask::kOuter_Style);)
344
345// tiny rects, blurs overlap in X and Y
346
347DEF_GM(return new BlurRectFastGM( "blurrect_5_5_2_normal_fast", 5, 5, kSmall, SkBlurMask::kNormal_Style);)
348DEF_GM(return new BlurRectFastGM("blurrect_5_5_20_normal_fast", 5, 5, kBig, SkBlurMask::kNormal_Style);)
349DEF_GM(return new BlurRectSlowGM( "blurrect_5_5_2_normal_slow", 5, 5, kSmall, SkBlurMask::kNormal_Style);)
350DEF_GM(return new BlurRectSlowGM("blurrect_5_5_20_normal_slow", 5, 5, kBig, SkBlurMask::kNormal_Style);)
351DEF_GM(return new BlurRectFastGM( "blurrect_5_5_2_inner_fast", 5, 5, kSmall, SkBlurMask::kInner_Style);)
352DEF_GM(return new BlurRectFastGM("blurrect_5_5_20_inner_fast", 5, 5, kBig, SkBlurMask::kInner_Style);)
353DEF_GM(return new BlurRectSlowGM( "blurrect_5_5_2_inner_slow", 5, 5, kSmall, SkBlurMask::kInner_Style);)
354DEF_GM(return new BlurRectSlowGM("blurrect_5_5_20_inner_slow", 5, 5, kBig, SkBlurMask::kInner_Style);)
355DEF_GM(return new BlurRectFastGM( "blurrect_5_5_2_outer_fast", 5, 5, kSmall, SkBlurMask::kOuter_Style);)
356DEF_GM(return new BlurRectFastGM("blurrect_5_5_20_outer_fast", 5, 5, kBig, SkBlurMask::kOuter_Style);)
357DEF_GM(return new BlurRectSlowGM( "blurrect_5_5_2_outer_slow", 5, 5, kSmall, SkBlurMask::kOuter_Style);)
358DEF_GM(return new BlurRectSlowGM("blurrect_5_5_20_outer_slow", 5, 5, kBig, SkBlurMask::kOuter_Style);)
359
360
361#if 0
362// dont' need to GM the gaussian convolution; it's slow and intended
363// as a ground truth comparison only.  Leaving these here in case we
364// ever want to turn these back on for debugging reasons.
365DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_1_simple", 25, 100, 1);)
366DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_2_simple", 25, 100, 2);)
367DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_3_simple", 25, 100, 3);)
368DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_4_simple", 25, 100, 4);)
369DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_5_simple", 25, 100, 5);)
370DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_6_simple", 25, 100, 6);)
371DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_7_simple", 25, 100, 7);)
372DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_8_simple", 25, 100, 8);)
373DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_9_simple", 25, 100, 9);)
374DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_10_simple", 25, 100, 10);)
375DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_11_simple", 25, 100, 11);)
376DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_12_simple", 25, 100, 12);)
377DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_13_simple", 25, 100, 13);)
378DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_14_simple", 25, 100, 14);)
379DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_15_simple", 25, 100, 15);)
380DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_16_simple", 25, 100, 16);)
381DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_17_simple", 25, 100, 17);)
382DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_18_simple", 25, 100, 18);)
383DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_19_simple", 25, 100, 19);)
384#endif
385