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