blurrect.cpp revision b3ec29d2d81ae391e433fbdf8aabc791e426ee38
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
60static const char* gBlurStyle2Name[] = {
61    "normal",
62    "solid",
63    "outer",
64    "inner"
65};
66
67class BlurRectGM : public skiagm::GM {
68      SkAutoTUnref<SkMaskFilter> fMaskFilter;
69      SkString  fName;
70      PaintProc fPProc;
71      SkAlpha   fAlpha;
72public:
73    BlurRectGM(const char name[], PaintProc pproc, U8CPU alpha,
74               SkBlurMaskFilter::BlurStyle bs)
75               : fMaskFilter(SkBlurMaskFilter::Create(bs,
76                             SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(STROKE_WIDTH/2)),
77                             SkBlurMaskFilter::kHighQuality_BlurFlag))
78               , fName(name)
79               , fPProc(pproc)
80               , fAlpha(SkToU8(alpha)) {
81        fName.appendf("_%s", gBlurStyle2Name[bs]);
82    }
83
84protected:
85    virtual SkString onShortName() {
86        return fName;
87    }
88
89    virtual SkISize onISize() {
90        return SkISize::Make(640, 480);
91    }
92
93    virtual void onDraw(SkCanvas* canvas) {
94        canvas->translate(STROKE_WIDTH*3/2, STROKE_WIDTH*3/2);
95
96        SkRect  r = { 0, 0, 250, 120 };
97
98        SkPaint paint;
99        paint.setMaskFilter(fMaskFilter);
100        if (fPProc) {
101            fPProc(&paint, r.width());
102        }
103        paint.setAlpha(fAlpha);
104
105        static const Proc procs[] = {
106            fill_rect, draw_donut, draw_donut_skewed
107        };
108
109        this->drawProcs(canvas, r, paint, false, procs, SK_ARRAY_COUNT(procs));
110        canvas->translate(r.width() * 4/3, 0);
111        this->drawProcs(canvas, r, paint, true, procs, SK_ARRAY_COUNT(procs));
112    }
113
114    virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; }
115
116private:
117    void drawProcs(SkCanvas* canvas, const SkRect& r, const SkPaint& paint,
118                   bool doClip, const Proc procs[], size_t procsCount) {
119        SkAutoCanvasRestore acr(canvas, true);
120        for (size_t i = 0; i < procsCount; ++i) {
121            if (doClip) {
122                SkRect clipRect(r);
123                clipRect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
124                canvas->save();
125                canvas->clipRect(r);
126            }
127            procs[i](canvas, r, paint);
128            if (doClip) {
129                canvas->restore();
130            }
131            canvas->translate(0, r.height() * 4/3);
132        }
133    }
134private:
135    typedef GM INHERITED;
136};
137
138class BlurRectCompareGM : public skiagm::GM {
139    SkString  fName;
140    unsigned int fRectWidth, fRectHeight;
141    SkScalar fRadius;
142    SkBlurMask::Style fStyle;
143public:
144    BlurRectCompareGM(const char name[], unsigned int rectWidth,
145                      unsigned int rectHeight, float radius,
146                      SkBlurMask::Style style)
147        : fName(name)
148        , fRectWidth(rectWidth)
149        , fRectHeight(rectHeight)
150        , fRadius(radius)
151        , fStyle(style) {
152    }
153    int width() const {
154        return fRectWidth;
155    }
156    int height() const {
157        return fRectHeight;
158    }
159    SkScalar radius() const {
160        return fRadius;
161    }
162    SkBlurMask::Style style() const {
163        return fStyle;
164    }
165
166protected:
167    virtual SkString onShortName() {
168        return fName;
169    }
170
171    virtual SkISize onISize() {
172        return SkISize::Make(640, 480);
173    }
174
175    virtual bool makeMask(SkMask *m, const SkRect&) = 0;
176
177    virtual void onDraw(SkCanvas* canvas) {
178        SkRect r;
179        r.setWH(SkIntToScalar(fRectWidth), SkIntToScalar(fRectHeight));
180
181        SkISize canvas_size = canvas->getDeviceSize();
182        int center_x = (canvas_size.fWidth - (int)(r.width()))/2;
183        int center_y = (canvas_size.fHeight - (int)(r.height()))/2;
184
185        SkMask mask;
186
187        if (!this->makeMask(&mask, r)) {
188            SkPaint paint;
189            r.offset( SkIntToScalar(center_x), SkIntToScalar(center_y) );
190            canvas->drawRect(r,paint);
191            return;
192        }
193        SkAutoMaskFreeImage amfi(mask.fImage);
194
195        SkBitmap bm;
196        bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height());
197        bm.setPixels(mask.fImage);
198
199        center_x = (canvas_size.fWidth - mask.fBounds.width())/2;
200        center_y = (canvas_size.fHeight - mask.fBounds.height())/2;
201
202        canvas->drawBitmap(bm, SkIntToScalar(center_x), SkIntToScalar(center_y), NULL);
203    }
204
205    virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; }
206
207private:
208    typedef GM INHERITED;
209};
210
211class BlurRectFastGM: public BlurRectCompareGM {
212public:
213    BlurRectFastGM(const char name[], unsigned int rectWidth,
214                   unsigned int rectHeight, float blurRadius,
215                   SkBlurMask::Style style) :
216        INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
217        }
218
219protected:
220    virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
221        return SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(this->radius()),
222                                    m, r, this->style());
223    }
224private:
225    typedef BlurRectCompareGM INHERITED;
226};
227
228class BlurRectSlowGM: public BlurRectCompareGM {
229public:
230    BlurRectSlowGM(const char name[], unsigned int rectWidth, unsigned int rectHeight,
231                   float blurRadius, SkBlurMask::Style style)
232        : INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
233        }
234
235protected:
236    virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
237        SkMask src;
238        r.roundOut(&src.fBounds);
239        src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop);  // move to origin
240        src.fFormat = SkMask::kA8_Format;
241        src.fRowBytes = src.fBounds.width();
242        src.fImage = SkMask::AllocImage(src.computeTotalImageSize());
243        SkAutoMaskFreeImage amfi(src.fImage);
244
245        memset(src.fImage, 0xff, src.computeTotalImageSize());
246
247        return SkBlurMask::BoxBlur(m, src,
248                                   SkBlurMask::ConvertRadiusToSigma(this->radius()),
249                                   this->style(), this->getQuality());
250    }
251
252    virtual SkBlurMask::Quality getQuality() {
253        return SkBlurMask::kHigh_Quality;
254    }
255private:
256    typedef BlurRectCompareGM INHERITED;
257};
258
259class BlurRectSlowLowGM: public BlurRectSlowGM {
260public:
261    BlurRectSlowLowGM(const char name[], unsigned int rectWidth, unsigned int rectHeight,
262                      float blurRadius, SkBlurMask::Style style)
263        : INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
264        }
265
266protected:
267    virtual SkBlurMask::Quality getQuality() SK_OVERRIDE {
268        return SkBlurMask::kLow_Quality;
269    }
270private:
271    typedef BlurRectSlowGM INHERITED;
272};
273
274class BlurRectGroundTruthGM: public BlurRectCompareGM {
275public:
276    BlurRectGroundTruthGM(const char name[], unsigned int rectWidth, unsigned int rectHeight,
277                          float blurRadius, SkBlurMask::Style style)
278        : INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
279        }
280
281protected:
282    virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
283        SkMask src;
284        r.roundOut(&src.fBounds);
285        src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop);  // move to origin
286        src.fFormat = SkMask::kA8_Format;
287        src.fRowBytes = src.fBounds.width();
288        src.fImage = SkMask::AllocImage(src.computeTotalImageSize());
289        SkAutoMaskFreeImage amfi(src.fImage);
290
291        memset(src.fImage, 0xff, src.computeTotalImageSize());
292
293        return SkBlurMask::BlurGroundTruth(SkBlurMask::ConvertRadiusToSigma(this->radius()),
294                                           m, src, this->style());
295    }
296
297    virtual SkBlurMask::Quality getQuality() {
298        return SkBlurMask::kHigh_Quality;
299    }
300private:
301    typedef BlurRectCompareGM INHERITED;
302};
303
304
305//////////////////////////////////////////////////////////////////////////////
306
307DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kNormal_BlurStyle);)
308DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kSolid_BlurStyle);)
309DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kOuter_BlurStyle);)
310DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kInner_BlurStyle);)
311
312static const SkScalar kBig = SkFloatToScalar(20);
313static const SkScalar kSmall = SkFloatToScalar(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