blurrect.cpp revision 3c1594aacbd20c4583db300fc66e3c227bec4f6c
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[kLastEnum_SkBlurStyle + 1]; 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 <= kLastEnum_SkBlurStyle; ++i) { 73 fMaskFilters[i].reset(SkBlurMaskFilter::Create((SkBlurStyle)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 | kSkipTiled_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 142 143class BlurRectDirectGM : public skiagm::GM { 144 SkString fName; 145 int fGMWidth, fGMHeight; 146 int fPadding, fMargin; 147public: 148 BlurRectDirectGM(const char name[]) 149 : fName(name), 150 fGMWidth(1200), 151 fGMHeight(1024), 152 fPadding(10), 153 fMargin(100) 154 { 155 } 156 157protected: 158 virtual SkString onShortName() { 159 return fName; 160 } 161 162 virtual SkISize onISize() { 163 return SkISize::Make(fGMWidth, fGMHeight); 164 } 165 166 virtual void onDraw(SkCanvas* canvas) { 167 const int widths[] = {25, 5, 5, 100, 150, 25}; 168 const int heights[] = {100, 100, 5, 25, 150, 25}; 169 const SkBlurStyle styles[] = {kNormal_SkBlurStyle, kInner_SkBlurStyle, kOuter_SkBlurStyle}; 170 const float radii[] = {20, 5, 10}; 171 172 canvas->translate(50,20); 173 174 int cur_x = 0; 175 int cur_y = 0; 176 177 int max_height = 0; 178 179 for (size_t i = 0 ; i < SK_ARRAY_COUNT(widths) ; i++) { 180 int width = widths[i]; 181 int height = heights[i]; 182 SkRect r; 183 r.setWH(SkIntToScalar(width), SkIntToScalar(height)); 184 SkAutoCanvasRestore autoRestore(canvas, true); 185 186 for (size_t j = 0 ; j < SK_ARRAY_COUNT(radii) ; j++) { 187 float radius = radii[j]; 188 for (size_t k = 0 ; k < SK_ARRAY_COUNT(styles) ; k++) { 189 SkBlurStyle style = styles[k]; 190 191 SkMask mask; 192 SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(radius), &mask, r, style); 193 194 SkAutoMaskFreeImage amfi(mask.fImage); 195 196 SkBitmap bm; 197 bm.installMaskPixels(mask); 198 199 if (cur_x + bm.width() >= fGMWidth - fMargin) { 200 cur_x = 0; 201 cur_y += max_height + fPadding; 202 max_height = 0; 203 } 204 205 canvas->save(); 206 canvas->translate(cur_x, cur_y); 207 canvas->translate(-(bm.width() - r.width())/2, -(bm.height()-r.height())/2); 208 canvas->drawBitmap(bm, 0.f, 0.f, NULL); 209 canvas->restore(); 210 211 cur_x += bm.width() + fPadding; 212 if (bm.height() > max_height) 213 max_height = bm.height(); 214 } 215 } 216 } 217 } 218 219 virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; } 220 221private: 222 typedef GM INHERITED; 223}; 224 225class BlurRectCompareGM : public skiagm::GM { 226 SkString fName; 227 unsigned int fRectWidth, fRectHeight; 228 SkScalar fRadius; 229 SkBlurStyle fStyle; 230public: 231 BlurRectCompareGM(const char name[], unsigned int rectWidth, 232 unsigned int rectHeight, float radius, 233 SkBlurStyle style) 234 : fName(name) 235 , fRectWidth(rectWidth) 236 , fRectHeight(rectHeight) 237 , fRadius(radius) 238 , fStyle(style) { 239 } 240 int width() const { 241 return fRectWidth; 242 } 243 int height() const { 244 return fRectHeight; 245 } 246 SkScalar radius() const { 247 return fRadius; 248 } 249 SkBlurStyle style() const { 250 return fStyle; 251 } 252 253protected: 254 virtual SkString onShortName() { 255 return fName; 256 } 257 258 virtual SkISize onISize() { 259 return SkISize::Make(640, 480); 260 } 261 262 virtual bool makeMask(SkMask *m, const SkRect&) = 0; 263 264 virtual void onDraw(SkCanvas* canvas) { 265 SkRect r; 266 r.setWH(SkIntToScalar(fRectWidth), SkIntToScalar(fRectHeight)); 267 268 SkISize canvas_size = canvas->getDeviceSize(); 269 int center_x = (canvas_size.fWidth - (int)(r.width()))/2; 270 int center_y = (canvas_size.fHeight - (int)(r.height()))/2; 271 272 SkMask mask; 273 274 if (!this->makeMask(&mask, r)) { 275 SkPaint paint; 276 r.offset( SkIntToScalar(center_x), SkIntToScalar(center_y) ); 277 canvas->drawRect(r,paint); 278 return; 279 } 280 SkAutoMaskFreeImage amfi(mask.fImage); 281 282 SkBitmap bm; 283 bm.installMaskPixels(mask); 284 285 center_x = (canvas_size.fWidth - mask.fBounds.width())/2; 286 center_y = (canvas_size.fHeight - mask.fBounds.height())/2; 287 288 canvas->drawBitmap(bm, SkIntToScalar(center_x), SkIntToScalar(center_y), NULL); 289 } 290 291 virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; } 292 293private: 294 typedef GM INHERITED; 295}; 296 297class BlurRectFastGM: public BlurRectCompareGM { 298public: 299 BlurRectFastGM(const char name[], unsigned int rectWidth, 300 unsigned int rectHeight, float blurRadius, 301 SkBlurStyle style) : 302 INHERITED(name, rectWidth, rectHeight, blurRadius, style) { 303 } 304 305protected: 306 virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE { 307 return SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(this->radius()), 308 m, r, this->style()); 309 } 310private: 311 typedef BlurRectCompareGM INHERITED; 312}; 313 314class BlurRectSlowGM: public BlurRectCompareGM { 315public: 316 BlurRectSlowGM(const char name[], unsigned int rectWidth, unsigned int rectHeight, 317 float blurRadius, SkBlurStyle style) 318 : INHERITED(name, rectWidth, rectHeight, blurRadius, style) { 319 } 320 321protected: 322 virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE { 323 SkMask src; 324 r.roundOut(&src.fBounds); 325 src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop); // move to origin 326 src.fFormat = SkMask::kA8_Format; 327 src.fRowBytes = src.fBounds.width(); 328 src.fImage = SkMask::AllocImage(src.computeTotalImageSize()); 329 SkAutoMaskFreeImage amfi(src.fImage); 330 331 memset(src.fImage, 0xff, src.computeTotalImageSize()); 332 333 return SkBlurMask::BoxBlur(m, src, 334 SkBlurMask::ConvertRadiusToSigma(this->radius()), 335 this->style(), this->getQuality()); 336 } 337 338 virtual SkBlurQuality getQuality() { 339 return kHigh_SkBlurQuality; 340 } 341private: 342 typedef BlurRectCompareGM INHERITED; 343}; 344 345class BlurRectSlowLowGM: public BlurRectSlowGM { 346public: 347 BlurRectSlowLowGM(const char name[], unsigned int rectWidth, unsigned int rectHeight, 348 float blurRadius, SkBlurStyle style) 349 : INHERITED(name, rectWidth, rectHeight, blurRadius, style) { 350 } 351 352protected: 353 virtual SkBlurQuality getQuality() SK_OVERRIDE { 354 return kLow_SkBlurQuality; 355 } 356private: 357 typedef BlurRectSlowGM INHERITED; 358}; 359 360class BlurRectGroundTruthGM: public BlurRectCompareGM { 361public: 362 BlurRectGroundTruthGM(const char name[], unsigned int rectWidth, unsigned int rectHeight, 363 float blurRadius, SkBlurStyle style) 364 : INHERITED(name, rectWidth, rectHeight, blurRadius, style) { 365 } 366 367protected: 368 virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE { 369 SkMask src; 370 r.roundOut(&src.fBounds); 371 src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop); // move to origin 372 src.fFormat = SkMask::kA8_Format; 373 src.fRowBytes = src.fBounds.width(); 374 src.fImage = SkMask::AllocImage(src.computeTotalImageSize()); 375 SkAutoMaskFreeImage amfi(src.fImage); 376 377 memset(src.fImage, 0xff, src.computeTotalImageSize()); 378 379 return SkBlurMask::BlurGroundTruth(SkBlurMask::ConvertRadiusToSigma(this->radius()), 380 m, src, this->style()); 381 } 382 383 virtual SkBlurQuality getQuality() { 384 return kHigh_SkBlurQuality; 385 } 386private: 387 typedef BlurRectCompareGM INHERITED; 388}; 389 390 391////////////////////////////////////////////////////////////////////////////// 392 393DEF_GM(return new BlurRectGM("blurrects", 0xFF);) 394DEF_GM(return new BlurRectDirectGM("blurrect_gallery");) 395