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 rect_width, 212 unsigned int rect_height, float blur_radius, 213 SkBlurMask::Style style) : 214 INHERITED(name, rect_width, rect_height, blur_radius, style) 215 { 216 217 } 218protected: 219 virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE { 220 return SkBlurMask::BlurRect(m, r, this->radius(), this->style()); 221 } 222private: 223 typedef BlurRectCompareGM INHERITED; 224}; 225 226class BlurRectSlowGM: public BlurRectCompareGM { 227public: 228 BlurRectSlowGM(const char name[], unsigned int rect_width, unsigned int rect_height, 229 float blur_radius, SkBlurMask::Style style) : 230 INHERITED(name, rect_width, rect_height, blur_radius, style) 231 { 232 233 } 234protected: 235 virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE { 236 SkMask src; 237 r.roundOut(&src.fBounds); 238 src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop); // move to origin 239 src.fFormat = SkMask::kA8_Format; 240 src.fRowBytes = src.fBounds.width(); 241 src.fImage = SkMask::AllocImage(src.computeTotalImageSize()); 242 SkAutoMaskFreeImage amfi(src.fImage); 243 244 memset(src.fImage, 0xff, src.computeTotalImageSize()); 245 246 return SkBlurMask::Blur(m, src, this->radius(), this->style(), this->getQuality()); 247 } 248 249 virtual SkBlurMask::Quality getQuality() { 250 return SkBlurMask::kHigh_Quality; 251 } 252private: 253 typedef BlurRectCompareGM INHERITED; 254}; 255 256class BlurRectSlowLowGM: public BlurRectSlowGM { 257public: 258 BlurRectSlowLowGM(const char name[], unsigned int rectWidth, unsigned int rectHeight, 259 float blurRadius, SkBlurMask::Style style) : 260 INHERITED(name, rectWidth, rectHeight, blurRadius, style) 261 { 262 263 } 264protected: 265 virtual SkBlurMask::Quality getQuality() SK_OVERRIDE { 266 return SkBlurMask::kLow_Quality; 267 } 268private: 269 typedef BlurRectSlowGM INHERITED; 270}; 271 272class BlurRectGroundTruthGM: public BlurRectCompareGM { 273public: 274 BlurRectGroundTruthGM(const char name[], unsigned int rectWidth, unsigned int rectHeight, 275 float blurRadius, SkBlurMask::Style style) : 276 INHERITED(name, rectWidth, rectHeight, blurRadius, style) 277 { 278 279 } 280protected: 281 virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE { 282 SkMask src; 283 r.roundOut(&src.fBounds); 284 src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop); // move to origin 285 src.fFormat = SkMask::kA8_Format; 286 src.fRowBytes = src.fBounds.width(); 287 src.fImage = SkMask::AllocImage(src.computeTotalImageSize()); 288 SkAutoMaskFreeImage amfi(src.fImage); 289 290 memset(src.fImage, 0xff, src.computeTotalImageSize()); 291 292 return SkBlurMask::BlurGroundTruth(m, src, this->radius(), this->style()); 293 } 294 295 virtual SkBlurMask::Quality getQuality() { 296 return SkBlurMask::kHigh_Quality; 297 } 298private: 299 typedef BlurRectCompareGM INHERITED; 300}; 301 302 303////////////////////////////////////////////////////////////////////////////// 304 305DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kNormal_BlurStyle);) 306DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kSolid_BlurStyle);) 307DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kOuter_BlurStyle);) 308DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kInner_BlurStyle);) 309 310// regular size rects, blurs should be small enough not to completely overlap. 311 312DEF_GM(return new BlurRectFastGM( "blurrect_25_100_2_normal_fast", 25, 100, 2, SkBlurMask::kNormal_Style);) 313DEF_GM(return new BlurRectFastGM("blurrect_25_100_20_normal_fast", 25, 100, 20, SkBlurMask::kNormal_Style);) 314DEF_GM(return new BlurRectSlowGM( "blurrect_25_100_2_normal_slow", 25, 100, 2, SkBlurMask::kNormal_Style);) 315DEF_GM(return new BlurRectSlowGM("blurrect_25_100_20_normal_slow", 25, 100, 20, SkBlurMask::kNormal_Style);) 316DEF_GM(return new BlurRectFastGM( "blurrect_25_100_2_inner_fast", 25, 100, 2, SkBlurMask::kInner_Style);) 317DEF_GM(return new BlurRectFastGM("blurrect_25_100_20_inner_fast", 25, 100, 20, SkBlurMask::kInner_Style);) 318DEF_GM(return new BlurRectSlowGM( "blurrect_25_100_2_inner_slow", 25, 100, 2, SkBlurMask::kInner_Style);) 319DEF_GM(return new BlurRectSlowGM("blurrect_25_100_20_inner_slow", 25, 100, 20, SkBlurMask::kInner_Style);) 320DEF_GM(return new BlurRectFastGM( "blurrect_25_100_2_outer_fast", 25, 100, 2, SkBlurMask::kOuter_Style);) 321DEF_GM(return new BlurRectFastGM("blurrect_25_100_20_outer_fast", 25, 100, 20, SkBlurMask::kOuter_Style);) 322DEF_GM(return new BlurRectSlowGM( "blurrect_25_100_2_outer_slow", 25, 100, 2, SkBlurMask::kOuter_Style);) 323DEF_GM(return new BlurRectSlowGM("blurrect_25_100_20_outer_slow", 25, 100, 20, SkBlurMask::kOuter_Style);) 324 325// skinny tall rects, blurs overlap in X but not y 326 327DEF_GM(return new BlurRectFastGM( "blurrect_5_100_2_normal_fast", 5, 100, 2 , SkBlurMask::kNormal_Style);) 328DEF_GM(return new BlurRectFastGM("blurrect_5_100_20_normal_fast", 5, 100, 20, SkBlurMask::kNormal_Style);) 329DEF_GM(return new BlurRectSlowGM( "blurrect_5_100_2_normal_slow", 5, 100, 2 , SkBlurMask::kNormal_Style);) 330DEF_GM(return new BlurRectSlowGM("blurrect_5_100_20_normal_slow", 5, 100, 20, SkBlurMask::kNormal_Style);) 331DEF_GM(return new BlurRectFastGM( "blurrect_5_100_2_inner_fast", 5, 100, 2 , SkBlurMask::kInner_Style);) 332DEF_GM(return new BlurRectFastGM("blurrect_5_100_20_inner_fast", 5, 100, 20, SkBlurMask::kInner_Style);) 333DEF_GM(return new BlurRectSlowGM( "blurrect_5_100_2_inner_slow", 5, 100, 2 , SkBlurMask::kInner_Style);) 334DEF_GM(return new BlurRectSlowGM("blurrect_5_100_20_inner_slow", 5, 100, 20, SkBlurMask::kInner_Style);) 335DEF_GM(return new BlurRectFastGM( "blurrect_5_100_2_outer_fast", 5, 100, 2 , SkBlurMask::kOuter_Style);) 336DEF_GM(return new BlurRectFastGM("blurrect_5_100_20_outer_fast", 5, 100, 20, SkBlurMask::kOuter_Style);) 337DEF_GM(return new BlurRectSlowGM( "blurrect_5_100_2_outer_slow", 5, 100, 2 , SkBlurMask::kOuter_Style);) 338DEF_GM(return new BlurRectSlowGM("blurrect_5_100_20_outer_slow", 5, 100, 20, SkBlurMask::kOuter_Style);) 339 340// tiny rects, blurs overlap in X and Y 341 342DEF_GM(return new BlurRectFastGM( "blurrect_5_5_2_normal_fast", 5, 5, 2 , SkBlurMask::kNormal_Style);) 343DEF_GM(return new BlurRectFastGM("blurrect_5_5_20_normal_fast", 5, 5, 20, SkBlurMask::kNormal_Style);) 344DEF_GM(return new BlurRectSlowGM( "blurrect_5_5_2_normal_slow", 5, 5, 2 , SkBlurMask::kNormal_Style);) 345DEF_GM(return new BlurRectSlowGM("blurrect_5_5_20_normal_slow", 5, 5, 20, SkBlurMask::kNormal_Style);) 346DEF_GM(return new BlurRectFastGM( "blurrect_5_5_2_inner_fast", 5, 5, 2 , SkBlurMask::kInner_Style);) 347DEF_GM(return new BlurRectFastGM("blurrect_5_5_20_inner_fast", 5, 5, 20, SkBlurMask::kInner_Style);) 348DEF_GM(return new BlurRectSlowGM( "blurrect_5_5_2_inner_slow", 5, 5, 2 , SkBlurMask::kInner_Style);) 349DEF_GM(return new BlurRectSlowGM("blurrect_5_5_20_inner_slow", 5, 5, 20, SkBlurMask::kInner_Style);) 350DEF_GM(return new BlurRectFastGM( "blurrect_5_5_2_outer_fast", 5, 5, 2 , SkBlurMask::kOuter_Style);) 351DEF_GM(return new BlurRectFastGM("blurrect_5_5_20_outer_fast", 5, 5, 20, SkBlurMask::kOuter_Style);) 352DEF_GM(return new BlurRectSlowGM( "blurrect_5_5_2_outer_slow", 5, 5, 2 , SkBlurMask::kOuter_Style);) 353DEF_GM(return new BlurRectSlowGM("blurrect_5_5_20_outer_slow", 5, 5, 20, SkBlurMask::kOuter_Style);) 354 355 356#if 0 357// dont' need to GM the gaussian convolution; it's slow and intended 358// as a ground truth comparison only. Leaving these here in case we 359// ever want to turn these back on for debugging reasons. 360DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_1_simple", 25, 100, 1);) 361DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_2_simple", 25, 100, 2);) 362DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_3_simple", 25, 100, 3);) 363DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_4_simple", 25, 100, 4);) 364DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_5_simple", 25, 100, 5);) 365DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_6_simple", 25, 100, 6);) 366DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_7_simple", 25, 100, 7);) 367DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_8_simple", 25, 100, 8);) 368DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_9_simple", 25, 100, 9);) 369DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_10_simple", 25, 100, 10);) 370DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_11_simple", 25, 100, 11);) 371DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_12_simple", 25, 100, 12);) 372DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_13_simple", 25, 100, 13);) 373DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_14_simple", 25, 100, 14);) 374DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_15_simple", 25, 100, 15);) 375DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_16_simple", 25, 100, 16);) 376DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_17_simple", 25, 100, 17);) 377DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_18_simple", 25, 100, 18);) 378DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_19_simple", 25, 100, 19);) 379#endif 380