blurrect.cpp revision dac522589e9395b4654a1a708f1bd971f37f95a5
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 60class BlurRectGM : public skiagm::GM { 61 SkAutoTUnref<SkMaskFilter> fMaskFilters[SkBlurMaskFilter::kBlurStyleCount]; 62 SkString fName; 63 SkAlpha fAlpha; 64public: 65 BlurRectGM(const char name[], U8CPU alpha) 66 : fName(name) 67 , fAlpha(SkToU8(alpha)) { 68 } 69 70protected: 71 virtual void onOnceBeforeDraw() SK_OVERRIDE { 72 for (int i = 0; i < SkBlurMaskFilter::kBlurStyleCount; ++i) { 73 fMaskFilters[i].reset(SkBlurMaskFilter::Create((SkBlurMaskFilter::BlurStyle) i, 74 SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(STROKE_WIDTH/2)), 75 SkBlurMaskFilter::kHighQuality_BlurFlag)); 76 } 77 } 78 79 virtual SkString onShortName() { 80 return fName; 81 } 82 83 virtual SkISize onISize() { 84 return SkISize::Make(440, 820); 85 } 86 87 virtual void onDraw(SkCanvas* canvas) { 88 canvas->translate(STROKE_WIDTH*3/2, STROKE_WIDTH*3/2); 89 90 SkRect r = { 0, 0, 100, 50 }; 91 SkScalar scales[] = { SK_Scalar1, 0.6f }; 92 93 for (size_t s = 0; s < SK_ARRAY_COUNT(scales); ++s) { 94 canvas->save(); 95 for (size_t f = 0; f < SK_ARRAY_COUNT(fMaskFilters); ++f) { 96 SkPaint paint; 97 paint.setMaskFilter(fMaskFilters[f]); 98 paint.setAlpha(fAlpha); 99 100 static const Proc procs[] = { 101 fill_rect, draw_donut, draw_donut_skewed 102 }; 103 104 canvas->save(); 105 canvas->scale(scales[s], scales[s]); 106 this->drawProcs(canvas, r, paint, false, procs, SK_ARRAY_COUNT(procs)); 107 canvas->translate(r.width() * 4/3, 0); 108 this->drawProcs(canvas, r, paint, true, procs, SK_ARRAY_COUNT(procs)); 109 canvas->restore(); 110 111 canvas->translate(0, SK_ARRAY_COUNT(procs) * r.height() * 4/3 * scales[s]); 112 } 113 canvas->restore(); 114 canvas->translate(2 * r.width() * 4/3 * scales[s], 0); 115 } 116 } 117 118 virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; } 119 120private: 121 void drawProcs(SkCanvas* canvas, const SkRect& r, const SkPaint& paint, 122 bool doClip, const Proc procs[], size_t procsCount) { 123 SkAutoCanvasRestore acr(canvas, true); 124 for (size_t i = 0; i < procsCount; ++i) { 125 if (doClip) { 126 SkRect clipRect(r); 127 clipRect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2); 128 canvas->save(); 129 canvas->clipRect(r); 130 } 131 procs[i](canvas, r, paint); 132 if (doClip) { 133 canvas->restore(); 134 } 135 canvas->translate(0, r.height() * 4/3); 136 } 137 } 138private: 139 typedef GM INHERITED; 140}; 141 142class BlurRectCompareGM : public skiagm::GM { 143 SkString fName; 144 unsigned int fRectWidth, fRectHeight; 145 SkScalar fRadius; 146 SkBlurMask::Style fStyle; 147public: 148 BlurRectCompareGM(const char name[], unsigned int rectWidth, 149 unsigned int rectHeight, float radius, 150 SkBlurMask::Style style) 151 : fName(name) 152 , fRectWidth(rectWidth) 153 , fRectHeight(rectHeight) 154 , fRadius(radius) 155 , fStyle(style) { 156 } 157 int width() const { 158 return fRectWidth; 159 } 160 int height() const { 161 return fRectHeight; 162 } 163 SkScalar radius() const { 164 return fRadius; 165 } 166 SkBlurMask::Style style() const { 167 return fStyle; 168 } 169 170protected: 171 virtual SkString onShortName() { 172 return fName; 173 } 174 175 virtual SkISize onISize() { 176 return SkISize::Make(640, 480); 177 } 178 179 virtual bool makeMask(SkMask *m, const SkRect&) = 0; 180 181 virtual void onDraw(SkCanvas* canvas) { 182 SkRect r; 183 r.setWH(SkIntToScalar(fRectWidth), SkIntToScalar(fRectHeight)); 184 185 SkISize canvas_size = canvas->getDeviceSize(); 186 int center_x = (canvas_size.fWidth - (int)(r.width()))/2; 187 int center_y = (canvas_size.fHeight - (int)(r.height()))/2; 188 189 SkMask mask; 190 191 if (!this->makeMask(&mask, r)) { 192 SkPaint paint; 193 r.offset( SkIntToScalar(center_x), SkIntToScalar(center_y) ); 194 canvas->drawRect(r,paint); 195 return; 196 } 197 SkAutoMaskFreeImage amfi(mask.fImage); 198 199 SkBitmap bm; 200 bm.installMaskPixels(mask); 201 202 center_x = (canvas_size.fWidth - mask.fBounds.width())/2; 203 center_y = (canvas_size.fHeight - mask.fBounds.height())/2; 204 205 canvas->drawBitmap(bm, SkIntToScalar(center_x), SkIntToScalar(center_y), NULL); 206 } 207 208 virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; } 209 210private: 211 typedef GM INHERITED; 212}; 213 214class BlurRectFastGM: public BlurRectCompareGM { 215public: 216 BlurRectFastGM(const char name[], unsigned int rectWidth, 217 unsigned int rectHeight, float blurRadius, 218 SkBlurMask::Style style) : 219 INHERITED(name, rectWidth, rectHeight, blurRadius, style) { 220 } 221 222protected: 223 virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE { 224 return SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(this->radius()), 225 m, r, this->style()); 226 } 227private: 228 typedef BlurRectCompareGM INHERITED; 229}; 230 231class BlurRectSlowGM: public BlurRectCompareGM { 232public: 233 BlurRectSlowGM(const char name[], unsigned int rectWidth, unsigned int rectHeight, 234 float blurRadius, SkBlurMask::Style style) 235 : INHERITED(name, rectWidth, rectHeight, blurRadius, style) { 236 } 237 238protected: 239 virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE { 240 SkMask src; 241 r.roundOut(&src.fBounds); 242 src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop); // move to origin 243 src.fFormat = SkMask::kA8_Format; 244 src.fRowBytes = src.fBounds.width(); 245 src.fImage = SkMask::AllocImage(src.computeTotalImageSize()); 246 SkAutoMaskFreeImage amfi(src.fImage); 247 248 memset(src.fImage, 0xff, src.computeTotalImageSize()); 249 250 return SkBlurMask::BoxBlur(m, src, 251 SkBlurMask::ConvertRadiusToSigma(this->radius()), 252 this->style(), this->getQuality()); 253 } 254 255 virtual SkBlurMask::Quality getQuality() { 256 return SkBlurMask::kHigh_Quality; 257 } 258private: 259 typedef BlurRectCompareGM INHERITED; 260}; 261 262class BlurRectSlowLowGM: public BlurRectSlowGM { 263public: 264 BlurRectSlowLowGM(const char name[], unsigned int rectWidth, unsigned int rectHeight, 265 float blurRadius, SkBlurMask::Style style) 266 : INHERITED(name, rectWidth, rectHeight, blurRadius, style) { 267 } 268 269protected: 270 virtual SkBlurMask::Quality getQuality() SK_OVERRIDE { 271 return SkBlurMask::kLow_Quality; 272 } 273private: 274 typedef BlurRectSlowGM INHERITED; 275}; 276 277class BlurRectGroundTruthGM: public BlurRectCompareGM { 278public: 279 BlurRectGroundTruthGM(const char name[], unsigned int rectWidth, unsigned int rectHeight, 280 float blurRadius, SkBlurMask::Style style) 281 : INHERITED(name, rectWidth, rectHeight, blurRadius, style) { 282 } 283 284protected: 285 virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE { 286 SkMask src; 287 r.roundOut(&src.fBounds); 288 src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop); // move to origin 289 src.fFormat = SkMask::kA8_Format; 290 src.fRowBytes = src.fBounds.width(); 291 src.fImage = SkMask::AllocImage(src.computeTotalImageSize()); 292 SkAutoMaskFreeImage amfi(src.fImage); 293 294 memset(src.fImage, 0xff, src.computeTotalImageSize()); 295 296 return SkBlurMask::BlurGroundTruth(SkBlurMask::ConvertRadiusToSigma(this->radius()), 297 m, src, this->style()); 298 } 299 300 virtual SkBlurMask::Quality getQuality() { 301 return SkBlurMask::kHigh_Quality; 302 } 303private: 304 typedef BlurRectCompareGM INHERITED; 305}; 306 307 308////////////////////////////////////////////////////////////////////////////// 309 310DEF_GM(return new BlurRectGM("blurrects", 0xFF);) 311 312static const SkScalar kBig = 20; 313static const SkScalar kSmall = 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