• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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