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