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 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(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 84 protected: 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 116 private: 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 } 134 private: 135 typedef GM INHERITED; 136 }; 137 138 class BlurRectCompareGM : public skiagm::GM { 139 SkString fName; 140 unsigned int fRectWidth, fRectHeight; 141 SkScalar fRadius; 142 SkBlurMask::Style fStyle; 143 public: 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 166 protected: 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 207 private: 208 typedef GM INHERITED; 209 }; 210 211 class BlurRectFastGM: public BlurRectCompareGM { 212 public: 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 219 protected: 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 } 224 private: 225 typedef BlurRectCompareGM INHERITED; 226 }; 227 228 class BlurRectSlowGM: public BlurRectCompareGM { 229 public: 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 235 protected: 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 } 255 private: 256 typedef BlurRectCompareGM INHERITED; 257 }; 258 259 class BlurRectSlowLowGM: public BlurRectSlowGM { 260 public: 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 266 protected: 267 virtual SkBlurMask::Quality getQuality() SK_OVERRIDE { 268 return SkBlurMask::kLow_Quality; 269 } 270 private: 271 typedef BlurRectSlowGM INHERITED; 272 }; 273 274 class BlurRectGroundTruthGM: public BlurRectCompareGM { 275 public: 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 281 protected: 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 } 300 private: 301 typedef BlurRectCompareGM INHERITED; 302 }; 303 304 305 ////////////////////////////////////////////////////////////////////////////// 306 307 DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kNormal_BlurStyle);) 308 DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kSolid_BlurStyle);) 309 DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kOuter_BlurStyle);) 310 DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kInner_BlurStyle);) 311 312 static const SkScalar kBig = 20; 313 static const SkScalar kSmall = 2; 314 315 // regular size rects, blurs should be small enough not to completely overlap. 316 317 DEF_GM(return new BlurRectFastGM( "blurrect_25_100_2_normal_fast", 25, 100, kSmall, SkBlurMask::kNormal_Style);) 318 DEF_GM(return new BlurRectFastGM("blurrect_25_100_20_normal_fast", 25, 100, kBig, SkBlurMask::kNormal_Style);) 319 DEF_GM(return new BlurRectSlowGM( "blurrect_25_100_2_normal_slow", 25, 100, kSmall, SkBlurMask::kNormal_Style);) 320 DEF_GM(return new BlurRectSlowGM("blurrect_25_100_20_normal_slow", 25, 100, kBig, SkBlurMask::kNormal_Style);) 321 DEF_GM(return new BlurRectFastGM( "blurrect_25_100_2_inner_fast", 25, 100, kSmall, SkBlurMask::kInner_Style);) 322 DEF_GM(return new BlurRectFastGM("blurrect_25_100_20_inner_fast", 25, 100, kBig, SkBlurMask::kInner_Style);) 323 DEF_GM(return new BlurRectSlowGM( "blurrect_25_100_2_inner_slow", 25, 100, kSmall, SkBlurMask::kInner_Style);) 324 DEF_GM(return new BlurRectSlowGM("blurrect_25_100_20_inner_slow", 25, 100, kBig, SkBlurMask::kInner_Style);) 325 DEF_GM(return new BlurRectFastGM( "blurrect_25_100_2_outer_fast", 25, 100, kSmall, SkBlurMask::kOuter_Style);) 326 DEF_GM(return new BlurRectFastGM("blurrect_25_100_20_outer_fast", 25, 100, kBig, SkBlurMask::kOuter_Style);) 327 DEF_GM(return new BlurRectSlowGM( "blurrect_25_100_2_outer_slow", 25, 100, kSmall, SkBlurMask::kOuter_Style);) 328 DEF_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 332 DEF_GM(return new BlurRectFastGM( "blurrect_5_100_2_normal_fast", 5, 100, kSmall, SkBlurMask::kNormal_Style);) 333 DEF_GM(return new BlurRectFastGM("blurrect_5_100_20_normal_fast", 5, 100, kBig, SkBlurMask::kNormal_Style);) 334 DEF_GM(return new BlurRectSlowGM( "blurrect_5_100_2_normal_slow", 5, 100, kSmall, SkBlurMask::kNormal_Style);) 335 DEF_GM(return new BlurRectSlowGM("blurrect_5_100_20_normal_slow", 5, 100, kBig, SkBlurMask::kNormal_Style);) 336 DEF_GM(return new BlurRectFastGM( "blurrect_5_100_2_inner_fast", 5, 100, kSmall, SkBlurMask::kInner_Style);) 337 DEF_GM(return new BlurRectFastGM("blurrect_5_100_20_inner_fast", 5, 100, kBig, SkBlurMask::kInner_Style);) 338 DEF_GM(return new BlurRectSlowGM( "blurrect_5_100_2_inner_slow", 5, 100, kSmall, SkBlurMask::kInner_Style);) 339 DEF_GM(return new BlurRectSlowGM("blurrect_5_100_20_inner_slow", 5, 100, kBig, SkBlurMask::kInner_Style);) 340 DEF_GM(return new BlurRectFastGM( "blurrect_5_100_2_outer_fast", 5, 100, kSmall, SkBlurMask::kOuter_Style);) 341 DEF_GM(return new BlurRectFastGM("blurrect_5_100_20_outer_fast", 5, 100, kBig, SkBlurMask::kOuter_Style);) 342 DEF_GM(return new BlurRectSlowGM( "blurrect_5_100_2_outer_slow", 5, 100, kSmall, SkBlurMask::kOuter_Style);) 343 DEF_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 347 DEF_GM(return new BlurRectFastGM( "blurrect_5_5_2_normal_fast", 5, 5, kSmall, SkBlurMask::kNormal_Style);) 348 DEF_GM(return new BlurRectFastGM("blurrect_5_5_20_normal_fast", 5, 5, kBig, SkBlurMask::kNormal_Style);) 349 DEF_GM(return new BlurRectSlowGM( "blurrect_5_5_2_normal_slow", 5, 5, kSmall, SkBlurMask::kNormal_Style);) 350 DEF_GM(return new BlurRectSlowGM("blurrect_5_5_20_normal_slow", 5, 5, kBig, SkBlurMask::kNormal_Style);) 351 DEF_GM(return new BlurRectFastGM( "blurrect_5_5_2_inner_fast", 5, 5, kSmall, SkBlurMask::kInner_Style);) 352 DEF_GM(return new BlurRectFastGM("blurrect_5_5_20_inner_fast", 5, 5, kBig, SkBlurMask::kInner_Style);) 353 DEF_GM(return new BlurRectSlowGM( "blurrect_5_5_2_inner_slow", 5, 5, kSmall, SkBlurMask::kInner_Style);) 354 DEF_GM(return new BlurRectSlowGM("blurrect_5_5_20_inner_slow", 5, 5, kBig, SkBlurMask::kInner_Style);) 355 DEF_GM(return new BlurRectFastGM( "blurrect_5_5_2_outer_fast", 5, 5, kSmall, SkBlurMask::kOuter_Style);) 356 DEF_GM(return new BlurRectFastGM("blurrect_5_5_20_outer_fast", 5, 5, kBig, SkBlurMask::kOuter_Style);) 357 DEF_GM(return new BlurRectSlowGM( "blurrect_5_5_2_outer_slow", 5, 5, kSmall, SkBlurMask::kOuter_Style);) 358 DEF_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. 365 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_1_simple", 25, 100, 1);) 366 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_2_simple", 25, 100, 2);) 367 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_3_simple", 25, 100, 3);) 368 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_4_simple", 25, 100, 4);) 369 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_5_simple", 25, 100, 5);) 370 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_6_simple", 25, 100, 6);) 371 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_7_simple", 25, 100, 7);) 372 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_8_simple", 25, 100, 8);) 373 DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_9_simple", 25, 100, 9);) 374 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_10_simple", 25, 100, 10);) 375 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_11_simple", 25, 100, 11);) 376 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_12_simple", 25, 100, 12);) 377 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_13_simple", 25, 100, 13);) 378 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_14_simple", 25, 100, 14);) 379 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_15_simple", 25, 100, 15);) 380 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_16_simple", 25, 100, 16);) 381 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_17_simple", 25, 100, 17);) 382 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_18_simple", 25, 100, 18);) 383 DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_19_simple", 25, 100, 19);) 384 #endif 385