• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006 The Android Open Source Project
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 "SkBlurMaskFilter.h"
9 #include "SkBlurMask.h"
10 #include "SkGpuBlurUtils.h"
11 #include "SkReadBuffer.h"
12 #include "SkWriteBuffer.h"
13 #include "SkMaskFilter.h"
14 #include "SkRRect.h"
15 #include "SkStringUtils.h"
16 #include "SkStrokeRec.h"
17 
18 #if SK_SUPPORT_GPU
19 #include "GrCircleBlurFragmentProcessor.h"
20 #include "GrClip.h"
21 #include "GrContext.h"
22 #include "GrFragmentProcessor.h"
23 #include "GrRenderTargetContext.h"
24 #include "GrResourceProvider.h"
25 #include "GrShaderCaps.h"
26 #include "GrStyle.h"
27 #include "GrTexture.h"
28 #include "GrTextureProxy.h"
29 #include "effects/GrSimpleTextureEffect.h"
30 #include "glsl/GrGLSLFragmentProcessor.h"
31 #include "glsl/GrGLSLFragmentShaderBuilder.h"
32 #include "glsl/GrGLSLProgramDataManager.h"
33 #include "glsl/GrGLSLUniformHandler.h"
34 #endif
35 
ConvertRadiusToSigma(SkScalar radius)36 SkScalar SkBlurMaskFilter::ConvertRadiusToSigma(SkScalar radius) {
37     return SkBlurMask::ConvertRadiusToSigma(radius);
38 }
39 
40 class SkBlurMaskFilterImpl : public SkMaskFilter {
41 public:
42     SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle, const SkRect& occluder, uint32_t flags);
43 
44     // overrides from SkMaskFilter
45     SkMask::Format getFormat() const override;
46     bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
47                     SkIPoint* margin) const override;
48 
49 #if SK_SUPPORT_GPU
50     bool canFilterMaskGPU(const SkRRect& devRRect,
51                           const SkIRect& clipBounds,
52                           const SkMatrix& ctm,
53                           SkRect* maskRect) const override;
54     bool directFilterMaskGPU(GrContext*,
55                              GrRenderTargetContext* renderTargetContext,
56                              GrPaint&&,
57                              const GrClip&,
58                              const SkMatrix& viewMatrix,
59                              const SkStrokeRec& strokeRec,
60                              const SkPath& path) const override;
61     bool directFilterRRectMaskGPU(GrContext*,
62                                   GrRenderTargetContext* renderTargetContext,
63                                   GrPaint&&,
64                                   const GrClip&,
65                                   const SkMatrix& viewMatrix,
66                                   const SkStrokeRec& strokeRec,
67                                   const SkRRect& rrect,
68                                   const SkRRect& devRRect) const override;
69     sk_sp<GrTextureProxy> filterMaskGPU(GrContext*,
70                                         sk_sp<GrTextureProxy> srcProxy,
71                                         const SkMatrix& ctm,
72                                         const SkIRect& maskRect) const override;
73 #endif
74 
75     void computeFastBounds(const SkRect&, SkRect*) const override;
76     bool asABlur(BlurRec*) const override;
77 
78     SK_TO_STRING_OVERRIDE()
79     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)
80 
81 protected:
82     FilterReturn filterRectsToNine(const SkRect[], int count, const SkMatrix&,
83                                    const SkIRect& clipBounds,
84                                    NinePatch*) const override;
85 
86     FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&,
87                                    const SkIRect& clipBounds,
88                                    NinePatch*) const override;
89 
90     bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix,
91                         SkIPoint* margin, SkMask::CreateMode createMode) const;
92     bool filterRRectMask(SkMask* dstM, const SkRRect& r, const SkMatrix& matrix,
93                         SkIPoint* margin, SkMask::CreateMode createMode) const;
94 
ignoreXform() const95     bool ignoreXform() const {
96         return SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
97     }
98 
99 private:
100     // To avoid unseemly allocation requests (esp. for finite platforms like
101     // handset) we limit the radius so something manageable. (as opposed to
102     // a request like 10,000)
103     static const SkScalar kMAX_BLUR_SIGMA;
104 
105     SkScalar    fSigma;
106     SkBlurStyle fBlurStyle;
107     SkRect      fOccluder;
108     uint32_t    fBlurFlags;
109 
getQuality() const110     SkBlurQuality getQuality() const {
111         return (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
112                 kHigh_SkBlurQuality : kLow_SkBlurQuality;
113     }
114 
115     SkBlurMaskFilterImpl(SkReadBuffer&);
116     void flatten(SkWriteBuffer&) const override;
117 
computeXformedSigma(const SkMatrix & ctm) const118     SkScalar computeXformedSigma(const SkMatrix& ctm) const {
119         SkScalar xformedSigma = this->ignoreXform() ? fSigma : ctm.mapRadius(fSigma);
120         return SkMinScalar(xformedSigma, kMAX_BLUR_SIGMA);
121     }
122 
123     friend class SkBlurMaskFilter;
124 
125     typedef SkMaskFilter INHERITED;
126 };
127 
128 const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_SIGMA = SkIntToScalar(128);
129 
Make(SkBlurStyle style,SkScalar sigma,const SkRect & occluder,uint32_t flags)130 sk_sp<SkMaskFilter> SkBlurMaskFilter::Make(SkBlurStyle style, SkScalar sigma,
131                                            const SkRect& occluder, uint32_t flags) {
132     SkASSERT(!(flags & ~SkBlurMaskFilter::kAll_BlurFlag));
133     SkASSERT(style <= kLastEnum_SkBlurStyle);
134 
135     if (!SkScalarIsFinite(sigma) || sigma <= 0) {
136         return nullptr;
137     }
138 
139     return sk_sp<SkMaskFilter>(new SkBlurMaskFilterImpl(sigma, style, occluder, flags));
140 }
141 
142 // linearly interpolate between y1 & y3 to match x2's position between x1 & x3
interp(SkScalar x1,SkScalar x2,SkScalar x3,SkScalar y1,SkScalar y3)143 static SkScalar interp(SkScalar x1, SkScalar x2, SkScalar x3, SkScalar y1, SkScalar y3) {
144     SkASSERT(x1 <= x2 && x2 <= x3);
145     SkASSERT(y1 <= y3);
146 
147     SkScalar t = (x2 - x1) / (x3 - x1);
148     return y1 + t * (y3 - y1);
149 }
150 
151 // Insert 'lower' and 'higher' into 'array1' and insert a new value at each matching insertion
152 // point in 'array2' that linearly interpolates between the existing values.
153 // Return a bit mask which contains a copy of 'inputMask' for all the cells between the two
154 // insertion points.
insert_into_arrays(SkScalar * array1,SkScalar * array2,SkScalar lower,SkScalar higher,int * num,uint32_t inputMask,int maskSize)155 static uint32_t insert_into_arrays(SkScalar* array1, SkScalar* array2,
156                                    SkScalar lower, SkScalar higher,
157                                    int* num, uint32_t inputMask, int maskSize) {
158     SkASSERT(lower < higher);
159     SkASSERT(lower >= array1[0] && higher <= array1[*num-1]);
160 
161     int32_t skipMask = 0x0;
162     int i;
163     for (i = 0; i < *num; ++i) {
164         if (lower >= array1[i] && lower < array1[i+1]) {
165             if (!SkScalarNearlyEqual(lower, array1[i])) {
166                 memmove(&array1[i+2], &array1[i+1], (*num-i-1)*sizeof(SkScalar));
167                 array1[i+1] = lower;
168                 memmove(&array2[i+2], &array2[i+1], (*num-i-1)*sizeof(SkScalar));
169                 array2[i+1] = interp(array1[i], lower, array1[i+2], array2[i], array2[i+2]);
170                 i++;
171                 (*num)++;
172             }
173             break;
174         }
175     }
176     for ( ; i < *num; ++i) {
177         skipMask |= inputMask << (i*maskSize);
178         if (higher > array1[i] && higher <= array1[i+1]) {
179             if (!SkScalarNearlyEqual(higher, array1[i+1])) {
180                 memmove(&array1[i+2], &array1[i+1], (*num-i-1)*sizeof(SkScalar));
181                 array1[i+1] = higher;
182                 memmove(&array2[i+2], &array2[i+1], (*num-i-1)*sizeof(SkScalar));
183                 array2[i+1] = interp(array1[i], higher, array1[i+2], array2[i], array2[i+2]);
184                 (*num)++;
185             }
186             break;
187         }
188     }
189 
190     return skipMask;
191 }
192 
ComputeBlurredRRectParams(const SkRRect & srcRRect,const SkRRect & devRRect,const SkRect & occluder,SkScalar sigma,SkScalar xformedSigma,SkRRect * rrectToDraw,SkISize * widthHeight,SkScalar rectXs[kMaxDivisions],SkScalar rectYs[kMaxDivisions],SkScalar texXs[kMaxDivisions],SkScalar texYs[kMaxDivisions],int * numXs,int * numYs,uint32_t * skipMask)193 bool SkBlurMaskFilter::ComputeBlurredRRectParams(const SkRRect& srcRRect, const SkRRect& devRRect,
194                                                  const SkRect& occluder,
195                                                  SkScalar sigma, SkScalar xformedSigma,
196                                                  SkRRect* rrectToDraw,
197                                                  SkISize* widthHeight,
198                                                  SkScalar rectXs[kMaxDivisions],
199                                                  SkScalar rectYs[kMaxDivisions],
200                                                  SkScalar texXs[kMaxDivisions],
201                                                  SkScalar texYs[kMaxDivisions],
202                                                  int* numXs, int* numYs, uint32_t* skipMask) {
203     unsigned int devBlurRadius = 3*SkScalarCeilToInt(xformedSigma-1/6.0f);
204     SkScalar srcBlurRadius = 3.0f * sigma;
205 
206     const SkRect& devOrig = devRRect.getBounds();
207     const SkVector& devRadiiUL = devRRect.radii(SkRRect::kUpperLeft_Corner);
208     const SkVector& devRadiiUR = devRRect.radii(SkRRect::kUpperRight_Corner);
209     const SkVector& devRadiiLR = devRRect.radii(SkRRect::kLowerRight_Corner);
210     const SkVector& devRadiiLL = devRRect.radii(SkRRect::kLowerLeft_Corner);
211 
212     const int devLeft  = SkScalarCeilToInt(SkTMax<SkScalar>(devRadiiUL.fX, devRadiiLL.fX));
213     const int devTop   = SkScalarCeilToInt(SkTMax<SkScalar>(devRadiiUL.fY, devRadiiUR.fY));
214     const int devRight = SkScalarCeilToInt(SkTMax<SkScalar>(devRadiiUR.fX, devRadiiLR.fX));
215     const int devBot   = SkScalarCeilToInt(SkTMax<SkScalar>(devRadiiLL.fY, devRadiiLR.fY));
216 
217     // This is a conservative check for nine-patchability
218     if (devOrig.fLeft + devLeft + devBlurRadius >= devOrig.fRight  - devRight - devBlurRadius ||
219         devOrig.fTop  + devTop  + devBlurRadius >= devOrig.fBottom - devBot   - devBlurRadius) {
220         return false;
221     }
222 
223     const SkVector& srcRadiiUL = srcRRect.radii(SkRRect::kUpperLeft_Corner);
224     const SkVector& srcRadiiUR = srcRRect.radii(SkRRect::kUpperRight_Corner);
225     const SkVector& srcRadiiLR = srcRRect.radii(SkRRect::kLowerRight_Corner);
226     const SkVector& srcRadiiLL = srcRRect.radii(SkRRect::kLowerLeft_Corner);
227 
228     const SkScalar srcLeft  = SkTMax<SkScalar>(srcRadiiUL.fX, srcRadiiLL.fX);
229     const SkScalar srcTop   = SkTMax<SkScalar>(srcRadiiUL.fY, srcRadiiUR.fY);
230     const SkScalar srcRight = SkTMax<SkScalar>(srcRadiiUR.fX, srcRadiiLR.fX);
231     const SkScalar srcBot   = SkTMax<SkScalar>(srcRadiiLL.fY, srcRadiiLR.fY);
232 
233     int newRRWidth = 2*devBlurRadius + devLeft + devRight + 1;
234     int newRRHeight = 2*devBlurRadius + devTop + devBot + 1;
235     widthHeight->fWidth = newRRWidth + 2 * devBlurRadius;
236     widthHeight->fHeight = newRRHeight + 2 * devBlurRadius;
237 
238     const SkRect srcProxyRect = srcRRect.getBounds().makeOutset(srcBlurRadius, srcBlurRadius);
239 
240     rectXs[0] = srcProxyRect.fLeft;
241     rectXs[1] = srcProxyRect.fLeft + 2*srcBlurRadius + srcLeft;
242     rectXs[2] = srcProxyRect.fRight - 2*srcBlurRadius - srcRight;
243     rectXs[3] = srcProxyRect.fRight;
244 
245     rectYs[0] = srcProxyRect.fTop;
246     rectYs[1] = srcProxyRect.fTop + 2*srcBlurRadius + srcTop;
247     rectYs[2] = srcProxyRect.fBottom - 2*srcBlurRadius - srcBot;
248     rectYs[3] = srcProxyRect.fBottom;
249 
250     texXs[0] = 0.0f;
251     texXs[1] = 2.0f*devBlurRadius + devLeft;
252     texXs[2] = 2.0f*devBlurRadius + devLeft + 1;
253     texXs[3] = SkIntToScalar(widthHeight->fWidth);
254 
255     texYs[0] = 0.0f;
256     texYs[1] = 2.0f*devBlurRadius + devTop;
257     texYs[2] = 2.0f*devBlurRadius + devTop + 1;
258     texYs[3] = SkIntToScalar(widthHeight->fHeight);
259 
260     SkRect temp = occluder;
261 
262     *numXs = 4;
263     *numYs = 4;
264     *skipMask = 0;
265     if (!temp.isEmpty() && (srcProxyRect.contains(temp) || temp.intersect(srcProxyRect))) {
266         *skipMask = insert_into_arrays(rectXs, texXs, temp.fLeft, temp.fRight, numXs, 0x1, 1);
267         *skipMask = insert_into_arrays(rectYs, texYs, temp.fTop, temp.fBottom,
268                                        numYs, *skipMask, *numXs-1);
269     }
270 
271     const SkRect newRect = SkRect::MakeXYWH(SkIntToScalar(devBlurRadius),
272                                             SkIntToScalar(devBlurRadius),
273                                             SkIntToScalar(newRRWidth),
274                                             SkIntToScalar(newRRHeight));
275     SkVector newRadii[4];
276     newRadii[0] = { SkScalarCeilToScalar(devRadiiUL.fX), SkScalarCeilToScalar(devRadiiUL.fY) };
277     newRadii[1] = { SkScalarCeilToScalar(devRadiiUR.fX), SkScalarCeilToScalar(devRadiiUR.fY) };
278     newRadii[2] = { SkScalarCeilToScalar(devRadiiLR.fX), SkScalarCeilToScalar(devRadiiLR.fY) };
279     newRadii[3] = { SkScalarCeilToScalar(devRadiiLL.fX), SkScalarCeilToScalar(devRadiiLL.fY) };
280 
281     rrectToDraw->setRectRadii(newRect, newRadii);
282     return true;
283 }
284 
285 ///////////////////////////////////////////////////////////////////////////////
286 
SkBlurMaskFilterImpl(SkScalar sigma,SkBlurStyle style,const SkRect & occluder,uint32_t flags)287 SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle style,
288                                            const SkRect& occluder, uint32_t flags)
289     : fSigma(sigma)
290     , fBlurStyle(style)
291     , fOccluder(occluder)
292     , fBlurFlags(flags) {
293     SkASSERT(fSigma > 0);
294     SkASSERT((unsigned)style <= kLastEnum_SkBlurStyle);
295     SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
296 }
297 
getFormat() const298 SkMask::Format SkBlurMaskFilterImpl::getFormat() const {
299     return SkMask::kA8_Format;
300 }
301 
asABlur(BlurRec * rec) const302 bool SkBlurMaskFilterImpl::asABlur(BlurRec* rec) const {
303     if (this->ignoreXform()) {
304         return false;
305     }
306 
307     if (rec) {
308         rec->fSigma = fSigma;
309         rec->fStyle = fBlurStyle;
310         rec->fQuality = this->getQuality();
311     }
312     return true;
313 }
314 
filterMask(SkMask * dst,const SkMask & src,const SkMatrix & matrix,SkIPoint * margin) const315 bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
316                                       const SkMatrix& matrix,
317                                       SkIPoint* margin) const {
318     SkScalar sigma = this->computeXformedSigma(matrix);
319     return SkBlurMask::BoxBlur(dst, src, sigma, fBlurStyle, this->getQuality(), margin);
320 }
321 
filterRectMask(SkMask * dst,const SkRect & r,const SkMatrix & matrix,SkIPoint * margin,SkMask::CreateMode createMode) const322 bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
323                                           const SkMatrix& matrix,
324                                           SkIPoint* margin, SkMask::CreateMode createMode) const {
325     SkScalar sigma = computeXformedSigma(matrix);
326 
327     return SkBlurMask::BlurRect(sigma, dst, r, fBlurStyle, margin, createMode);
328 }
329 
filterRRectMask(SkMask * dst,const SkRRect & r,const SkMatrix & matrix,SkIPoint * margin,SkMask::CreateMode createMode) const330 bool SkBlurMaskFilterImpl::filterRRectMask(SkMask* dst, const SkRRect& r,
331                                           const SkMatrix& matrix,
332                                           SkIPoint* margin, SkMask::CreateMode createMode) const {
333     SkScalar sigma = computeXformedSigma(matrix);
334 
335     return SkBlurMask::BlurRRect(sigma, dst, r, fBlurStyle, margin, createMode);
336 }
337 
338 #include "SkCanvas.h"
339 
prepare_to_draw_into_mask(const SkRect & bounds,SkMask * mask)340 static bool prepare_to_draw_into_mask(const SkRect& bounds, SkMask* mask) {
341     SkASSERT(mask != nullptr);
342 
343     mask->fBounds = bounds.roundOut();
344     mask->fRowBytes = SkAlign4(mask->fBounds.width());
345     mask->fFormat = SkMask::kA8_Format;
346     const size_t size = mask->computeImageSize();
347     mask->fImage = SkMask::AllocImage(size);
348     if (nullptr == mask->fImage) {
349         return false;
350     }
351 
352     // FIXME: use sk_calloc in AllocImage?
353     sk_bzero(mask->fImage, size);
354     return true;
355 }
356 
draw_rrect_into_mask(const SkRRect rrect,SkMask * mask)357 static bool draw_rrect_into_mask(const SkRRect rrect, SkMask* mask) {
358     if (!prepare_to_draw_into_mask(rrect.rect(), mask)) {
359         return false;
360     }
361 
362     // FIXME: This code duplicates code in draw_rects_into_mask, below. Is there a
363     // clean way to share more code?
364     SkBitmap bitmap;
365     bitmap.installMaskPixels(*mask);
366 
367     SkCanvas canvas(bitmap);
368     canvas.translate(-SkIntToScalar(mask->fBounds.left()),
369                      -SkIntToScalar(mask->fBounds.top()));
370 
371     SkPaint paint;
372     paint.setAntiAlias(true);
373     canvas.drawRRect(rrect, paint);
374     return true;
375 }
376 
draw_rects_into_mask(const SkRect rects[],int count,SkMask * mask)377 static bool draw_rects_into_mask(const SkRect rects[], int count, SkMask* mask) {
378     if (!prepare_to_draw_into_mask(rects[0], mask)) {
379         return false;
380     }
381 
382     SkBitmap bitmap;
383     bitmap.installPixels(SkImageInfo::Make(mask->fBounds.width(),
384                                            mask->fBounds.height(),
385                                            kAlpha_8_SkColorType,
386                                            kPremul_SkAlphaType),
387                          mask->fImage, mask->fRowBytes);
388 
389     SkCanvas canvas(bitmap);
390     canvas.translate(-SkIntToScalar(mask->fBounds.left()),
391                      -SkIntToScalar(mask->fBounds.top()));
392 
393     SkPaint paint;
394     paint.setAntiAlias(true);
395 
396     if (1 == count) {
397         canvas.drawRect(rects[0], paint);
398     } else {
399         // todo: do I need a fast way to do this?
400         SkPath path;
401         path.addRect(rects[0]);
402         path.addRect(rects[1]);
403         path.setFillType(SkPath::kEvenOdd_FillType);
404         canvas.drawPath(path, paint);
405     }
406     return true;
407 }
408 
rect_exceeds(const SkRect & r,SkScalar v)409 static bool rect_exceeds(const SkRect& r, SkScalar v) {
410     return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v ||
411            r.width() > v || r.height() > v;
412 }
413 
414 #include "SkMaskCache.h"
415 
copy_mask_to_cacheddata(SkMask * mask)416 static SkCachedData* copy_mask_to_cacheddata(SkMask* mask) {
417     const size_t size = mask->computeTotalImageSize();
418     SkCachedData* data = SkResourceCache::NewCachedData(size);
419     if (data) {
420         memcpy(data->writable_data(), mask->fImage, size);
421         SkMask::FreeImage(mask->fImage);
422         mask->fImage = (uint8_t*)data->data();
423     }
424     return data;
425 }
426 
find_cached_rrect(SkMask * mask,SkScalar sigma,SkBlurStyle style,SkBlurQuality quality,const SkRRect & rrect)427 static SkCachedData* find_cached_rrect(SkMask* mask, SkScalar sigma, SkBlurStyle style,
428                                        SkBlurQuality quality, const SkRRect& rrect) {
429     return SkMaskCache::FindAndRef(sigma, style, quality, rrect, mask);
430 }
431 
add_cached_rrect(SkMask * mask,SkScalar sigma,SkBlurStyle style,SkBlurQuality quality,const SkRRect & rrect)432 static SkCachedData* add_cached_rrect(SkMask* mask, SkScalar sigma, SkBlurStyle style,
433                                       SkBlurQuality quality, const SkRRect& rrect) {
434     SkCachedData* cache = copy_mask_to_cacheddata(mask);
435     if (cache) {
436         SkMaskCache::Add(sigma, style, quality, rrect, *mask, cache);
437     }
438     return cache;
439 }
440 
find_cached_rects(SkMask * mask,SkScalar sigma,SkBlurStyle style,SkBlurQuality quality,const SkRect rects[],int count)441 static SkCachedData* find_cached_rects(SkMask* mask, SkScalar sigma, SkBlurStyle style,
442                                        SkBlurQuality quality, const SkRect rects[], int count) {
443     return SkMaskCache::FindAndRef(sigma, style, quality, rects, count, mask);
444 }
445 
add_cached_rects(SkMask * mask,SkScalar sigma,SkBlurStyle style,SkBlurQuality quality,const SkRect rects[],int count)446 static SkCachedData* add_cached_rects(SkMask* mask, SkScalar sigma, SkBlurStyle style,
447                                       SkBlurQuality quality, const SkRect rects[], int count) {
448     SkCachedData* cache = copy_mask_to_cacheddata(mask);
449     if (cache) {
450         SkMaskCache::Add(sigma, style, quality, rects, count, *mask, cache);
451     }
452     return cache;
453 }
454 
455 #ifdef SK_IGNORE_FAST_RRECT_BLUR
456   // Use the faster analytic blur approach for ninepatch round rects
457   static const bool c_analyticBlurRRect{false};
458 #else
459   static const bool c_analyticBlurRRect{true};
460 #endif
461 
462 SkMaskFilter::FilterReturn
filterRRectToNine(const SkRRect & rrect,const SkMatrix & matrix,const SkIRect & clipBounds,NinePatch * patch) const463 SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& matrix,
464                                         const SkIRect& clipBounds,
465                                         NinePatch* patch) const {
466     SkASSERT(patch != nullptr);
467     switch (rrect.getType()) {
468         case SkRRect::kEmpty_Type:
469             // Nothing to draw.
470             return kFalse_FilterReturn;
471 
472         case SkRRect::kRect_Type:
473             // We should have caught this earlier.
474             SkASSERT(false);
475             // Fall through.
476         case SkRRect::kOval_Type:
477             // The nine patch special case does not handle ovals, and we
478             // already have code for rectangles.
479             return kUnimplemented_FilterReturn;
480 
481         // These three can take advantage of this fast path.
482         case SkRRect::kSimple_Type:
483         case SkRRect::kNinePatch_Type:
484         case SkRRect::kComplex_Type:
485             break;
486     }
487 
488     // TODO: report correct metrics for innerstyle, where we do not grow the
489     // total bounds, but we do need an inset the size of our blur-radius
490     if (kInner_SkBlurStyle == fBlurStyle) {
491         return kUnimplemented_FilterReturn;
492     }
493 
494     // TODO: take clipBounds into account to limit our coordinates up front
495     // for now, just skip too-large src rects (to take the old code path).
496     if (rect_exceeds(rrect.rect(), SkIntToScalar(32767))) {
497         return kUnimplemented_FilterReturn;
498     }
499 
500     SkIPoint margin;
501     SkMask  srcM, dstM;
502     srcM.fBounds = rrect.rect().roundOut();
503     srcM.fFormat = SkMask::kA8_Format;
504     srcM.fRowBytes = 0;
505 
506     bool filterResult = false;
507     if (c_analyticBlurRRect) {
508         // special case for fast round rect blur
509         // don't actually do the blur the first time, just compute the correct size
510         filterResult = this->filterRRectMask(&dstM, rrect, matrix, &margin,
511                                             SkMask::kJustComputeBounds_CreateMode);
512     }
513 
514     if (!filterResult) {
515         filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
516     }
517 
518     if (!filterResult) {
519         return kFalse_FilterReturn;
520     }
521 
522     // Now figure out the appropriate width and height of the smaller round rectangle
523     // to stretch. It will take into account the larger radius per side as well as double
524     // the margin, to account for inner and outer blur.
525     const SkVector& UL = rrect.radii(SkRRect::kUpperLeft_Corner);
526     const SkVector& UR = rrect.radii(SkRRect::kUpperRight_Corner);
527     const SkVector& LR = rrect.radii(SkRRect::kLowerRight_Corner);
528     const SkVector& LL = rrect.radii(SkRRect::kLowerLeft_Corner);
529 
530     const SkScalar leftUnstretched = SkTMax(UL.fX, LL.fX) + SkIntToScalar(2 * margin.fX);
531     const SkScalar rightUnstretched = SkTMax(UR.fX, LR.fX) + SkIntToScalar(2 * margin.fX);
532 
533     // Extra space in the middle to ensure an unchanging piece for stretching. Use 3 to cover
534     // any fractional space on either side plus 1 for the part to stretch.
535     const SkScalar stretchSize = SkIntToScalar(3);
536 
537     const SkScalar totalSmallWidth = leftUnstretched + rightUnstretched + stretchSize;
538     if (totalSmallWidth >= rrect.rect().width()) {
539         // There is no valid piece to stretch.
540         return kUnimplemented_FilterReturn;
541     }
542 
543     const SkScalar topUnstretched = SkTMax(UL.fY, UR.fY) + SkIntToScalar(2 * margin.fY);
544     const SkScalar bottomUnstretched = SkTMax(LL.fY, LR.fY) + SkIntToScalar(2 * margin.fY);
545 
546     const SkScalar totalSmallHeight = topUnstretched + bottomUnstretched + stretchSize;
547     if (totalSmallHeight >= rrect.rect().height()) {
548         // There is no valid piece to stretch.
549         return kUnimplemented_FilterReturn;
550     }
551 
552     SkRect smallR = SkRect::MakeWH(totalSmallWidth, totalSmallHeight);
553 
554     SkRRect smallRR;
555     SkVector radii[4];
556     radii[SkRRect::kUpperLeft_Corner] = UL;
557     radii[SkRRect::kUpperRight_Corner] = UR;
558     radii[SkRRect::kLowerRight_Corner] = LR;
559     radii[SkRRect::kLowerLeft_Corner] = LL;
560     smallRR.setRectRadii(smallR, radii);
561 
562     const SkScalar sigma = this->computeXformedSigma(matrix);
563     SkCachedData* cache = find_cached_rrect(&patch->fMask, sigma, fBlurStyle,
564                                             this->getQuality(), smallRR);
565     if (!cache) {
566         bool analyticBlurWorked = false;
567         if (c_analyticBlurRRect) {
568             analyticBlurWorked =
569                 this->filterRRectMask(&patch->fMask, smallRR, matrix, &margin,
570                                       SkMask::kComputeBoundsAndRenderImage_CreateMode);
571         }
572 
573         if (!analyticBlurWorked) {
574             if (!draw_rrect_into_mask(smallRR, &srcM)) {
575                 return kFalse_FilterReturn;
576             }
577 
578             SkAutoMaskFreeImage amf(srcM.fImage);
579 
580             if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
581                 return kFalse_FilterReturn;
582             }
583         }
584         cache = add_cached_rrect(&patch->fMask, sigma, fBlurStyle, this->getQuality(), smallRR);
585     }
586 
587     patch->fMask.fBounds.offsetTo(0, 0);
588     patch->fOuterRect = dstM.fBounds;
589     patch->fCenter.fX = SkScalarCeilToInt(leftUnstretched) + 1;
590     patch->fCenter.fY = SkScalarCeilToInt(topUnstretched) + 1;
591     SkASSERT(nullptr == patch->fCache);
592     patch->fCache = cache;  // transfer ownership to patch
593     return kTrue_FilterReturn;
594 }
595 
596 // Use the faster analytic blur approach for ninepatch rects
597 static const bool c_analyticBlurNinepatch{true};
598 
599 SkMaskFilter::FilterReturn
filterRectsToNine(const SkRect rects[],int count,const SkMatrix & matrix,const SkIRect & clipBounds,NinePatch * patch) const600 SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
601                                         const SkMatrix& matrix,
602                                         const SkIRect& clipBounds,
603                                         NinePatch* patch) const {
604     if (count < 1 || count > 2) {
605         return kUnimplemented_FilterReturn;
606     }
607 
608     // TODO: report correct metrics for innerstyle, where we do not grow the
609     // total bounds, but we do need an inset the size of our blur-radius
610     if (kInner_SkBlurStyle == fBlurStyle || kOuter_SkBlurStyle == fBlurStyle) {
611         return kUnimplemented_FilterReturn;
612     }
613 
614     // TODO: take clipBounds into account to limit our coordinates up front
615     // for now, just skip too-large src rects (to take the old code path).
616     if (rect_exceeds(rects[0], SkIntToScalar(32767))) {
617         return kUnimplemented_FilterReturn;
618     }
619 
620     SkIPoint margin;
621     SkMask  srcM, dstM;
622     srcM.fBounds = rects[0].roundOut();
623     srcM.fFormat = SkMask::kA8_Format;
624     srcM.fRowBytes = 0;
625 
626     bool filterResult = false;
627     if (count == 1 && c_analyticBlurNinepatch) {
628         // special case for fast rect blur
629         // don't actually do the blur the first time, just compute the correct size
630         filterResult = this->filterRectMask(&dstM, rects[0], matrix, &margin,
631                                             SkMask::kJustComputeBounds_CreateMode);
632     } else {
633         filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
634     }
635 
636     if (!filterResult) {
637         return kFalse_FilterReturn;
638     }
639 
640     /*
641      *  smallR is the smallest version of 'rect' that will still guarantee that
642      *  we get the same blur results on all edges, plus 1 center row/col that is
643      *  representative of the extendible/stretchable edges of the ninepatch.
644      *  Since our actual edge may be fractional we inset 1 more to be sure we
645      *  don't miss any interior blur.
646      *  x is an added pixel of blur, and { and } are the (fractional) edge
647      *  pixels from the original rect.
648      *
649      *   x x { x x .... x x } x x
650      *
651      *  Thus, in this case, we inset by a total of 5 (on each side) beginning
652      *  with our outer-rect (dstM.fBounds)
653      */
654     SkRect smallR[2];
655     SkIPoint center;
656 
657     // +2 is from +1 for each edge (to account for possible fractional edges
658     int smallW = dstM.fBounds.width() - srcM.fBounds.width() + 2;
659     int smallH = dstM.fBounds.height() - srcM.fBounds.height() + 2;
660     SkIRect innerIR;
661 
662     if (1 == count) {
663         innerIR = srcM.fBounds;
664         center.set(smallW, smallH);
665     } else {
666         SkASSERT(2 == count);
667         rects[1].roundIn(&innerIR);
668         center.set(smallW + (innerIR.left() - srcM.fBounds.left()),
669                    smallH + (innerIR.top() - srcM.fBounds.top()));
670     }
671 
672     // +1 so we get a clean, stretchable, center row/col
673     smallW += 1;
674     smallH += 1;
675 
676     // we want the inset amounts to be integral, so we don't change any
677     // fractional phase on the fRight or fBottom of our smallR.
678     const SkScalar dx = SkIntToScalar(innerIR.width() - smallW);
679     const SkScalar dy = SkIntToScalar(innerIR.height() - smallH);
680     if (dx < 0 || dy < 0) {
681         // we're too small, relative to our blur, to break into nine-patch,
682         // so we ask to have our normal filterMask() be called.
683         return kUnimplemented_FilterReturn;
684     }
685 
686     smallR[0].set(rects[0].left(), rects[0].top(), rects[0].right() - dx, rects[0].bottom() - dy);
687     if (smallR[0].width() < 2 || smallR[0].height() < 2) {
688         return kUnimplemented_FilterReturn;
689     }
690     if (2 == count) {
691         smallR[1].set(rects[1].left(), rects[1].top(),
692                       rects[1].right() - dx, rects[1].bottom() - dy);
693         SkASSERT(!smallR[1].isEmpty());
694     }
695 
696     const SkScalar sigma = this->computeXformedSigma(matrix);
697     SkCachedData* cache = find_cached_rects(&patch->fMask, sigma, fBlurStyle,
698                                             this->getQuality(), smallR, count);
699     if (!cache) {
700         if (count > 1 || !c_analyticBlurNinepatch) {
701             if (!draw_rects_into_mask(smallR, count, &srcM)) {
702                 return kFalse_FilterReturn;
703             }
704 
705             SkAutoMaskFreeImage amf(srcM.fImage);
706 
707             if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
708                 return kFalse_FilterReturn;
709             }
710         } else {
711             if (!this->filterRectMask(&patch->fMask, smallR[0], matrix, &margin,
712                                       SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
713                 return kFalse_FilterReturn;
714             }
715         }
716         cache = add_cached_rects(&patch->fMask, sigma, fBlurStyle, this->getQuality(), smallR, count);
717     }
718     patch->fMask.fBounds.offsetTo(0, 0);
719     patch->fOuterRect = dstM.fBounds;
720     patch->fCenter = center;
721     SkASSERT(nullptr == patch->fCache);
722     patch->fCache = cache;  // transfer ownership to patch
723     return kTrue_FilterReturn;
724 }
725 
computeFastBounds(const SkRect & src,SkRect * dst) const726 void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
727                                              SkRect* dst) const {
728     SkScalar pad = 3.0f * fSigma;
729 
730     dst->set(src.fLeft  - pad, src.fTop    - pad,
731              src.fRight + pad, src.fBottom + pad);
732 }
733 
CreateProc(SkReadBuffer & buffer)734 sk_sp<SkFlattenable> SkBlurMaskFilterImpl::CreateProc(SkReadBuffer& buffer) {
735     const SkScalar sigma = buffer.readScalar();
736     const unsigned style = buffer.readUInt();
737     unsigned flags = buffer.readUInt();
738 
739     buffer.validate(style <= kLastEnum_SkBlurStyle);
740     buffer.validate(!(flags & ~SkBlurMaskFilter::kAll_BlurFlag));
741 
742     flags &= SkBlurMaskFilter::kAll_BlurFlag;
743 
744     SkRect occluder;
745     if (buffer.isVersionLT(SkReadBuffer::kBlurMaskFilterWritesOccluder)) {
746         occluder.setEmpty();
747     } else {
748         buffer.readRect(&occluder);
749     }
750 
751     if (style <= kLastEnum_SkBlurStyle) {
752         return SkBlurMaskFilter::Make((SkBlurStyle)style, sigma, occluder, flags);
753     }
754     return nullptr;
755 }
756 
flatten(SkWriteBuffer & buffer) const757 void SkBlurMaskFilterImpl::flatten(SkWriteBuffer& buffer) const {
758     buffer.writeScalar(fSigma);
759     buffer.writeUInt(fBlurStyle);
760     buffer.writeUInt(fBlurFlags);
761     buffer.writeRect(fOccluder);
762 }
763 
764 
765 #if SK_SUPPORT_GPU
766 
767 class GrGLRectBlurEffect;
768 
769 class GrRectBlurEffect : public GrFragmentProcessor {
770 public:
~GrRectBlurEffect()771     ~GrRectBlurEffect() override { }
772 
name() const773     const char* name() const override { return "RectBlur"; }
774 
Make(GrResourceProvider * resourceProvider,const SkRect & rect,float sigma)775     static sk_sp<GrFragmentProcessor> Make(GrResourceProvider* resourceProvider,
776                                            const SkRect& rect, float sigma) {
777         int doubleProfileSize = SkScalarCeilToInt(12*sigma);
778 
779         if (doubleProfileSize >= rect.width() || doubleProfileSize >= rect.height()) {
780             // if the blur sigma is too large so the gaussian overlaps the whole
781             // rect in either direction, fall back to CPU path for now.
782             return nullptr;
783         }
784 
785         sk_sp<GrTextureProxy> blurProfile(CreateBlurProfileTexture(resourceProvider, sigma));
786         if (!blurProfile) {
787            return nullptr;
788         }
789         // in OpenGL ES, mediump floats have a minimum range of 2^14. If we have coordinates bigger
790         // than that, the shader math will end up with infinities and result in the blur effect not
791         // working correctly. To avoid this, we switch into highp when the coordinates are too big.
792         // As 2^14 is the minimum range but the actual range can be bigger, we might end up
793         // switching to highp sooner than strictly necessary, but most devices that have a bigger
794         // range for mediump also have mediump being exactly the same as highp (e.g. all non-OpenGL
795         // ES devices), and thus incur no additional penalty for the switch.
796         static const SkScalar kMAX_BLUR_COORD = SkIntToScalar(16000);
797         GrSLPrecision precision;
798         if (SkScalarAbs(rect.top()) > kMAX_BLUR_COORD ||
799             SkScalarAbs(rect.left()) > kMAX_BLUR_COORD ||
800             SkScalarAbs(rect.bottom()) > kMAX_BLUR_COORD ||
801             SkScalarAbs(rect.right()) > kMAX_BLUR_COORD ||
802             SkScalarAbs(rect.width()) > kMAX_BLUR_COORD ||
803             SkScalarAbs(rect.height()) > kMAX_BLUR_COORD) {
804             precision = kHigh_GrSLPrecision;
805         } else {
806             precision = kDefault_GrSLPrecision;
807         }
808 
809         return sk_sp<GrFragmentProcessor>(new GrRectBlurEffect(resourceProvider,
810                                                                rect, sigma,
811                                                                std::move(blurProfile), precision));
812     }
813 
getRect() const814     const SkRect& getRect() const { return fRect; }
getSigma() const815     float getSigma() const { return fSigma; }
precision() const816     GrSLPrecision precision() const { return fPrecision; }
817 
818 private:
819     GrRectBlurEffect(GrResourceProvider*, const SkRect& rect, float sigma,
820                      sk_sp<GrTextureProxy> blurProfile, GrSLPrecision fPrecision);
821 
822     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
823 
824     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
825 
826     bool onIsEqual(const GrFragmentProcessor&) const override;
827 
828     static sk_sp<GrTextureProxy> CreateBlurProfileTexture(GrResourceProvider*, float sigma);
829 
830     SkRect          fRect;
831     float           fSigma;
832     TextureSampler  fBlurProfileSampler;
833     GrSLPrecision   fPrecision;
834 
835     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
836 
837     typedef GrFragmentProcessor INHERITED;
838 };
839 
840 class GrGLRectBlurEffect : public GrGLSLFragmentProcessor {
841 public:
842     void emitCode(EmitArgs&) override;
843 
844     static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
845 
846 protected:
847     void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
848 
849 private:
850     typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
851 
852     UniformHandle       fProxyRectUniform;
853     UniformHandle       fProfileSizeUniform;
854 
855     typedef GrGLSLFragmentProcessor INHERITED;
856 };
857 
OutputRectBlurProfileLookup(GrGLSLFPFragmentBuilder * fragBuilder,GrGLSLFragmentProcessor::SamplerHandle sampler,const char * output,const char * profileSize,const char * loc,const char * blurred_width,const char * sharp_width)858 void OutputRectBlurProfileLookup(GrGLSLFPFragmentBuilder* fragBuilder,
859                                  GrGLSLFragmentProcessor::SamplerHandle sampler,
860                                  const char *output,
861                                  const char *profileSize, const char *loc,
862                                  const char *blurred_width,
863                                  const char *sharp_width) {
864     fragBuilder->codeAppendf("float %s;", output);
865     fragBuilder->codeAppendf("{");
866     fragBuilder->codeAppendf("float coord = ((abs(%s - 0.5 * %s) - 0.5 * %s)) / %s;",
867                            loc, blurred_width, sharp_width, profileSize);
868     fragBuilder->codeAppendf("%s = ", output);
869     fragBuilder->appendTextureLookup(sampler, "vec2(coord,0.5)");
870     fragBuilder->codeAppend(".a;");
871     fragBuilder->codeAppendf("}");
872 }
873 
874 
GenKey(const GrProcessor & proc,const GrShaderCaps &,GrProcessorKeyBuilder * b)875 void GrGLRectBlurEffect::GenKey(const GrProcessor& proc, const GrShaderCaps&,
876                                 GrProcessorKeyBuilder* b) {
877     const GrRectBlurEffect& rbe = proc.cast<GrRectBlurEffect>();
878 
879     b->add32(rbe.precision());
880 }
881 
882 
emitCode(EmitArgs & args)883 void GrGLRectBlurEffect::emitCode(EmitArgs& args) {
884     const GrRectBlurEffect& rbe = args.fFp.cast<GrRectBlurEffect>();
885 
886     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
887 
888     const char *rectName;
889     const char *profileSizeName;
890 
891     SkString precisionString;
892     if (args.fShaderCaps->usesPrecisionModifiers()) {
893         precisionString.printf("%s ", GrGLSLPrecisionString(rbe.precision()));
894     }
895     fProxyRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
896                                                    kVec4f_GrSLType,
897                                                    rbe.precision(),
898                                                    "proxyRect",
899                                                    &rectName);
900     fProfileSizeUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
901                                                      kFloat_GrSLType,
902                                                      kDefault_GrSLPrecision,
903                                                      "profileSize",
904                                                      &profileSizeName);
905 
906     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
907 
908     if (args.fInputColor) {
909         fragBuilder->codeAppendf("vec4 src=%s;", args.fInputColor);
910     } else {
911         fragBuilder->codeAppendf("vec4 src=vec4(1);");
912     }
913 
914     fragBuilder->codeAppendf("%s vec2 translatedPos = sk_FragCoord.xy - %s.xy;",
915                              precisionString.c_str(), rectName);
916     fragBuilder->codeAppendf("%s float width = %s.z - %s.x;", precisionString.c_str(), rectName,
917                              rectName);
918     fragBuilder->codeAppendf("%s float height = %s.w - %s.y;", precisionString.c_str(), rectName,
919                              rectName);
920 
921     fragBuilder->codeAppendf("%s vec2 smallDims = vec2(width - %s, height - %s);",
922                              precisionString.c_str(), profileSizeName, profileSizeName);
923     fragBuilder->codeAppendf("%s float center = 2.0 * floor(%s/2.0 + .25) - 1.0;",
924                              precisionString.c_str(), profileSizeName);
925     fragBuilder->codeAppendf("%s vec2 wh = smallDims - vec2(center,center);",
926                              precisionString.c_str());
927 
928     OutputRectBlurProfileLookup(fragBuilder, args.fTexSamplers[0], "horiz_lookup", profileSizeName,
929                                 "translatedPos.x", "width", "wh.x");
930     OutputRectBlurProfileLookup(fragBuilder, args.fTexSamplers[0], "vert_lookup", profileSizeName,
931                                 "translatedPos.y", "height", "wh.y");
932 
933     fragBuilder->codeAppendf("float final = horiz_lookup * vert_lookup;");
934     fragBuilder->codeAppendf("%s = src * final;", args.fOutputColor);
935 }
936 
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & proc)937 void GrGLRectBlurEffect::onSetData(const GrGLSLProgramDataManager& pdman,
938                                    const GrProcessor& proc) {
939     const GrRectBlurEffect& rbe = proc.cast<GrRectBlurEffect>();
940     SkRect rect = rbe.getRect();
941 
942     pdman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
943     pdman.set1f(fProfileSizeUniform, SkScalarCeilToScalar(6*rbe.getSigma()));
944 }
945 
CreateBlurProfileTexture(GrResourceProvider * resourceProvider,float sigma)946 sk_sp<GrTextureProxy> GrRectBlurEffect::CreateBlurProfileTexture(
947                                                             GrResourceProvider* resourceProvider,
948                                                             float sigma) {
949     GrSurfaceDesc texDesc;
950 
951     unsigned int profileSize = SkScalarCeilToInt(6*sigma);
952 
953     texDesc.fWidth = profileSize;
954     texDesc.fHeight = 1;
955     texDesc.fConfig = kAlpha_8_GrPixelConfig;
956     texDesc.fIsMipMapped = false;
957 
958     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
959     GrUniqueKey key;
960     GrUniqueKey::Builder builder(&key, kDomain, 1);
961     builder[0] = profileSize;
962     builder.finish();
963 
964     sk_sp<GrTextureProxy> blurProfile(resourceProvider->findProxyByUniqueKey(key));
965     if (!blurProfile) {
966         std::unique_ptr<uint8_t[]> profile(SkBlurMask::ComputeBlurProfile(sigma));
967 
968         blurProfile = GrSurfaceProxy::MakeDeferred(resourceProvider,
969                                                    texDesc, SkBudgeted::kYes, profile.get(), 0);
970         if (!blurProfile) {
971             return nullptr;
972         }
973 
974         resourceProvider->assignUniqueKeyToProxy(key, blurProfile.get());
975     }
976 
977     return blurProfile;
978 }
979 
GrRectBlurEffect(GrResourceProvider * resourceProvider,const SkRect & rect,float sigma,sk_sp<GrTextureProxy> blurProfile,GrSLPrecision precision)980 GrRectBlurEffect::GrRectBlurEffect(GrResourceProvider* resourceProvider,
981                                    const SkRect& rect, float sigma,
982                                    sk_sp<GrTextureProxy> blurProfile,
983                                    GrSLPrecision precision)
984         : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag)
985         , fRect(rect)
986         , fSigma(sigma)
987         , fBlurProfileSampler(resourceProvider, std::move(blurProfile))
988         , fPrecision(precision) {
989     this->initClassID<GrRectBlurEffect>();
990     this->addTextureSampler(&fBlurProfileSampler);
991 }
992 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const993 void GrRectBlurEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
994                                              GrProcessorKeyBuilder* b) const {
995     GrGLRectBlurEffect::GenKey(*this, caps, b);
996 }
997 
onCreateGLSLInstance() const998 GrGLSLFragmentProcessor* GrRectBlurEffect::onCreateGLSLInstance() const {
999     return new GrGLRectBlurEffect;
1000 }
1001 
onIsEqual(const GrFragmentProcessor & sBase) const1002 bool GrRectBlurEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
1003     const GrRectBlurEffect& s = sBase.cast<GrRectBlurEffect>();
1004     return this->getSigma() == s.getSigma() && this->getRect() == s.getRect();
1005 }
1006 
1007 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRectBlurEffect);
1008 
1009 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)1010 sk_sp<GrFragmentProcessor> GrRectBlurEffect::TestCreate(GrProcessorTestData* d) {
1011     float sigma = d->fRandom->nextRangeF(3,8);
1012     float width = d->fRandom->nextRangeF(200,300);
1013     float height = d->fRandom->nextRangeF(200,300);
1014     return GrRectBlurEffect::Make(d->resourceProvider(),
1015                                   SkRect::MakeWH(width, height), sigma);
1016 }
1017 #endif
1018 
directFilterMaskGPU(GrContext * context,GrRenderTargetContext * renderTargetContext,GrPaint && paint,const GrClip & clip,const SkMatrix & viewMatrix,const SkStrokeRec & strokeRec,const SkPath & path) const1019 bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext* context,
1020                                                GrRenderTargetContext* renderTargetContext,
1021                                                GrPaint&& paint,
1022                                                const GrClip& clip,
1023                                                const SkMatrix& viewMatrix,
1024                                                const SkStrokeRec& strokeRec,
1025                                                const SkPath& path) const {
1026     SkASSERT(renderTargetContext);
1027 
1028     if (fBlurStyle != kNormal_SkBlurStyle) {
1029         return false;
1030     }
1031 
1032     // TODO: we could handle blurred stroked circles
1033     if (!strokeRec.isFillStyle()) {
1034         return false;
1035     }
1036 
1037     SkScalar xformedSigma = this->computeXformedSigma(viewMatrix);
1038 
1039     GrResourceProvider* resourceProvider = renderTargetContext->resourceProvider();
1040     sk_sp<GrFragmentProcessor> fp;
1041 
1042     SkRect rect;
1043     if (path.isRect(&rect)) {
1044         SkScalar pad = 3.0f * xformedSigma;
1045         rect.outset(pad, pad);
1046 
1047         fp = GrRectBlurEffect::Make(resourceProvider, rect, xformedSigma);
1048     } else if (path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height())) {
1049         fp = GrCircleBlurFragmentProcessor::Make(resourceProvider, rect, xformedSigma);
1050 
1051         // expand the rect for the coverage geometry
1052         int pad = SkScalarCeilToInt(6*xformedSigma)/2;
1053         rect.outset(SkIntToScalar(pad), SkIntToScalar(pad));
1054     } else {
1055         return false;
1056     }
1057 
1058     if (!fp) {
1059         return false;
1060     }
1061 
1062     SkMatrix inverse;
1063     if (!viewMatrix.invert(&inverse)) {
1064         return false;
1065     }
1066 
1067     paint.addCoverageFragmentProcessor(std::move(fp));
1068     renderTargetContext->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(),
1069                                                  rect, inverse);
1070     return true;
1071 }
1072 
1073 //////////////////////////////////////////////////////////////////////////////
1074 
1075 class GrRRectBlurEffect : public GrFragmentProcessor {
1076 public:
1077 
1078     static sk_sp<GrFragmentProcessor> Make(GrContext*,
1079                                            float sigma, float xformedSigma,
1080                                            const SkRRect& srcRRect, const SkRRect& devRRect);
1081 
~GrRRectBlurEffect()1082     ~GrRRectBlurEffect() override {}
name() const1083     const char* name() const override { return "GrRRectBlur"; }
1084 
getRRect() const1085     const SkRRect& getRRect() const { return fRRect; }
getSigma() const1086     float getSigma() const { return fSigma; }
1087 
1088 private:
1089     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
1090 
1091     GrRRectBlurEffect(GrResourceProvider*, float sigma, const SkRRect&,
1092                       sk_sp<GrTextureProxy> profileProxy);
1093 
1094     virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
1095                                        GrProcessorKeyBuilder* b) const override;
1096 
1097     bool onIsEqual(const GrFragmentProcessor& other) const override;
1098 
1099     SkRRect             fRRect;
1100     float               fSigma;
1101     TextureSampler      fNinePatchSampler;
1102 
1103     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
1104 
1105     typedef GrFragmentProcessor INHERITED;
1106 };
1107 
find_or_create_rrect_blur_mask(GrContext * context,const SkRRect & rrectToDraw,const SkISize & size,float xformedSigma)1108 static sk_sp<GrTextureProxy> find_or_create_rrect_blur_mask(GrContext* context,
1109                                                             const SkRRect& rrectToDraw,
1110                                                             const SkISize& size,
1111                                                             float xformedSigma) {
1112     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
1113     GrUniqueKey key;
1114     GrUniqueKey::Builder builder(&key, kDomain, 9);
1115     builder[0] = SkScalarCeilToInt(xformedSigma-1/6.0f);
1116 
1117     int index = 1;
1118     for (auto c : { SkRRect::kUpperLeft_Corner,  SkRRect::kUpperRight_Corner,
1119                     SkRRect::kLowerRight_Corner, SkRRect::kLowerLeft_Corner }) {
1120         SkASSERT(SkScalarIsInt(rrectToDraw.radii(c).fX) && SkScalarIsInt(rrectToDraw.radii(c).fY));
1121         builder[index++] = SkScalarCeilToInt(rrectToDraw.radii(c).fX);
1122         builder[index++] = SkScalarCeilToInt(rrectToDraw.radii(c).fY);
1123     }
1124     builder.finish();
1125 
1126     sk_sp<GrTextureProxy> mask(context->resourceProvider()->findProxyByUniqueKey(key));
1127     if (!mask) {
1128         // TODO: this could be approx but the texture coords will need to be updated
1129         sk_sp<GrRenderTargetContext> rtc(context->makeDeferredRenderTargetContextWithFallback(
1130             SkBackingFit::kExact, size.fWidth, size.fHeight, kAlpha_8_GrPixelConfig, nullptr));
1131         if (!rtc) {
1132             return nullptr;
1133         }
1134 
1135         GrPaint paint;
1136 
1137         rtc->clear(nullptr, 0x0, true);
1138         rtc->drawRRect(GrNoClip(), std::move(paint), GrAA::kYes, SkMatrix::I(), rrectToDraw,
1139                        GrStyle::SimpleFill());
1140 
1141         sk_sp<GrTextureProxy> srcProxy(rtc->asTextureProxyRef());
1142         if (!srcProxy) {
1143             return nullptr;
1144         }
1145         sk_sp<GrRenderTargetContext> rtc2(SkGpuBlurUtils::GaussianBlur(context,
1146                                                                        std::move(srcProxy),
1147                                                                        nullptr,
1148                                                                        SkIRect::MakeWH(
1149                                                                                     size.fWidth,
1150                                                                                     size.fHeight),
1151                                                                        nullptr,
1152                                                                        xformedSigma, xformedSigma,
1153                                                                        SkBackingFit::kExact));
1154         if (!rtc2) {
1155             return nullptr;
1156         }
1157 
1158         mask = rtc2->asTextureProxyRef();
1159         if (!mask) {
1160             return nullptr;
1161         }
1162         context->resourceProvider()->assignUniqueKeyToProxy(key, mask.get());
1163     }
1164 
1165     return mask;
1166 }
1167 
Make(GrContext * context,float sigma,float xformedSigma,const SkRRect & srcRRect,const SkRRect & devRRect)1168 sk_sp<GrFragmentProcessor> GrRRectBlurEffect::Make(GrContext* context,
1169                                                    float sigma, float xformedSigma,
1170                                                    const SkRRect& srcRRect, const SkRRect& devRRect) {
1171     SkASSERT(!devRRect.isCircle() && !devRRect.isRect()); // Should've been caught up-stream
1172 
1173     // TODO: loosen this up
1174     if (!devRRect.isSimpleCircular()) {
1175         return nullptr;
1176     }
1177 
1178     // Make sure we can successfully ninepatch this rrect -- the blur sigma has to be
1179     // sufficiently small relative to both the size of the corner radius and the
1180     // width (and height) of the rrect.
1181     SkRRect rrectToDraw;
1182     SkISize size;
1183     SkScalar ignored[SkBlurMaskFilter::kMaxDivisions];
1184     int ignoredSize;
1185     uint32_t ignored32;
1186 
1187     bool ninePatchable = SkBlurMaskFilter::ComputeBlurredRRectParams(srcRRect, devRRect,
1188                                                                      SkRect::MakeEmpty(),
1189                                                                      sigma, xformedSigma,
1190                                                                      &rrectToDraw, &size,
1191                                                                      ignored, ignored,
1192                                                                      ignored, ignored,
1193                                                                      &ignoredSize, &ignoredSize,
1194                                                                      &ignored32);
1195     if (!ninePatchable) {
1196         return nullptr;
1197     }
1198 
1199     sk_sp<GrTextureProxy> mask(find_or_create_rrect_blur_mask(context, rrectToDraw,
1200                                                               size, xformedSigma));
1201     if (!mask) {
1202         return nullptr;
1203     }
1204 
1205     return sk_sp<GrFragmentProcessor>(new GrRRectBlurEffect(context->resourceProvider(),
1206                                                             xformedSigma,
1207                                                             devRRect,
1208                                                             std::move(mask)));
1209 }
1210 
GrRRectBlurEffect(GrResourceProvider * resourceProvider,float sigma,const SkRRect & rrect,sk_sp<GrTextureProxy> ninePatchProxy)1211 GrRRectBlurEffect::GrRRectBlurEffect(GrResourceProvider* resourceProvider,
1212                                      float sigma, const SkRRect& rrect,
1213                                      sk_sp<GrTextureProxy> ninePatchProxy)
1214         : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag)
1215         , fRRect(rrect)
1216         , fSigma(sigma)
1217         , fNinePatchSampler(resourceProvider, std::move(ninePatchProxy)) {
1218     this->initClassID<GrRRectBlurEffect>();
1219     this->addTextureSampler(&fNinePatchSampler);
1220 }
1221 
onIsEqual(const GrFragmentProcessor & other) const1222 bool GrRRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const {
1223     const GrRRectBlurEffect& rrbe = other.cast<GrRRectBlurEffect>();
1224     return fRRect.getSimpleRadii().fX == rrbe.fRRect.getSimpleRadii().fX &&
1225            fSigma == rrbe.fSigma &&
1226            fRRect.rect() == rrbe.fRRect.rect();
1227 }
1228 
1229 //////////////////////////////////////////////////////////////////////////////
1230 
1231 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRRectBlurEffect);
1232 
1233 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)1234 sk_sp<GrFragmentProcessor> GrRRectBlurEffect::TestCreate(GrProcessorTestData* d) {
1235     SkScalar w = d->fRandom->nextRangeScalar(100.f, 1000.f);
1236     SkScalar h = d->fRandom->nextRangeScalar(100.f, 1000.f);
1237     SkScalar r = d->fRandom->nextRangeF(1.f, 9.f);
1238     SkScalar sigma = d->fRandom->nextRangeF(1.f,10.f);
1239     SkRRect rrect;
1240     rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
1241     return GrRRectBlurEffect::Make(d->context(), sigma, sigma, rrect, rrect);
1242 }
1243 #endif
1244 
1245 //////////////////////////////////////////////////////////////////////////////
1246 
1247 class GrGLRRectBlurEffect : public GrGLSLFragmentProcessor {
1248 public:
1249     void emitCode(EmitArgs&) override;
1250 
1251 protected:
1252     void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
1253 
1254 private:
1255     GrGLSLProgramDataManager::UniformHandle fProxyRectUniform;
1256     GrGLSLProgramDataManager::UniformHandle fCornerRadiusUniform;
1257     GrGLSLProgramDataManager::UniformHandle fBlurRadiusUniform;
1258     typedef GrGLSLFragmentProcessor INHERITED;
1259 };
1260 
emitCode(EmitArgs & args)1261 void GrGLRRectBlurEffect::emitCode(EmitArgs& args) {
1262     const char *rectName;
1263     const char *cornerRadiusName;
1264     const char *blurRadiusName;
1265 
1266     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1267     // The proxy rect has left, top, right, and bottom edges correspond to
1268     // components x, y, z, and w, respectively.
1269 
1270     fProxyRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
1271                                                    kVec4f_GrSLType,
1272                                                    kDefault_GrSLPrecision,
1273                                                    "proxyRect",
1274                                                    &rectName);
1275     fCornerRadiusUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
1276                                                       kFloat_GrSLType,
1277                                                       kDefault_GrSLPrecision,
1278                                                       "cornerRadius",
1279                                                       &cornerRadiusName);
1280     fBlurRadiusUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
1281                                                     kFloat_GrSLType,
1282                                                     kDefault_GrSLPrecision,
1283                                                     "blurRadius",
1284                                                     &blurRadiusName);
1285 
1286     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
1287 
1288     // warp the fragment position to the appropriate part of the 9patch blur texture
1289 
1290     fragBuilder->codeAppendf("vec2 rectCenter = (%s.xy + %s.zw)/2.0;", rectName, rectName);
1291     fragBuilder->codeAppendf("vec2 translatedFragPos = sk_FragCoord.xy - %s.xy;", rectName);
1292     fragBuilder->codeAppendf("float threshold = %s + 2.0*%s;", cornerRadiusName, blurRadiusName);
1293     fragBuilder->codeAppendf("vec2 middle = %s.zw - %s.xy - 2.0*threshold;", rectName, rectName);
1294 
1295     fragBuilder->codeAppendf(
1296            "if (translatedFragPos.x >= threshold && translatedFragPos.x < (middle.x+threshold)) {");
1297     fragBuilder->codeAppendf("translatedFragPos.x = threshold;\n");
1298     fragBuilder->codeAppendf("} else if (translatedFragPos.x >= (middle.x + threshold)) {");
1299     fragBuilder->codeAppendf("translatedFragPos.x -= middle.x - 1.0;");
1300     fragBuilder->codeAppendf("}");
1301 
1302     fragBuilder->codeAppendf(
1303             "if (translatedFragPos.y > threshold && translatedFragPos.y < (middle.y+threshold)) {");
1304     fragBuilder->codeAppendf("translatedFragPos.y = threshold;");
1305     fragBuilder->codeAppendf("} else if (translatedFragPos.y >= (middle.y + threshold)) {");
1306     fragBuilder->codeAppendf("translatedFragPos.y -= middle.y - 1.0;");
1307     fragBuilder->codeAppendf("}");
1308 
1309     fragBuilder->codeAppendf("vec2 proxyDims = vec2(2.0*threshold+1.0);");
1310     fragBuilder->codeAppendf("vec2 texCoord = translatedFragPos / proxyDims;");
1311 
1312     fragBuilder->codeAppendf("%s = ", args.fOutputColor);
1313     fragBuilder->appendTextureLookupAndModulate(args.fInputColor, args.fTexSamplers[0], "texCoord");
1314     fragBuilder->codeAppend(";");
1315 }
1316 
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & proc)1317 void GrGLRRectBlurEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1318                                     const GrProcessor& proc) {
1319     const GrRRectBlurEffect& brre = proc.cast<GrRRectBlurEffect>();
1320     const SkRRect& rrect = brre.getRRect();
1321 
1322     float blurRadius = 3.f*SkScalarCeilToScalar(brre.getSigma()-1/6.0f);
1323     pdman.set1f(fBlurRadiusUniform, blurRadius);
1324 
1325     SkRect rect = rrect.getBounds();
1326     rect.outset(blurRadius, blurRadius);
1327     pdman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
1328 
1329     SkScalar radius = 0;
1330     SkASSERT(rrect.isSimpleCircular() || rrect.isRect());
1331     radius = rrect.getSimpleRadii().fX;
1332     pdman.set1f(fCornerRadiusUniform, radius);
1333 }
1334 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const1335 void GrRRectBlurEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
1336                                               GrProcessorKeyBuilder* b) const {
1337     GrGLRRectBlurEffect::GenKey(*this, caps, b);
1338 }
1339 
onCreateGLSLInstance() const1340 GrGLSLFragmentProcessor* GrRRectBlurEffect::onCreateGLSLInstance() const {
1341     return new GrGLRRectBlurEffect;
1342 }
1343 
directFilterRRectMaskGPU(GrContext * context,GrRenderTargetContext * renderTargetContext,GrPaint && paint,const GrClip & clip,const SkMatrix & viewMatrix,const SkStrokeRec & strokeRec,const SkRRect & srcRRect,const SkRRect & devRRect) const1344 bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context,
1345                                                     GrRenderTargetContext* renderTargetContext,
1346                                                     GrPaint&& paint,
1347                                                     const GrClip& clip,
1348                                                     const SkMatrix& viewMatrix,
1349                                                     const SkStrokeRec& strokeRec,
1350                                                     const SkRRect& srcRRect,
1351                                                     const SkRRect& devRRect) const {
1352     SkASSERT(renderTargetContext);
1353 
1354     if (fBlurStyle != kNormal_SkBlurStyle) {
1355         return false;
1356     }
1357 
1358     if (!strokeRec.isFillStyle()) {
1359         return false;
1360     }
1361 
1362     GrResourceProvider* resourceProvider = renderTargetContext->resourceProvider();
1363     SkScalar xformedSigma = this->computeXformedSigma(viewMatrix);
1364 
1365     if (devRRect.isRect() || devRRect.isCircle()) {
1366         if (this->ignoreXform()) {
1367             return false;
1368         }
1369 
1370         sk_sp<GrFragmentProcessor> fp;
1371         if (devRRect.isRect()) {
1372             SkScalar pad = 3.0f * xformedSigma;
1373             const SkRect dstCoverageRect = devRRect.rect().makeOutset(pad, pad);
1374 
1375             fp = GrRectBlurEffect::Make(resourceProvider, dstCoverageRect, xformedSigma);
1376         } else {
1377             fp = GrCircleBlurFragmentProcessor::Make(resourceProvider,
1378                                                      devRRect.rect(), xformedSigma);
1379         }
1380 
1381         if (!fp) {
1382             return false;
1383         }
1384 
1385         paint.addCoverageFragmentProcessor(std::move(fp));
1386 
1387         SkRect srcProxyRect = srcRRect.rect();
1388         srcProxyRect.outset(3.0f*fSigma, 3.0f*fSigma);
1389 
1390         renderTargetContext->drawRect(clip, std::move(paint), GrAA::kNo, viewMatrix, srcProxyRect);
1391         return true;
1392     }
1393 
1394     sk_sp<GrFragmentProcessor> fp(GrRRectBlurEffect::Make(context, fSigma, xformedSigma,
1395                                                           srcRRect, devRRect));
1396     if (!fp) {
1397         return false;
1398     }
1399 
1400     if (!this->ignoreXform()) {
1401         SkRect srcProxyRect = srcRRect.rect();
1402         srcProxyRect.outset(3.0f*fSigma, 3.0f*fSigma);
1403 
1404         SkPoint points[8];
1405         uint16_t indices[24];
1406         int numPoints, numIndices;
1407 
1408         SkRect temp = fOccluder;
1409 
1410         if (!temp.isEmpty() && (srcProxyRect.contains(temp) || temp.intersect(srcProxyRect))) {
1411             srcProxyRect.toQuad(points);
1412             temp.toQuad(&points[4]);
1413             numPoints = 8;
1414 
1415             static const uint16_t ringI[24] = { 0, 1, 5, 5, 4, 0,
1416                                                 1, 2, 6, 6, 5, 1,
1417                                                 2, 3, 7, 7, 6, 2,
1418                                                 3, 0, 4, 4, 7, 3 };
1419             memcpy(indices, ringI, sizeof(ringI));
1420             numIndices = 24;
1421         } else {
1422             // full rect case
1423             srcProxyRect.toQuad(points);
1424             numPoints = 4;
1425 
1426             static const uint16_t fullI[6] = { 0, 1, 2, 0, 2, 3 };
1427             memcpy(indices, fullI, sizeof(fullI));
1428             numIndices = 6;
1429         }
1430 
1431         paint.addCoverageFragmentProcessor(std::move(fp));
1432         renderTargetContext->drawVertices(clip, std::move(paint), viewMatrix,
1433                                           kTriangles_GrPrimitiveType, numPoints, points, nullptr,
1434                                           nullptr, indices, numIndices);
1435 
1436     } else {
1437         SkMatrix inverse;
1438         if (!viewMatrix.invert(&inverse)) {
1439             return false;
1440         }
1441 
1442         float extra=3.f*SkScalarCeilToScalar(xformedSigma-1/6.0f);
1443         SkRect proxyRect = devRRect.rect();
1444         proxyRect.outset(extra, extra);
1445 
1446         paint.addCoverageFragmentProcessor(std::move(fp));
1447         renderTargetContext->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo,
1448                                                      SkMatrix::I(), proxyRect, inverse);
1449     }
1450 
1451     return true;
1452 }
1453 
canFilterMaskGPU(const SkRRect & devRRect,const SkIRect & clipBounds,const SkMatrix & ctm,SkRect * maskRect) const1454 bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRRect& devRRect,
1455                                             const SkIRect& clipBounds,
1456                                             const SkMatrix& ctm,
1457                                             SkRect* maskRect) const {
1458     SkScalar xformedSigma = this->computeXformedSigma(ctm);
1459     if (xformedSigma <= 0) {
1460         return false;
1461     }
1462 
1463     // We always do circles and simple circular rrects on the GPU
1464     if (!devRRect.isCircle() && !devRRect.isSimpleCircular()) {
1465         static const SkScalar kMIN_GPU_BLUR_SIZE  = SkIntToScalar(64);
1466         static const SkScalar kMIN_GPU_BLUR_SIGMA = SkIntToScalar(32);
1467 
1468         if (devRRect.width() <= kMIN_GPU_BLUR_SIZE &&
1469             devRRect.height() <= kMIN_GPU_BLUR_SIZE &&
1470             xformedSigma <= kMIN_GPU_BLUR_SIGMA) {
1471             // We prefer to blur small rects with small radii on the CPU.
1472             return false;
1473         }
1474     }
1475 
1476     if (nullptr == maskRect) {
1477         // don't need to compute maskRect
1478         return true;
1479     }
1480 
1481     float sigma3 = 3 * SkScalarToFloat(xformedSigma);
1482 
1483     SkRect clipRect = SkRect::Make(clipBounds);
1484     SkRect srcRect(devRRect.rect());
1485 
1486     // Outset srcRect and clipRect by 3 * sigma, to compute affected blur area.
1487     srcRect.outset(sigma3, sigma3);
1488     clipRect.outset(sigma3, sigma3);
1489     if (!srcRect.intersect(clipRect)) {
1490         srcRect.setEmpty();
1491     }
1492     *maskRect = srcRect;
1493     return true;
1494 }
1495 
filterMaskGPU(GrContext * context,sk_sp<GrTextureProxy> srcProxy,const SkMatrix & ctm,const SkIRect & maskRect) const1496 sk_sp<GrTextureProxy> SkBlurMaskFilterImpl::filterMaskGPU(GrContext* context,
1497                                                           sk_sp<GrTextureProxy> srcProxy,
1498                                                           const SkMatrix& ctm,
1499                                                           const SkIRect& maskRect) const {
1500     // 'maskRect' isn't snapped to the UL corner but the mask in 'src' is.
1501     const SkIRect clipRect = SkIRect::MakeWH(maskRect.width(), maskRect.height());
1502 
1503     SkScalar xformedSigma = this->computeXformedSigma(ctm);
1504     SkASSERT(xformedSigma > 0);
1505 
1506     // If we're doing a normal blur, we can clobber the pathTexture in the
1507     // gaussianBlur.  Otherwise, we need to save it for later compositing.
1508     bool isNormalBlur = (kNormal_SkBlurStyle == fBlurStyle);
1509     sk_sp<GrRenderTargetContext> renderTargetContext(SkGpuBlurUtils::GaussianBlur(context,
1510                                                                                   srcProxy,
1511                                                                                   nullptr, clipRect,
1512                                                                                   nullptr,
1513                                                                                   xformedSigma,
1514                                                                                   xformedSigma));
1515     if (!renderTargetContext) {
1516         return nullptr;
1517     }
1518 
1519     if (!isNormalBlur) {
1520         GrPaint paint;
1521         // Blend pathTexture over blurTexture.
1522         paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(context->resourceProvider(),
1523                                                                        std::move(srcProxy),
1524                                                                        nullptr, SkMatrix::I()));
1525         if (kInner_SkBlurStyle == fBlurStyle) {
1526             // inner:  dst = dst * src
1527             paint.setCoverageSetOpXPFactory(SkRegion::kIntersect_Op);
1528         } else if (kSolid_SkBlurStyle == fBlurStyle) {
1529             // solid:  dst = src + dst - src * dst
1530             //             = src + (1 - src) * dst
1531             paint.setCoverageSetOpXPFactory(SkRegion::kUnion_Op);
1532         } else if (kOuter_SkBlurStyle == fBlurStyle) {
1533             // outer:  dst = dst * (1 - src)
1534             //             = 0 * src + (1 - src) * dst
1535             paint.setCoverageSetOpXPFactory(SkRegion::kDifference_Op);
1536         } else {
1537             paint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op);
1538         }
1539 
1540         renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
1541                                       SkRect::Make(clipRect));
1542     }
1543 
1544     return renderTargetContext->asTextureProxyRef();
1545 }
1546 
1547 #endif // SK_SUPPORT_GPU
1548 
1549 
1550 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const1551 void SkBlurMaskFilterImpl::toString(SkString* str) const {
1552     str->append("SkBlurMaskFilterImpl: (");
1553 
1554     str->append("sigma: ");
1555     str->appendScalar(fSigma);
1556     str->append(" ");
1557 
1558     static const char* gStyleName[kLastEnum_SkBlurStyle + 1] = {
1559         "normal", "solid", "outer", "inner"
1560     };
1561 
1562     str->appendf("style: %s ", gStyleName[fBlurStyle]);
1563     str->append("flags: (");
1564     if (fBlurFlags) {
1565         bool needSeparator = false;
1566         SkAddFlagToString(str, this->ignoreXform(), "IgnoreXform", &needSeparator);
1567         SkAddFlagToString(str,
1568                           SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag),
1569                           "HighQuality", &needSeparator);
1570     } else {
1571         str->append("None");
1572     }
1573     str->append("))");
1574 }
1575 #endif
1576 
1577 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
1578     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
1579 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
1580