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/gm.h" 9 #include "include/core/SkBitmap.h" 10 #include "include/core/SkBlurTypes.h" 11 #include "include/core/SkCanvas.h" 12 #include "include/core/SkColor.h" 13 #include "include/core/SkMaskFilter.h" 14 #include "include/core/SkMatrix.h" 15 #include "include/core/SkPaint.h" 16 #include "include/core/SkPath.h" 17 #include "include/core/SkPoint.h" 18 #include "include/core/SkRect.h" 19 #include "include/core/SkRefCnt.h" 20 #include "include/core/SkScalar.h" 21 #include "include/core/SkShader.h" 22 #include "include/core/SkSize.h" 23 #include "include/core/SkString.h" 24 #include "include/core/SkTileMode.h" 25 #include "include/core/SkTypes.h" 26 #include "include/effects/SkGradientShader.h" 27 #include "include/private/SkTo.h" 28 #include "src/core/SkBlurMask.h" 29 #include "src/core/SkMask.h" 30 31 #define STROKE_WIDTH SkIntToScalar(10) 32 33 typedef void (*Proc)(SkCanvas*, const SkRect&, const SkPaint&); 34 fill_rect(SkCanvas * canvas,const SkRect & r,const SkPaint & p)35 static void fill_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) { 36 canvas->drawRect(r, p); 37 } 38 draw_donut(SkCanvas * canvas,const SkRect & r,const SkPaint & p)39 static void draw_donut(SkCanvas* canvas, const SkRect& r, const SkPaint& p) { 40 SkRect rect; 41 SkPath path; 42 43 rect = r; 44 rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2); 45 path.addRect(rect); 46 rect = r; 47 rect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2); 48 49 path.addRect(rect); 50 path.setFillType(SkPath::kEvenOdd_FillType); 51 52 canvas->drawPath(path, p); 53 } 54 draw_donut_skewed(SkCanvas * canvas,const SkRect & r,const SkPaint & p)55 static void draw_donut_skewed(SkCanvas* canvas, const SkRect& r, const SkPaint& p) { 56 SkRect rect; 57 SkPath path; 58 59 rect = r; 60 rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2); 61 path.addRect(rect); 62 rect = r; 63 rect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2); 64 65 rect.offset(7, -7); 66 67 path.addRect(rect); 68 path.setFillType(SkPath::kEvenOdd_FillType); 69 70 canvas->drawPath(path, p); 71 } 72 73 /* 74 * Spits out a dummy gradient to test blur with shader on paint 75 */ make_radial()76 static sk_sp<SkShader> make_radial() { 77 SkPoint pts[2] = { 78 { 0, 0 }, 79 { SkIntToScalar(100), SkIntToScalar(100) } 80 }; 81 SkTileMode tm = SkTileMode::kClamp; 82 const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, }; 83 const SkScalar pos[] = { SK_Scalar1/4, SK_Scalar1*3/4 }; 84 SkMatrix scale; 85 scale.setScale(0.5f, 0.5f); 86 scale.postTranslate(25.f, 25.f); 87 SkPoint center0, center1; 88 center0.set(SkScalarAve(pts[0].fX, pts[1].fX), 89 SkScalarAve(pts[0].fY, pts[1].fY)); 90 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), 91 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); 92 return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7, 93 center0, (pts[1].fX - pts[0].fX) / 2, 94 colors, pos, SK_ARRAY_COUNT(colors), tm, 95 0, &scale); 96 } 97 98 typedef void (*PaintProc)(SkPaint*, SkScalar width); 99 100 class BlurRectGM : public skiagm::GM { 101 public: BlurRectGM(const char name[],U8CPU alpha)102 BlurRectGM(const char name[], U8CPU alpha) : fName(name), fAlpha(SkToU8(alpha)) {} 103 104 private: 105 sk_sp<SkMaskFilter> fMaskFilters[kLastEnum_SkBlurStyle + 1]; 106 const char* fName; 107 SkAlpha fAlpha; 108 onOnceBeforeDraw()109 void onOnceBeforeDraw() override { 110 for (int i = 0; i <= kLastEnum_SkBlurStyle; ++i) { 111 fMaskFilters[i] = SkMaskFilter::MakeBlur((SkBlurStyle)i, 112 SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(STROKE_WIDTH/2))); 113 } 114 } 115 onShortName()116 SkString onShortName() override { return SkString(fName); } 117 onISize()118 SkISize onISize() override { return {860, 820}; } 119 onDraw(SkCanvas * canvas)120 void onDraw(SkCanvas* canvas) override { 121 canvas->translate(STROKE_WIDTH*3/2, STROKE_WIDTH*3/2); 122 123 SkRect r = { 0, 0, 100, 50 }; 124 SkScalar scales[] = { SK_Scalar1, 0.6f }; 125 126 for (size_t s = 0; s < SK_ARRAY_COUNT(scales); ++s) { 127 canvas->save(); 128 for (size_t f = 0; f < SK_ARRAY_COUNT(fMaskFilters); ++f) { 129 SkPaint paint; 130 paint.setMaskFilter(fMaskFilters[f]); 131 paint.setAlpha(fAlpha); 132 133 SkPaint paintWithRadial = paint; 134 paintWithRadial.setShader(make_radial()); 135 136 constexpr Proc procs[] = { 137 fill_rect, draw_donut, draw_donut_skewed 138 }; 139 140 canvas->save(); 141 canvas->scale(scales[s], scales[s]); 142 this->drawProcs(canvas, r, paint, false, procs, SK_ARRAY_COUNT(procs)); 143 canvas->translate(r.width() * 4/3, 0); 144 this->drawProcs(canvas, r, paintWithRadial, false, procs, SK_ARRAY_COUNT(procs)); 145 canvas->translate(r.width() * 4/3, 0); 146 this->drawProcs(canvas, r, paint, true, procs, SK_ARRAY_COUNT(procs)); 147 canvas->translate(r.width() * 4/3, 0); 148 this->drawProcs(canvas, r, paintWithRadial, true, procs, SK_ARRAY_COUNT(procs)); 149 canvas->restore(); 150 151 canvas->translate(0, SK_ARRAY_COUNT(procs) * r.height() * 4/3 * scales[s]); 152 } 153 canvas->restore(); 154 canvas->translate(4 * r.width() * 4/3 * scales[s], 0); 155 } 156 } 157 drawProcs(SkCanvas * canvas,const SkRect & r,const SkPaint & paint,bool doClip,const Proc procs[],size_t procsCount)158 void drawProcs(SkCanvas* canvas, const SkRect& r, const SkPaint& paint, 159 bool doClip, const Proc procs[], size_t procsCount) { 160 SkAutoCanvasRestore acr(canvas, true); 161 for (size_t i = 0; i < procsCount; ++i) { 162 if (doClip) { 163 SkRect clipRect(r); 164 clipRect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2); 165 canvas->save(); 166 canvas->clipRect(r); 167 } 168 procs[i](canvas, r, paint); 169 if (doClip) { 170 canvas->restore(); 171 } 172 canvas->translate(0, r.height() * 4/3); 173 } 174 } 175 }; 176 177 DEF_SIMPLE_GM(blurrect_gallery, canvas, 1200, 1024) { 178 const int fGMWidth = 1200; 179 const int fPadding = 10; 180 const int fMargin = 100; 181 182 const int widths[] = {25, 5, 5, 100, 150, 25}; 183 const int heights[] = {100, 100, 5, 25, 150, 25}; 184 const SkBlurStyle styles[] = {kNormal_SkBlurStyle, kInner_SkBlurStyle, kOuter_SkBlurStyle}; 185 const float radii[] = {20, 5, 10}; 186 187 canvas->translate(50,20); 188 189 int cur_x = 0; 190 int cur_y = 0; 191 192 int max_height = 0; 193 194 for (size_t i = 0 ; i < SK_ARRAY_COUNT(widths) ; i++) { 195 int width = widths[i]; 196 int height = heights[i]; 197 SkRect r; 198 r.setWH(SkIntToScalar(width), SkIntToScalar(height)); 199 SkAutoCanvasRestore autoRestore(canvas, true); 200 201 for (size_t j = 0 ; j < SK_ARRAY_COUNT(radii) ; j++) { 202 float radius = radii[j]; 203 for (size_t k = 0 ; k < SK_ARRAY_COUNT(styles) ; k++) { 204 SkBlurStyle style = styles[k]; 205 206 SkMask mask; 207 if (!SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(radius), 208 &mask, r, style)) { 209 continue; 210 } 211 212 SkAutoMaskFreeImage amfi(mask.fImage); 213 214 SkBitmap bm; 215 bm.installMaskPixels(mask); 216 217 if (cur_x + bm.width() >= fGMWidth - fMargin) { 218 cur_x = 0; 219 cur_y += max_height + fPadding; 220 max_height = 0; 221 } 222 223 canvas->save(); 224 canvas->translate((SkScalar)cur_x, (SkScalar)cur_y); 225 canvas->translate(-(bm.width() - r.width())/2, -(bm.height()-r.height())/2); 226 canvas->drawBitmap(bm, 0.f, 0.f, nullptr); 227 canvas->restore(); 228 229 cur_x += bm.width() + fPadding; 230 if (bm.height() > max_height) 231 max_height = bm.height(); 232 } 233 } 234 } 235 } 236 237 ////////////////////////////////////////////////////////////////////////////// 238 239 DEF_GM(return new BlurRectGM("blurrects", 0xFF);) 240