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 /* 59 * Spits out a dummy gradient to test blur with shader on paint 60 */ 61 static SkShader* MakeRadial() { 62 SkPoint pts[2] = { 63 { 0, 0 }, 64 { SkIntToScalar(100), SkIntToScalar(100) } 65 }; 66 SkShader::TileMode tm = SkShader::kClamp_TileMode; 67 const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, }; 68 const SkScalar pos[] = { SK_Scalar1/4, SK_Scalar1*3/4 }; 69 SkMatrix scale; 70 scale.setScale(0.5f, 0.5f); 71 scale.postTranslate(25.f, 25.f); 72 SkPoint center0, center1; 73 center0.set(SkScalarAve(pts[0].fX, pts[1].fX), 74 SkScalarAve(pts[0].fY, pts[1].fY)); 75 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), 76 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); 77 return SkGradientShader::CreateTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7, 78 center0, (pts[1].fX - pts[0].fX) / 2, 79 colors, pos, SK_ARRAY_COUNT(colors), tm, 80 0, &scale); 81 } 82 83 typedef void (*PaintProc)(SkPaint*, SkScalar width); 84 85 class BlurRectGM : public skiagm::GM { 86 SkAutoTUnref<SkMaskFilter> fMaskFilters[kLastEnum_SkBlurStyle + 1]; 87 SkString fName; 88 SkAlpha fAlpha; 89 public: 90 BlurRectGM(const char name[], U8CPU alpha) 91 : fName(name) 92 , fAlpha(SkToU8(alpha)) { 93 } 94 95 protected: 96 void onOnceBeforeDraw() override { 97 for (int i = 0; i <= kLastEnum_SkBlurStyle; ++i) { 98 fMaskFilters[i].reset(SkBlurMaskFilter::Create((SkBlurStyle)i, 99 SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(STROKE_WIDTH/2)), 100 SkBlurMaskFilter::kHighQuality_BlurFlag)); 101 } 102 } 103 104 SkString onShortName() override { 105 return fName; 106 } 107 108 SkISize onISize() override { 109 return SkISize::Make(860, 820); 110 } 111 112 void onDraw(SkCanvas* canvas) override { 113 canvas->translate(STROKE_WIDTH*3/2, STROKE_WIDTH*3/2); 114 115 SkRect r = { 0, 0, 100, 50 }; 116 SkScalar scales[] = { SK_Scalar1, 0.6f }; 117 118 for (size_t s = 0; s < SK_ARRAY_COUNT(scales); ++s) { 119 canvas->save(); 120 for (size_t f = 0; f < SK_ARRAY_COUNT(fMaskFilters); ++f) { 121 SkPaint paint; 122 paint.setMaskFilter(fMaskFilters[f]); 123 paint.setAlpha(fAlpha); 124 125 SkPaint paintWithRadial = paint; 126 paintWithRadial.setShader(MakeRadial())->unref(); 127 128 static const Proc procs[] = { 129 fill_rect, draw_donut, draw_donut_skewed 130 }; 131 132 canvas->save(); 133 canvas->scale(scales[s], scales[s]); 134 this->drawProcs(canvas, r, paint, false, procs, SK_ARRAY_COUNT(procs)); 135 canvas->translate(r.width() * 4/3, 0); 136 this->drawProcs(canvas, r, paintWithRadial, false, procs, SK_ARRAY_COUNT(procs)); 137 canvas->translate(r.width() * 4/3, 0); 138 this->drawProcs(canvas, r, paint, true, procs, SK_ARRAY_COUNT(procs)); 139 canvas->translate(r.width() * 4/3, 0); 140 this->drawProcs(canvas, r, paintWithRadial, true, procs, SK_ARRAY_COUNT(procs)); 141 canvas->restore(); 142 143 canvas->translate(0, SK_ARRAY_COUNT(procs) * r.height() * 4/3 * scales[s]); 144 } 145 canvas->restore(); 146 canvas->translate(4 * r.width() * 4/3 * scales[s], 0); 147 } 148 } 149 150 private: 151 void drawProcs(SkCanvas* canvas, const SkRect& r, const SkPaint& paint, 152 bool doClip, const Proc procs[], size_t procsCount) { 153 SkAutoCanvasRestore acr(canvas, true); 154 for (size_t i = 0; i < procsCount; ++i) { 155 if (doClip) { 156 SkRect clipRect(r); 157 clipRect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2); 158 canvas->save(); 159 canvas->clipRect(r); 160 } 161 procs[i](canvas, r, paint); 162 if (doClip) { 163 canvas->restore(); 164 } 165 canvas->translate(0, r.height() * 4/3); 166 } 167 } 168 private: 169 typedef GM INHERITED; 170 }; 171 172 DEF_SIMPLE_GM(blurrect_gallery, canvas, 1200, 1024) { 173 const int fGMWidth = 1200; 174 const int fPadding = 10; 175 const int fMargin = 100; 176 177 const int widths[] = {25, 5, 5, 100, 150, 25}; 178 const int heights[] = {100, 100, 5, 25, 150, 25}; 179 const SkBlurStyle styles[] = {kNormal_SkBlurStyle, kInner_SkBlurStyle, kOuter_SkBlurStyle}; 180 const float radii[] = {20, 5, 10}; 181 182 canvas->translate(50,20); 183 184 int cur_x = 0; 185 int cur_y = 0; 186 187 int max_height = 0; 188 189 for (size_t i = 0 ; i < SK_ARRAY_COUNT(widths) ; i++) { 190 int width = widths[i]; 191 int height = heights[i]; 192 SkRect r; 193 r.setWH(SkIntToScalar(width), SkIntToScalar(height)); 194 SkAutoCanvasRestore autoRestore(canvas, true); 195 196 for (size_t j = 0 ; j < SK_ARRAY_COUNT(radii) ; j++) { 197 float radius = radii[j]; 198 for (size_t k = 0 ; k < SK_ARRAY_COUNT(styles) ; k++) { 199 SkBlurStyle style = styles[k]; 200 201 SkMask mask; 202 if (!SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(radius), 203 &mask, r, style)) { 204 continue; 205 } 206 207 SkAutoMaskFreeImage amfi(mask.fImage); 208 209 SkBitmap bm; 210 bm.installMaskPixels(mask); 211 212 if (cur_x + bm.width() >= fGMWidth - fMargin) { 213 cur_x = 0; 214 cur_y += max_height + fPadding; 215 max_height = 0; 216 } 217 218 canvas->save(); 219 canvas->translate((SkScalar)cur_x, (SkScalar)cur_y); 220 canvas->translate(-(bm.width() - r.width())/2, -(bm.height()-r.height())/2); 221 canvas->drawBitmap(bm, 0.f, 0.f, nullptr); 222 canvas->restore(); 223 224 cur_x += bm.width() + fPadding; 225 if (bm.height() > max_height) 226 max_height = bm.height(); 227 } 228 } 229 } 230 } 231 232 ////////////////////////////////////////////////////////////////////////////// 233 234 DEF_GM(return new BlurRectGM("blurrects", 0xFF);) 235