fb3ee379031e01801e687d22502b81b38bce3ba2
[platform/upstream/libSkiaSharp.git] / gm / blurrect.cpp
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
16 typedef void (*Proc)(SkCanvas*, const SkRect&, const SkPaint&);
17
18 static void fill_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
19     canvas->drawRect(r, p);
20 }
21
22 static 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
38 static 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
58 /*
59  * Spits out a dummy gradient to test blur with shader on paint
60  */
61 static SkShader* MakeRadial() {
62     SkPoint pts[2] = {
63         { 0, 0 },
64         { SkIntToScalar(100), SkIntToScalar(100) }
65     };
66     SkShader::TileMode tm = SkShader::kClamp_TileMode;
67     const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, };
68     const SkScalar pos[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
69     SkMatrix scale;
70     scale.setScale(0.5f, 0.5f);
71     scale.postTranslate(25.f, 25.f);
72     SkPoint center0, center1;
73     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
74                 SkScalarAve(pts[0].fY, pts[1].fY));
75     center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
76                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
77     return SkGradientShader::CreateTwoPointRadial(center1, (pts[1].fX - pts[0].fX) / 7,
78                                                   center0, (pts[1].fX - pts[0].fX) / 2,
79                                                   colors, pos, SK_ARRAY_COUNT(colors), tm,
80                                                   0, &scale);
81 }
82
83 typedef void (*PaintProc)(SkPaint*, SkScalar width);
84
85 class BlurRectGM : public skiagm::GM {
86       SkAutoTUnref<SkMaskFilter> fMaskFilters[kLastEnum_SkBlurStyle + 1];
87       SkString  fName;
88       SkAlpha   fAlpha;
89 public:
90     BlurRectGM(const char name[], U8CPU alpha)
91         : fName(name)
92         , fAlpha(SkToU8(alpha)) {
93     }
94
95 protected:
96     void onOnceBeforeDraw() SK_OVERRIDE {
97         for (int i = 0; i <= kLastEnum_SkBlurStyle; ++i) {
98             fMaskFilters[i].reset(SkBlurMaskFilter::Create((SkBlurStyle)i,
99                                   SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(STROKE_WIDTH/2)),
100                                   SkBlurMaskFilter::kHighQuality_BlurFlag));
101         }
102     }
103
104     SkString onShortName() SK_OVERRIDE {
105         return fName;
106     }
107
108     SkISize onISize() SK_OVERRIDE {
109         return SkISize::Make(860, 820);
110     }
111
112     void onDraw(SkCanvas* canvas) SK_OVERRIDE {
113         canvas->translate(STROKE_WIDTH*3/2, STROKE_WIDTH*3/2);
114
115         SkRect  r = { 0, 0, 100, 50 };
116         SkScalar scales[] = { SK_Scalar1, 0.6f };
117
118         for (size_t s = 0; s < SK_ARRAY_COUNT(scales); ++s) {
119             canvas->save();
120             for (size_t f = 0; f < SK_ARRAY_COUNT(fMaskFilters); ++f) {
121                 SkPaint paint;
122                 paint.setMaskFilter(fMaskFilters[f]);
123                 paint.setAlpha(fAlpha);
124
125                 SkPaint paintWithRadial = paint;
126                 paintWithRadial.setShader(MakeRadial())->unref();
127
128                 static const Proc procs[] = {
129                     fill_rect, draw_donut, draw_donut_skewed
130                 };
131
132                 canvas->save();
133                 canvas->scale(scales[s], scales[s]);
134                 this->drawProcs(canvas, r, paint, false, procs, SK_ARRAY_COUNT(procs));
135                 canvas->translate(r.width() * 4/3, 0);
136                 this->drawProcs(canvas, r, paintWithRadial, false, procs, SK_ARRAY_COUNT(procs));
137                 canvas->translate(r.width() * 4/3, 0);
138                 this->drawProcs(canvas, r, paint, true, procs, SK_ARRAY_COUNT(procs));
139                 canvas->translate(r.width() * 4/3, 0);
140                 this->drawProcs(canvas, r, paintWithRadial, true, procs, SK_ARRAY_COUNT(procs));
141                 canvas->restore();
142
143                 canvas->translate(0, SK_ARRAY_COUNT(procs) * r.height() * 4/3 * scales[s]);
144             }
145             canvas->restore();
146             canvas->translate(4 * r.width() * 4/3 * scales[s], 0);
147         }
148     }
149
150 private:
151     void drawProcs(SkCanvas* canvas, const SkRect& r, const SkPaint& paint,
152                    bool doClip, const Proc procs[], size_t procsCount) {
153         SkAutoCanvasRestore acr(canvas, true);
154         for (size_t i = 0; i < procsCount; ++i) {
155             if (doClip) {
156                 SkRect clipRect(r);
157                 clipRect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
158                 canvas->save();
159                 canvas->clipRect(r);
160             }
161             procs[i](canvas, r, paint);
162             if (doClip) {
163                 canvas->restore();
164             }
165             canvas->translate(0, r.height() * 4/3);
166         }
167     }
168 private:
169     typedef GM INHERITED;
170 };
171
172
173 class BlurRectDirectGM : public skiagm::GM {
174     SkString  fName;
175     int fGMWidth, fGMHeight;
176     int fPadding, fMargin;
177 public:
178     BlurRectDirectGM(const char name[])
179         : fName(name),
180           fGMWidth(1200),
181           fGMHeight(1024),
182           fPadding(10),
183           fMargin(100)
184     {
185     }
186
187 protected:
188     virtual SkString onShortName() {
189         return fName;
190     }
191
192     virtual SkISize onISize() {
193         return SkISize::Make(fGMWidth, fGMHeight);
194     }
195
196     virtual void onDraw(SkCanvas* canvas) {
197         const int widths[] = {25, 5, 5, 100, 150, 25};
198         const int heights[] = {100, 100, 5, 25, 150, 25};
199         const SkBlurStyle styles[] = {kNormal_SkBlurStyle, kInner_SkBlurStyle, kOuter_SkBlurStyle};
200         const float radii[] = {20, 5, 10};
201
202         canvas->translate(50,20);
203
204         int cur_x = 0;
205         int cur_y = 0;
206
207         int max_height = 0;
208
209         for (size_t i = 0 ; i < SK_ARRAY_COUNT(widths) ; i++) {
210             int width = widths[i];
211             int height = heights[i];
212             SkRect r;
213             r.setWH(SkIntToScalar(width), SkIntToScalar(height));
214             SkAutoCanvasRestore autoRestore(canvas, true);
215
216             for (size_t j = 0 ; j < SK_ARRAY_COUNT(radii) ; j++) {
217                 float radius = radii[j];
218                 for (size_t k = 0 ; k < SK_ARRAY_COUNT(styles) ; k++) {
219                     SkBlurStyle style = styles[k];
220
221                     SkMask mask;
222                     SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(radius), &mask, r, style);
223
224                     SkAutoMaskFreeImage amfi(mask.fImage);
225
226                     SkBitmap bm;
227                     bm.installMaskPixels(mask);
228
229                     if (cur_x + bm.width() >= fGMWidth - fMargin) {
230                         cur_x = 0;
231                         cur_y += max_height + fPadding;
232                         max_height = 0;
233                     }
234
235                     canvas->save();
236                     canvas->translate((SkScalar)cur_x, (SkScalar)cur_y);
237                     canvas->translate(-(bm.width() - r.width())/2, -(bm.height()-r.height())/2);
238                     canvas->drawBitmap(bm, 0.f, 0.f, NULL);
239                     canvas->restore();
240
241                     cur_x += bm.width() + fPadding;
242                     if (bm.height() > max_height)
243                         max_height = bm.height();
244                 }
245             }
246         }
247     }
248
249 private:
250     typedef GM INHERITED;
251 };
252
253 class BlurRectCompareGM : public skiagm::GM {
254     SkString  fName;
255     unsigned int fRectWidth, fRectHeight;
256     SkScalar fRadius;
257     SkBlurStyle fStyle;
258 public:
259     BlurRectCompareGM(const char name[], unsigned int rectWidth,
260                       unsigned int rectHeight, float radius,
261                       SkBlurStyle style)
262         : fName(name)
263         , fRectWidth(rectWidth)
264         , fRectHeight(rectHeight)
265         , fRadius(radius)
266         , fStyle(style) {
267     }
268     int width() const {
269         return fRectWidth;
270     }
271     int height() const {
272         return fRectHeight;
273     }
274     SkScalar radius() const {
275         return fRadius;
276     }
277     SkBlurStyle style() const {
278         return fStyle;
279     }
280
281 protected:
282     virtual SkString onShortName() {
283         return fName;
284     }
285
286     virtual SkISize onISize() {
287         return SkISize::Make(640, 480);
288     }
289
290     virtual bool makeMask(SkMask *m, const SkRect&) = 0;
291
292     virtual void onDraw(SkCanvas* canvas) {
293         SkRect r;
294         r.setWH(SkIntToScalar(fRectWidth), SkIntToScalar(fRectHeight));
295
296         SkISize canvas_size = canvas->getDeviceSize();
297         int center_x = (canvas_size.fWidth - (int)(r.width()))/2;
298         int center_y = (canvas_size.fHeight - (int)(r.height()))/2;
299
300         SkMask mask;
301
302         if (!this->makeMask(&mask, r)) {
303             SkPaint paint;
304             r.offset( SkIntToScalar(center_x), SkIntToScalar(center_y) );
305             canvas->drawRect(r,paint);
306             return;
307         }
308         SkAutoMaskFreeImage amfi(mask.fImage);
309
310         SkBitmap bm;
311         bm.installMaskPixels(mask);
312
313         center_x = (canvas_size.fWidth - mask.fBounds.width())/2;
314         center_y = (canvas_size.fHeight - mask.fBounds.height())/2;
315
316         canvas->drawBitmap(bm, SkIntToScalar(center_x), SkIntToScalar(center_y), NULL);
317     }
318
319 private:
320     typedef GM INHERITED;
321 };
322
323 class BlurRectFastGM: public BlurRectCompareGM {
324 public:
325     BlurRectFastGM(const char name[], unsigned int rectWidth,
326                    unsigned int rectHeight, float blurRadius,
327                    SkBlurStyle style) :
328         INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
329         }
330
331 protected:
332     bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
333         return SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(this->radius()),
334                                     m, r, this->style());
335     }
336 private:
337     typedef BlurRectCompareGM INHERITED;
338 };
339
340 class BlurRectSlowGM: public BlurRectCompareGM {
341 public:
342     BlurRectSlowGM(const char name[], unsigned int rectWidth, unsigned int rectHeight,
343                    float blurRadius, SkBlurStyle style)
344         : INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
345         }
346
347 protected:
348     bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
349         SkMask src;
350         r.roundOut(&src.fBounds);
351         src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop);  // move to origin
352         src.fFormat = SkMask::kA8_Format;
353         src.fRowBytes = src.fBounds.width();
354         src.fImage = SkMask::AllocImage(src.computeTotalImageSize());
355         SkAutoMaskFreeImage amfi(src.fImage);
356
357         memset(src.fImage, 0xff, src.computeTotalImageSize());
358
359         return SkBlurMask::BoxBlur(m, src,
360                                    SkBlurMask::ConvertRadiusToSigma(this->radius()),
361                                    this->style(), this->getQuality());
362     }
363
364     virtual SkBlurQuality getQuality() {
365         return kHigh_SkBlurQuality;
366     }
367 private:
368     typedef BlurRectCompareGM INHERITED;
369 };
370
371 class BlurRectSlowLowGM: public BlurRectSlowGM {
372 public:
373     BlurRectSlowLowGM(const char name[], unsigned int rectWidth, unsigned int rectHeight,
374                       float blurRadius, SkBlurStyle style)
375         : INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
376         }
377
378 protected:
379     SkBlurQuality getQuality() SK_OVERRIDE {
380         return kLow_SkBlurQuality;
381     }
382 private:
383     typedef BlurRectSlowGM INHERITED;
384 };
385
386 class BlurRectGroundTruthGM: public BlurRectCompareGM {
387 public:
388     BlurRectGroundTruthGM(const char name[], unsigned int rectWidth, unsigned int rectHeight,
389                           float blurRadius, SkBlurStyle style)
390         : INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
391         }
392
393 protected:
394     bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
395         SkMask src;
396         r.roundOut(&src.fBounds);
397         src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop);  // move to origin
398         src.fFormat = SkMask::kA8_Format;
399         src.fRowBytes = src.fBounds.width();
400         src.fImage = SkMask::AllocImage(src.computeTotalImageSize());
401         SkAutoMaskFreeImage amfi(src.fImage);
402
403         memset(src.fImage, 0xff, src.computeTotalImageSize());
404
405         return SkBlurMask::BlurGroundTruth(SkBlurMask::ConvertRadiusToSigma(this->radius()),
406                                            m, src, this->style());
407     }
408
409     virtual SkBlurQuality getQuality() {
410         return kHigh_SkBlurQuality;
411     }
412 private:
413     typedef BlurRectCompareGM INHERITED;
414 };
415
416
417 //////////////////////////////////////////////////////////////////////////////
418
419 DEF_GM(return new BlurRectGM("blurrects", 0xFF);)
420 DEF_GM(return new BlurRectDirectGM("blurrect_gallery");)