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