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 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 typedef void (*PaintProc)(SkPaint*, SkScalar width); 59 60 static const char* gBlurStyle2Name[] = { 61 "normal", 62 "solid", 63 "outer", 64 "inner" 65 }; 66 67 class BlurRectGM : public skiagm::GM { 68 SkAutoTUnref<SkMaskFilter> fMaskFilter; 69 SkString fName; 70 PaintProc fPProc; 71 SkAlpha fAlpha; 72 public: 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 83 protected: 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 115 private: 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 } 133 private: 134 typedef GM INHERITED; 135 }; 136 137 class BlurRectCompareGM : public skiagm::GM { 138 SkString fName; 139 unsigned int fRectWidth, fRectHeight; 140 SkScalar fRadius; 141 SkBlurMask::Style fStyle; 142 public: 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 164 protected: 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 205 private: 206 typedef GM INHERITED; 207 }; 208 209 class BlurRectFastGM: public BlurRectCompareGM { 210 public: 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 } 218 protected: 219 virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE { 220 return SkBlurMask::BlurRect(m, r, this->radius(), this->style()); 221 } 222 private: 223 typedef BlurRectCompareGM INHERITED; 224 }; 225 226 class BlurRectSlowGM: public BlurRectCompareGM { 227 public: 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 } 234 protected: 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 } 252 private: 253 typedef BlurRectCompareGM INHERITED; 254 }; 255 256 class BlurRectSlowLowGM: public BlurRectSlowGM { 257 public: 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 } 264 protected: 265 virtual SkBlurMask::Quality getQuality() SK_OVERRIDE { 266 return SkBlurMask::kLow_Quality; 267 } 268 private: 269 typedef BlurRectSlowGM INHERITED; 270 }; 271 272 class BlurRectGroundTruthGM: public BlurRectCompareGM { 273 public: 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 } 280 protected: 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 } 298 private: 299 typedef BlurRectCompareGM INHERITED; 300 }; 301 302 303 ////////////////////////////////////////////////////////////////////////////// 304 305 DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kNormal_BlurStyle);) 306 DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kSolid_BlurStyle);) 307 DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kOuter_BlurStyle);) 308 DEF_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 312 DEF_GM(return new BlurRectFastGM( "blurrect_25_100_2_normal_fast", 25, 100, 2, SkBlurMask::kNormal_Style);) 313 DEF_GM(return new BlurRectFastGM("blurrect_25_100_20_normal_fast", 25, 100, 20, SkBlurMask::kNormal_Style);) 314 DEF_GM(return new BlurRectSlowGM( "blurrect_25_100_2_normal_slow", 25, 100, 2, SkBlurMask::kNormal_Style);) 315 DEF_GM(return new BlurRectSlowGM("blurrect_25_100_20_normal_slow", 25, 100, 20, SkBlurMask::kNormal_Style);) 316 DEF_GM(return new BlurRectFastGM( "blurrect_25_100_2_inner_fast", 25, 100, 2, SkBlurMask::kInner_Style);) 317 DEF_GM(return new BlurRectFastGM("blurrect_25_100_20_inner_fast", 25, 100, 20, SkBlurMask::kInner_Style);) 318 DEF_GM(return new BlurRectSlowGM( "blurrect_25_100_2_inner_slow", 25, 100, 2, SkBlurMask::kInner_Style);) 319 DEF_GM(return new BlurRectSlowGM("blurrect_25_100_20_inner_slow", 25, 100, 20, SkBlurMask::kInner_Style);) 320 DEF_GM(return new BlurRectFastGM( "blurrect_25_100_2_outer_fast", 25, 100, 2, SkBlurMask::kOuter_Style);) 321 DEF_GM(return new BlurRectFastGM("blurrect_25_100_20_outer_fast", 25, 100, 20, SkBlurMask::kOuter_Style);) 322 DEF_GM(return new BlurRectSlowGM( "blurrect_25_100_2_outer_slow", 25, 100, 2, SkBlurMask::kOuter_Style);) 323 DEF_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 327 DEF_GM(return new BlurRectFastGM( "blurrect_5_100_2_normal_fast", 5, 100, 2 , SkBlurMask::kNormal_Style);) 328 DEF_GM(return new BlurRectFastGM("blurrect_5_100_20_normal_fast", 5, 100, 20, SkBlurMask::kNormal_Style);) 329 DEF_GM(return new BlurRectSlowGM( "blurrect_5_100_2_normal_slow", 5, 100, 2 , SkBlurMask::kNormal_Style);) 330 DEF_GM(return new BlurRectSlowGM("blurrect_5_100_20_normal_slow", 5, 100, 20, SkBlurMask::kNormal_Style);) 331 DEF_GM(return new BlurRectFastGM( "blurrect_5_100_2_inner_fast", 5, 100, 2 , SkBlurMask::kInner_Style);) 332 DEF_GM(return new BlurRectFastGM("blurrect_5_100_20_inner_fast", 5, 100, 20, SkBlurMask::kInner_Style);) 333 DEF_GM(return new BlurRectSlowGM( "blurrect_5_100_2_inner_slow", 5, 100, 2 , SkBlurMask::kInner_Style);) 334 DEF_GM(return new BlurRectSlowGM("blurrect_5_100_20_inner_slow", 5, 100, 20, SkBlurMask::kInner_Style);) 335 DEF_GM(return new BlurRectFastGM( "blurrect_5_100_2_outer_fast", 5, 100, 2 , SkBlurMask::kOuter_Style);) 336 DEF_GM(return new BlurRectFastGM("blurrect_5_100_20_outer_fast", 5, 100, 20, SkBlurMask::kOuter_Style);) 337 DEF_GM(return new BlurRectSlowGM( "blurrect_5_100_2_outer_slow", 5, 100, 2 , SkBlurMask::kOuter_Style);) 338 DEF_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 342 DEF_GM(return new BlurRectFastGM( "blurrect_5_5_2_normal_fast", 5, 5, 2 , SkBlurMask::kNormal_Style);) 343 DEF_GM(return new BlurRectFastGM("blurrect_5_5_20_normal_fast", 5, 5, 20, SkBlurMask::kNormal_Style);) 344 DEF_GM(return new BlurRectSlowGM( "blurrect_5_5_2_normal_slow", 5, 5, 2 , SkBlurMask::kNormal_Style);) 345 DEF_GM(return new BlurRectSlowGM("blurrect_5_5_20_normal_slow", 5, 5, 20, SkBlurMask::kNormal_Style);) 346 DEF_GM(return new BlurRectFastGM( "blurrect_5_5_2_inner_fast", 5, 5, 2 , SkBlurMask::kInner_Style);) 347 DEF_GM(return new BlurRectFastGM("blurrect_5_5_20_inner_fast", 5, 5, 20, SkBlurMask::kInner_Style);) 348 DEF_GM(return new BlurRectSlowGM( "blurrect_5_5_2_inner_slow", 5, 5, 2 , SkBlurMask::kInner_Style);) 349 DEF_GM(return new BlurRectSlowGM("blurrect_5_5_20_inner_slow", 5, 5, 20, SkBlurMask::kInner_Style);) 350 DEF_GM(return new BlurRectFastGM( "blurrect_5_5_2_outer_fast", 5, 5, 2 , SkBlurMask::kOuter_Style);) 351 DEF_GM(return new BlurRectFastGM("blurrect_5_5_20_outer_fast", 5, 5, 20, SkBlurMask::kOuter_Style);) 352 DEF_GM(return new BlurRectSlowGM( "blurrect_5_5_2_outer_slow", 5, 5, 2 , SkBlurMask::kOuter_Style);) 353 DEF_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. 360 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_1_simple", 25, 100, 1);) 361 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_2_simple", 25, 100, 2);) 362 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_3_simple", 25, 100, 3);) 363 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_4_simple", 25, 100, 4);) 364 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_5_simple", 25, 100, 5);) 365 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_6_simple", 25, 100, 6);) 366 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_7_simple", 25, 100, 7);) 367 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_8_simple", 25, 100, 8);) 368 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_9_simple", 25, 100, 9);) 369 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_10_simple", 25, 100, 10);) 370 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_11_simple", 25, 100, 11);) 371 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_12_simple", 25, 100, 12);) 372 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_13_simple", 25, 100, 13);) 373 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_14_simple", 25, 100, 14);) 374 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_15_simple", 25, 100, 15);) 375 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_16_simple", 25, 100, 16);) 376 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_17_simple", 25, 100, 17);) 377 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_18_simple", 25, 100, 18);) 378 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_19_simple", 25, 100, 19);) 379 #endif 380