• 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 "SkRTConf.h"
16 #include "SkStringUtils.h"
17 #include "SkStrokeRec.h"
18 
19 #if SK_SUPPORT_GPU
20 #include "GrCircleBlurFragmentProcessor.h"
21 #include "GrContext.h"
22 #include "GrDrawContext.h"
23 #include "GrTexture.h"
24 #include "GrFragmentProcessor.h"
25 #include "GrInvariantOutput.h"
26 #include "SkDraw.h"
27 #include "effects/GrSimpleTextureEffect.h"
28 #include "glsl/GrGLSLFragmentProcessor.h"
29 #include "glsl/GrGLSLFragmentShaderBuilder.h"
30 #include "glsl/GrGLSLProgramDataManager.h"
31 #include "glsl/GrGLSLTextureSampler.h"
32 #include "glsl/GrGLSLUniformHandler.h"
33 #endif
34 
ConvertRadiusToSigma(SkScalar radius)35 SkScalar SkBlurMaskFilter::ConvertRadiusToSigma(SkScalar radius) {
36     return SkBlurMask::ConvertRadiusToSigma(radius);
37 }
38 
39 class SkBlurMaskFilterImpl : public SkMaskFilter {
40 public:
41     SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle, uint32_t flags);
42 
43     // overrides from SkMaskFilter
44     SkMask::Format getFormat() const override;
45     bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
46                     SkIPoint* margin) const override;
47 
48 #if SK_SUPPORT_GPU
49     bool canFilterMaskGPU(const SkRRect& devRRect,
50                           const SkIRect& clipBounds,
51                           const SkMatrix& ctm,
52                           SkRect* maskRect) const override;
53     bool directFilterMaskGPU(GrTextureProvider* texProvider,
54                              GrDrawContext* drawContext,
55                              GrPaint* grp,
56                              const GrClip&,
57                              const SkMatrix& viewMatrix,
58                              const SkStrokeRec& strokeRec,
59                              const SkPath& path) const override;
60     bool directFilterRRectMaskGPU(GrTextureProvider* texProvider,
61                                   GrDrawContext* drawContext,
62                                   GrPaint* grp,
63                                   const GrClip&,
64                                   const SkMatrix& viewMatrix,
65                                   const SkStrokeRec& strokeRec,
66                                   const SkRRect& rrect) const override;
67     bool filterMaskGPU(GrTexture* src,
68                        const SkMatrix& ctm,
69                        const SkRect& maskRect,
70                        GrTexture** result,
71                        bool canOverwriteSrc) const override;
72 #endif
73 
74     void computeFastBounds(const SkRect&, SkRect*) const override;
75     bool asABlur(BlurRec*) const override;
76 
77     SK_TO_STRING_OVERRIDE()
78     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)
79 
80 protected:
81     FilterReturn filterRectsToNine(const SkRect[], int count, const SkMatrix&,
82                                    const SkIRect& clipBounds,
83                                    NinePatch*) const override;
84 
85     FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&,
86                                    const SkIRect& clipBounds,
87                                    NinePatch*) const override;
88 
89     bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix,
90                         SkIPoint* margin, SkMask::CreateMode createMode) const;
91     bool filterRRectMask(SkMask* dstM, const SkRRect& r, const SkMatrix& matrix,
92                         SkIPoint* margin, SkMask::CreateMode createMode) const;
93 
94 private:
95     // To avoid unseemly allocation requests (esp. for finite platforms like
96     // handset) we limit the radius so something manageable. (as opposed to
97     // a request like 10,000)
98     static const SkScalar kMAX_BLUR_SIGMA;
99 
100     SkScalar    fSigma;
101     SkBlurStyle fBlurStyle;
102     uint32_t    fBlurFlags;
103 
getQuality() const104     SkBlurQuality getQuality() const {
105         return (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
106                 kHigh_SkBlurQuality : kLow_SkBlurQuality;
107     }
108 
109     SkBlurMaskFilterImpl(SkReadBuffer&);
110     void flatten(SkWriteBuffer&) const override;
111 
computeXformedSigma(const SkMatrix & ctm) const112     SkScalar computeXformedSigma(const SkMatrix& ctm) const {
113         bool ignoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
114 
115         SkScalar xformedSigma = ignoreTransform ? fSigma : ctm.mapRadius(fSigma);
116         return SkMinScalar(xformedSigma, kMAX_BLUR_SIGMA);
117     }
118 
119     friend class SkBlurMaskFilter;
120 
121     typedef SkMaskFilter INHERITED;
122 };
123 
124 const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_SIGMA = SkIntToScalar(128);
125 
Create(SkBlurStyle style,SkScalar sigma,uint32_t flags)126 SkMaskFilter* SkBlurMaskFilter::Create(SkBlurStyle style, SkScalar sigma, uint32_t flags) {
127     if (!SkScalarIsFinite(sigma) || sigma <= 0) {
128         return nullptr;
129     }
130     if ((unsigned)style > (unsigned)kLastEnum_SkBlurStyle) {
131         return nullptr;
132     }
133     if (flags > SkBlurMaskFilter::kAll_BlurFlag) {
134         return nullptr;
135     }
136     return new SkBlurMaskFilterImpl(sigma, style, flags);
137 }
138 
139 ///////////////////////////////////////////////////////////////////////////////
140 
SkBlurMaskFilterImpl(SkScalar sigma,SkBlurStyle style,uint32_t flags)141 SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle style, uint32_t flags)
142     : fSigma(sigma)
143     , fBlurStyle(style)
144     , fBlurFlags(flags) {
145     SkASSERT(fSigma > 0);
146     SkASSERT((unsigned)style <= kLastEnum_SkBlurStyle);
147     SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
148 }
149 
getFormat() const150 SkMask::Format SkBlurMaskFilterImpl::getFormat() const {
151     return SkMask::kA8_Format;
152 }
153 
asABlur(BlurRec * rec) const154 bool SkBlurMaskFilterImpl::asABlur(BlurRec* rec) const {
155     if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
156         return false;
157     }
158 
159     if (rec) {
160         rec->fSigma = fSigma;
161         rec->fStyle = fBlurStyle;
162         rec->fQuality = this->getQuality();
163     }
164     return true;
165 }
166 
filterMask(SkMask * dst,const SkMask & src,const SkMatrix & matrix,SkIPoint * margin) const167 bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
168                                       const SkMatrix& matrix,
169                                       SkIPoint* margin) const {
170     SkScalar sigma = this->computeXformedSigma(matrix);
171     return SkBlurMask::BoxBlur(dst, src, sigma, fBlurStyle, this->getQuality(), margin);
172 }
173 
filterRectMask(SkMask * dst,const SkRect & r,const SkMatrix & matrix,SkIPoint * margin,SkMask::CreateMode createMode) const174 bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
175                                           const SkMatrix& matrix,
176                                           SkIPoint* margin, SkMask::CreateMode createMode) const {
177     SkScalar sigma = computeXformedSigma(matrix);
178 
179     return SkBlurMask::BlurRect(sigma, dst, r, fBlurStyle, margin, createMode);
180 }
181 
filterRRectMask(SkMask * dst,const SkRRect & r,const SkMatrix & matrix,SkIPoint * margin,SkMask::CreateMode createMode) const182 bool SkBlurMaskFilterImpl::filterRRectMask(SkMask* dst, const SkRRect& r,
183                                           const SkMatrix& matrix,
184                                           SkIPoint* margin, SkMask::CreateMode createMode) const {
185     SkScalar sigma = computeXformedSigma(matrix);
186 
187     return SkBlurMask::BlurRRect(sigma, dst, r, fBlurStyle, margin, createMode);
188 }
189 
190 #include "SkCanvas.h"
191 
prepare_to_draw_into_mask(const SkRect & bounds,SkMask * mask)192 static bool prepare_to_draw_into_mask(const SkRect& bounds, SkMask* mask) {
193     SkASSERT(mask != nullptr);
194 
195     mask->fBounds = bounds.roundOut();
196     mask->fRowBytes = SkAlign4(mask->fBounds.width());
197     mask->fFormat = SkMask::kA8_Format;
198     const size_t size = mask->computeImageSize();
199     mask->fImage = SkMask::AllocImage(size);
200     if (nullptr == mask->fImage) {
201         return false;
202     }
203 
204     // FIXME: use sk_calloc in AllocImage?
205     sk_bzero(mask->fImage, size);
206     return true;
207 }
208 
draw_rrect_into_mask(const SkRRect rrect,SkMask * mask)209 static bool draw_rrect_into_mask(const SkRRect rrect, SkMask* mask) {
210     if (!prepare_to_draw_into_mask(rrect.rect(), mask)) {
211         return false;
212     }
213 
214     // FIXME: This code duplicates code in draw_rects_into_mask, below. Is there a
215     // clean way to share more code?
216     SkBitmap bitmap;
217     bitmap.installMaskPixels(*mask);
218 
219     SkCanvas canvas(bitmap);
220     canvas.translate(-SkIntToScalar(mask->fBounds.left()),
221                      -SkIntToScalar(mask->fBounds.top()));
222 
223     SkPaint paint;
224     paint.setAntiAlias(true);
225     canvas.drawRRect(rrect, paint);
226     return true;
227 }
228 
draw_rects_into_mask(const SkRect rects[],int count,SkMask * mask)229 static bool draw_rects_into_mask(const SkRect rects[], int count, SkMask* mask) {
230     if (!prepare_to_draw_into_mask(rects[0], mask)) {
231         return false;
232     }
233 
234     SkBitmap bitmap;
235     bitmap.installPixels(SkImageInfo::Make(mask->fBounds.width(),
236                                            mask->fBounds.height(),
237                                            kAlpha_8_SkColorType,
238                                            kPremul_SkAlphaType),
239                          mask->fImage, mask->fRowBytes);
240 
241     SkCanvas canvas(bitmap);
242     canvas.translate(-SkIntToScalar(mask->fBounds.left()),
243                      -SkIntToScalar(mask->fBounds.top()));
244 
245     SkPaint paint;
246     paint.setAntiAlias(true);
247 
248     if (1 == count) {
249         canvas.drawRect(rects[0], paint);
250     } else {
251         // todo: do I need a fast way to do this?
252         SkPath path;
253         path.addRect(rects[0]);
254         path.addRect(rects[1]);
255         path.setFillType(SkPath::kEvenOdd_FillType);
256         canvas.drawPath(path, paint);
257     }
258     return true;
259 }
260 
rect_exceeds(const SkRect & r,SkScalar v)261 static bool rect_exceeds(const SkRect& r, SkScalar v) {
262     return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v ||
263            r.width() > v || r.height() > v;
264 }
265 
266 #include "SkMaskCache.h"
267 
copy_mask_to_cacheddata(SkMask * mask)268 static SkCachedData* copy_mask_to_cacheddata(SkMask* mask) {
269     const size_t size = mask->computeTotalImageSize();
270     SkCachedData* data = SkResourceCache::NewCachedData(size);
271     if (data) {
272         memcpy(data->writable_data(), mask->fImage, size);
273         SkMask::FreeImage(mask->fImage);
274         mask->fImage = (uint8_t*)data->data();
275     }
276     return data;
277 }
278 
find_cached_rrect(SkMask * mask,SkScalar sigma,SkBlurStyle style,SkBlurQuality quality,const SkRRect & rrect)279 static SkCachedData* find_cached_rrect(SkMask* mask, SkScalar sigma, SkBlurStyle style,
280                                        SkBlurQuality quality, const SkRRect& rrect) {
281     return SkMaskCache::FindAndRef(sigma, style, quality, rrect, mask);
282 }
283 
add_cached_rrect(SkMask * mask,SkScalar sigma,SkBlurStyle style,SkBlurQuality quality,const SkRRect & rrect)284 static SkCachedData* add_cached_rrect(SkMask* mask, SkScalar sigma, SkBlurStyle style,
285                                       SkBlurQuality quality, const SkRRect& rrect) {
286     SkCachedData* cache = copy_mask_to_cacheddata(mask);
287     if (cache) {
288         SkMaskCache::Add(sigma, style, quality, rrect, *mask, cache);
289     }
290     return cache;
291 }
292 
find_cached_rects(SkMask * mask,SkScalar sigma,SkBlurStyle style,SkBlurQuality quality,const SkRect rects[],int count)293 static SkCachedData* find_cached_rects(SkMask* mask, SkScalar sigma, SkBlurStyle style,
294                                        SkBlurQuality quality, const SkRect rects[], int count) {
295     return SkMaskCache::FindAndRef(sigma, style, quality, rects, count, mask);
296 }
297 
add_cached_rects(SkMask * mask,SkScalar sigma,SkBlurStyle style,SkBlurQuality quality,const SkRect rects[],int count)298 static SkCachedData* add_cached_rects(SkMask* mask, SkScalar sigma, SkBlurStyle style,
299                                       SkBlurQuality quality, const SkRect rects[], int count) {
300     SkCachedData* cache = copy_mask_to_cacheddata(mask);
301     if (cache) {
302         SkMaskCache::Add(sigma, style, quality, rects, count, *mask, cache);
303     }
304     return cache;
305 }
306 
307 #ifdef SK_IGNORE_FAST_RRECT_BLUR
308 SK_CONF_DECLARE(bool, c_analyticBlurRRect, "mask.filter.blur.analyticblurrrect", false, "Use the faster analytic blur approach for ninepatch rects");
309 #else
310 SK_CONF_DECLARE(bool, c_analyticBlurRRect, "mask.filter.blur.analyticblurrrect", true, "Use the faster analytic blur approach for ninepatch round rects");
311 #endif
312 
313 SkMaskFilter::FilterReturn
filterRRectToNine(const SkRRect & rrect,const SkMatrix & matrix,const SkIRect & clipBounds,NinePatch * patch) const314 SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& matrix,
315                                         const SkIRect& clipBounds,
316                                         NinePatch* patch) const {
317     SkASSERT(patch != nullptr);
318     switch (rrect.getType()) {
319         case SkRRect::kEmpty_Type:
320             // Nothing to draw.
321             return kFalse_FilterReturn;
322 
323         case SkRRect::kRect_Type:
324             // We should have caught this earlier.
325             SkASSERT(false);
326             // Fall through.
327         case SkRRect::kOval_Type:
328             // The nine patch special case does not handle ovals, and we
329             // already have code for rectangles.
330             return kUnimplemented_FilterReturn;
331 
332         // These three can take advantage of this fast path.
333         case SkRRect::kSimple_Type:
334         case SkRRect::kNinePatch_Type:
335         case SkRRect::kComplex_Type:
336             break;
337     }
338 
339     // TODO: report correct metrics for innerstyle, where we do not grow the
340     // total bounds, but we do need an inset the size of our blur-radius
341     if (kInner_SkBlurStyle == fBlurStyle) {
342         return kUnimplemented_FilterReturn;
343     }
344 
345     // TODO: take clipBounds into account to limit our coordinates up front
346     // for now, just skip too-large src rects (to take the old code path).
347     if (rect_exceeds(rrect.rect(), SkIntToScalar(32767))) {
348         return kUnimplemented_FilterReturn;
349     }
350 
351     SkIPoint margin;
352     SkMask  srcM, dstM;
353     srcM.fBounds = rrect.rect().roundOut();
354     srcM.fFormat = SkMask::kA8_Format;
355     srcM.fRowBytes = 0;
356 
357     bool filterResult = false;
358     if (c_analyticBlurRRect) {
359         // special case for fast round rect blur
360         // don't actually do the blur the first time, just compute the correct size
361         filterResult = this->filterRRectMask(&dstM, rrect, matrix, &margin,
362                                             SkMask::kJustComputeBounds_CreateMode);
363     }
364 
365     if (!filterResult) {
366         filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
367     }
368 
369     if (!filterResult) {
370         return kFalse_FilterReturn;
371     }
372 
373     // Now figure out the appropriate width and height of the smaller round rectangle
374     // to stretch. It will take into account the larger radius per side as well as double
375     // the margin, to account for inner and outer blur.
376     const SkVector& UL = rrect.radii(SkRRect::kUpperLeft_Corner);
377     const SkVector& UR = rrect.radii(SkRRect::kUpperRight_Corner);
378     const SkVector& LR = rrect.radii(SkRRect::kLowerRight_Corner);
379     const SkVector& LL = rrect.radii(SkRRect::kLowerLeft_Corner);
380 
381     const SkScalar leftUnstretched = SkTMax(UL.fX, LL.fX) + SkIntToScalar(2 * margin.fX);
382     const SkScalar rightUnstretched = SkTMax(UR.fX, LR.fX) + SkIntToScalar(2 * margin.fX);
383 
384     // Extra space in the middle to ensure an unchanging piece for stretching. Use 3 to cover
385     // any fractional space on either side plus 1 for the part to stretch.
386     const SkScalar stretchSize = SkIntToScalar(3);
387 
388     const SkScalar totalSmallWidth = leftUnstretched + rightUnstretched + stretchSize;
389     if (totalSmallWidth >= rrect.rect().width()) {
390         // There is no valid piece to stretch.
391         return kUnimplemented_FilterReturn;
392     }
393 
394     const SkScalar topUnstretched = SkTMax(UL.fY, UR.fY) + SkIntToScalar(2 * margin.fY);
395     const SkScalar bottomUnstretched = SkTMax(LL.fY, LR.fY) + SkIntToScalar(2 * margin.fY);
396 
397     const SkScalar totalSmallHeight = topUnstretched + bottomUnstretched + stretchSize;
398     if (totalSmallHeight >= rrect.rect().height()) {
399         // There is no valid piece to stretch.
400         return kUnimplemented_FilterReturn;
401     }
402 
403     SkRect smallR = SkRect::MakeWH(totalSmallWidth, totalSmallHeight);
404 
405     SkRRect smallRR;
406     SkVector radii[4];
407     radii[SkRRect::kUpperLeft_Corner] = UL;
408     radii[SkRRect::kUpperRight_Corner] = UR;
409     radii[SkRRect::kLowerRight_Corner] = LR;
410     radii[SkRRect::kLowerLeft_Corner] = LL;
411     smallRR.setRectRadii(smallR, radii);
412 
413     const SkScalar sigma = this->computeXformedSigma(matrix);
414     SkCachedData* cache = find_cached_rrect(&patch->fMask, sigma, fBlurStyle,
415                                             this->getQuality(), smallRR);
416     if (!cache) {
417         bool analyticBlurWorked = false;
418         if (c_analyticBlurRRect) {
419             analyticBlurWorked =
420                 this->filterRRectMask(&patch->fMask, smallRR, matrix, &margin,
421                                       SkMask::kComputeBoundsAndRenderImage_CreateMode);
422         }
423 
424         if (!analyticBlurWorked) {
425             if (!draw_rrect_into_mask(smallRR, &srcM)) {
426                 return kFalse_FilterReturn;
427             }
428 
429             SkAutoMaskFreeImage amf(srcM.fImage);
430 
431             if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
432                 return kFalse_FilterReturn;
433             }
434         }
435         cache = add_cached_rrect(&patch->fMask, sigma, fBlurStyle, this->getQuality(), smallRR);
436     }
437 
438     patch->fMask.fBounds.offsetTo(0, 0);
439     patch->fOuterRect = dstM.fBounds;
440     patch->fCenter.fX = SkScalarCeilToInt(leftUnstretched) + 1;
441     patch->fCenter.fY = SkScalarCeilToInt(topUnstretched) + 1;
442     SkASSERT(nullptr == patch->fCache);
443     patch->fCache = cache;  // transfer ownership to patch
444     return kTrue_FilterReturn;
445 }
446 
447 SK_CONF_DECLARE(bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", true, "Use the faster analytic blur approach for ninepatch rects");
448 
449 SkMaskFilter::FilterReturn
filterRectsToNine(const SkRect rects[],int count,const SkMatrix & matrix,const SkIRect & clipBounds,NinePatch * patch) const450 SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
451                                         const SkMatrix& matrix,
452                                         const SkIRect& clipBounds,
453                                         NinePatch* patch) const {
454     if (count < 1 || count > 2) {
455         return kUnimplemented_FilterReturn;
456     }
457 
458     // TODO: report correct metrics for innerstyle, where we do not grow the
459     // total bounds, but we do need an inset the size of our blur-radius
460     if (kInner_SkBlurStyle == fBlurStyle || kOuter_SkBlurStyle == fBlurStyle) {
461         return kUnimplemented_FilterReturn;
462     }
463 
464     // TODO: take clipBounds into account to limit our coordinates up front
465     // for now, just skip too-large src rects (to take the old code path).
466     if (rect_exceeds(rects[0], SkIntToScalar(32767))) {
467         return kUnimplemented_FilterReturn;
468     }
469 
470     SkIPoint margin;
471     SkMask  srcM, dstM;
472     srcM.fBounds = rects[0].roundOut();
473     srcM.fFormat = SkMask::kA8_Format;
474     srcM.fRowBytes = 0;
475 
476     bool filterResult = false;
477     if (count == 1 && c_analyticBlurNinepatch) {
478         // special case for fast rect blur
479         // don't actually do the blur the first time, just compute the correct size
480         filterResult = this->filterRectMask(&dstM, rects[0], matrix, &margin,
481                                             SkMask::kJustComputeBounds_CreateMode);
482     } else {
483         filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
484     }
485 
486     if (!filterResult) {
487         return kFalse_FilterReturn;
488     }
489 
490     /*
491      *  smallR is the smallest version of 'rect' that will still guarantee that
492      *  we get the same blur results on all edges, plus 1 center row/col that is
493      *  representative of the extendible/stretchable edges of the ninepatch.
494      *  Since our actual edge may be fractional we inset 1 more to be sure we
495      *  don't miss any interior blur.
496      *  x is an added pixel of blur, and { and } are the (fractional) edge
497      *  pixels from the original rect.
498      *
499      *   x x { x x .... x x } x x
500      *
501      *  Thus, in this case, we inset by a total of 5 (on each side) beginning
502      *  with our outer-rect (dstM.fBounds)
503      */
504     SkRect smallR[2];
505     SkIPoint center;
506 
507     // +2 is from +1 for each edge (to account for possible fractional edges
508     int smallW = dstM.fBounds.width() - srcM.fBounds.width() + 2;
509     int smallH = dstM.fBounds.height() - srcM.fBounds.height() + 2;
510     SkIRect innerIR;
511 
512     if (1 == count) {
513         innerIR = srcM.fBounds;
514         center.set(smallW, smallH);
515     } else {
516         SkASSERT(2 == count);
517         rects[1].roundIn(&innerIR);
518         center.set(smallW + (innerIR.left() - srcM.fBounds.left()),
519                    smallH + (innerIR.top() - srcM.fBounds.top()));
520     }
521 
522     // +1 so we get a clean, stretchable, center row/col
523     smallW += 1;
524     smallH += 1;
525 
526     // we want the inset amounts to be integral, so we don't change any
527     // fractional phase on the fRight or fBottom of our smallR.
528     const SkScalar dx = SkIntToScalar(innerIR.width() - smallW);
529     const SkScalar dy = SkIntToScalar(innerIR.height() - smallH);
530     if (dx < 0 || dy < 0) {
531         // we're too small, relative to our blur, to break into nine-patch,
532         // so we ask to have our normal filterMask() be called.
533         return kUnimplemented_FilterReturn;
534     }
535 
536     smallR[0].set(rects[0].left(), rects[0].top(), rects[0].right() - dx, rects[0].bottom() - dy);
537     if (smallR[0].width() < 2 || smallR[0].height() < 2) {
538         return kUnimplemented_FilterReturn;
539     }
540     if (2 == count) {
541         smallR[1].set(rects[1].left(), rects[1].top(),
542                       rects[1].right() - dx, rects[1].bottom() - dy);
543         SkASSERT(!smallR[1].isEmpty());
544     }
545 
546     const SkScalar sigma = this->computeXformedSigma(matrix);
547     SkCachedData* cache = find_cached_rects(&patch->fMask, sigma, fBlurStyle,
548                                             this->getQuality(), smallR, count);
549     if (!cache) {
550         if (count > 1 || !c_analyticBlurNinepatch) {
551             if (!draw_rects_into_mask(smallR, count, &srcM)) {
552                 return kFalse_FilterReturn;
553             }
554 
555             SkAutoMaskFreeImage amf(srcM.fImage);
556 
557             if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
558                 return kFalse_FilterReturn;
559             }
560         } else {
561             if (!this->filterRectMask(&patch->fMask, smallR[0], matrix, &margin,
562                                       SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
563                 return kFalse_FilterReturn;
564             }
565         }
566         cache = add_cached_rects(&patch->fMask, sigma, fBlurStyle, this->getQuality(), smallR, count);
567     }
568     patch->fMask.fBounds.offsetTo(0, 0);
569     patch->fOuterRect = dstM.fBounds;
570     patch->fCenter = center;
571     SkASSERT(nullptr == patch->fCache);
572     patch->fCache = cache;  // transfer ownership to patch
573     return kTrue_FilterReturn;
574 }
575 
computeFastBounds(const SkRect & src,SkRect * dst) const576 void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
577                                              SkRect* dst) const {
578     SkScalar pad = 3.0f * fSigma;
579 
580     dst->set(src.fLeft  - pad, src.fTop    - pad,
581              src.fRight + pad, src.fBottom + pad);
582 }
583 
CreateProc(SkReadBuffer & buffer)584 SkFlattenable* SkBlurMaskFilterImpl::CreateProc(SkReadBuffer& buffer) {
585     const SkScalar sigma = buffer.readScalar();
586     const unsigned style = buffer.readUInt();
587     const unsigned flags = buffer.readUInt();
588     if (style <= kLastEnum_SkBlurStyle) {
589         return SkBlurMaskFilter::Create((SkBlurStyle)style, sigma, flags);
590     }
591     return nullptr;
592 }
593 
flatten(SkWriteBuffer & buffer) const594 void SkBlurMaskFilterImpl::flatten(SkWriteBuffer& buffer) const {
595     buffer.writeScalar(fSigma);
596     buffer.writeUInt(fBlurStyle);
597     buffer.writeUInt(fBlurFlags);
598 }
599 
600 #if SK_SUPPORT_GPU
601 
602 class GrGLRectBlurEffect;
603 
604 class GrRectBlurEffect : public GrFragmentProcessor {
605 public:
~GrRectBlurEffect()606     ~GrRectBlurEffect() override { }
607 
name() const608     const char* name() const override { return "RectBlur"; }
609 
Create(GrTextureProvider * textureProvider,const SkRect & rect,float sigma)610     static GrFragmentProcessor* Create(GrTextureProvider *textureProvider,
611                                        const SkRect& rect, float sigma) {
612         int doubleProfileSize = SkScalarCeilToInt(12*sigma);
613 
614         if (doubleProfileSize >= rect.width() || doubleProfileSize >= rect.height()) {
615             // if the blur sigma is too large so the gaussian overlaps the whole
616             // rect in either direction, fall back to CPU path for now.
617             return nullptr;
618         }
619 
620         SkAutoTUnref<GrTexture> blurProfile(CreateBlurProfileTexture(textureProvider, sigma));
621         if (!blurProfile) {
622            return nullptr;
623         }
624         // in OpenGL ES, mediump floats have a minimum range of 2^14. If we have coordinates bigger
625         // than that, the shader math will end up with infinities and result in the blur effect not
626         // working correctly. To avoid this, we switch into highp when the coordinates are too big.
627         // As 2^14 is the minimum range but the actual range can be bigger, we might end up
628         // switching to highp sooner than strictly necessary, but most devices that have a bigger
629         // range for mediump also have mediump being exactly the same as highp (e.g. all non-OpenGL
630         // ES devices), and thus incur no additional penalty for the switch.
631         static const SkScalar kMAX_BLUR_COORD = SkIntToScalar(16000);
632         GrSLPrecision precision;
633         if (SkScalarAbs(rect.top()) > kMAX_BLUR_COORD ||
634             SkScalarAbs(rect.left()) > kMAX_BLUR_COORD ||
635             SkScalarAbs(rect.bottom()) > kMAX_BLUR_COORD ||
636             SkScalarAbs(rect.right()) > kMAX_BLUR_COORD ||
637             SkScalarAbs(rect.width()) > kMAX_BLUR_COORD ||
638             SkScalarAbs(rect.height()) > kMAX_BLUR_COORD) {
639             precision = kHigh_GrSLPrecision;
640         }
641         else {
642             precision = kDefault_GrSLPrecision;
643         }
644         return new GrRectBlurEffect(rect, sigma, blurProfile, precision);
645     }
646 
getRect() const647     const SkRect& getRect() const { return fRect; }
getSigma() const648     float getSigma() const { return fSigma; }
precision() const649     GrSLPrecision precision() const { return fPrecision; }
650 
651 private:
652     GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blurProfile,
653                      GrSLPrecision fPrecision);
654 
655     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
656 
657     void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
658 
659     bool onIsEqual(const GrFragmentProcessor&) const override;
660 
661     void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
662 
663     static GrTexture* CreateBlurProfileTexture(GrTextureProvider*, float sigma);
664 
665     SkRect          fRect;
666     float           fSigma;
667     GrTextureAccess fBlurProfileAccess;
668     GrSLPrecision   fPrecision;
669 
670     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
671 
672     typedef GrFragmentProcessor INHERITED;
673 };
674 
675 class GrGLRectBlurEffect : public GrGLSLFragmentProcessor {
676 public:
677     void emitCode(EmitArgs&) override;
678 
679     static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
680 
681 protected:
682     void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
683 
684 private:
685     typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
686 
687     UniformHandle       fProxyRectUniform;
688     UniformHandle       fProfileSizeUniform;
689 
690     typedef GrGLSLFragmentProcessor INHERITED;
691 };
692 
OutputRectBlurProfileLookup(GrGLSLFPFragmentBuilder * fragBuilder,const GrGLSLTextureSampler & sampler,const char * output,const char * profileSize,const char * loc,const char * blurred_width,const char * sharp_width)693 void OutputRectBlurProfileLookup(GrGLSLFPFragmentBuilder* fragBuilder,
694                                  const GrGLSLTextureSampler& sampler,
695                                  const char *output,
696                                  const char *profileSize, const char *loc,
697                                  const char *blurred_width,
698                                  const char *sharp_width) {
699     fragBuilder->codeAppendf("float %s;", output);
700     fragBuilder->codeAppendf("{");
701     fragBuilder->codeAppendf("float coord = ((abs(%s - 0.5 * %s) - 0.5 * %s)) / %s;",
702                            loc, blurred_width, sharp_width, profileSize);
703     fragBuilder->codeAppendf("%s = ", output);
704     fragBuilder->appendTextureLookup(sampler, "vec2(coord,0.5)");
705     fragBuilder->codeAppend(".a;");
706     fragBuilder->codeAppendf("}");
707 }
708 
709 
GenKey(const GrProcessor & proc,const GrGLSLCaps &,GrProcessorKeyBuilder * b)710 void GrGLRectBlurEffect::GenKey(const GrProcessor& proc, const GrGLSLCaps&,
711                                 GrProcessorKeyBuilder* b) {
712     const GrRectBlurEffect& rbe = proc.cast<GrRectBlurEffect>();
713 
714     b->add32(rbe.precision());
715 }
716 
717 
emitCode(EmitArgs & args)718 void GrGLRectBlurEffect::emitCode(EmitArgs& args) {
719     const GrRectBlurEffect& rbe = args.fFp.cast<GrRectBlurEffect>();
720 
721     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
722 
723     const char *rectName;
724     const char *profileSizeName;
725 
726     const char* precisionString = GrGLSLShaderVar::PrecisionString(args.fGLSLCaps, rbe.precision());
727     fProxyRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
728                                                    kVec4f_GrSLType,
729                                                    rbe.precision(),
730                                                    "proxyRect",
731                                                    &rectName);
732     fProfileSizeUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
733                                                      kFloat_GrSLType,
734                                                      kDefault_GrSLPrecision,
735                                                      "profileSize",
736                                                      &profileSizeName);
737 
738     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
739     const char *fragmentPos = fragBuilder->fragmentPosition();
740 
741     if (args.fInputColor) {
742         fragBuilder->codeAppendf("vec4 src=%s;", args.fInputColor);
743     } else {
744         fragBuilder->codeAppendf("vec4 src=vec4(1);");
745     }
746 
747     fragBuilder->codeAppendf("%s vec2 translatedPos = %s.xy - %s.xy;", precisionString, fragmentPos,
748                              rectName);
749     fragBuilder->codeAppendf("%s float width = %s.z - %s.x;", precisionString, rectName, rectName);
750     fragBuilder->codeAppendf("%s float height = %s.w - %s.y;", precisionString, rectName, rectName);
751 
752     fragBuilder->codeAppendf("%s vec2 smallDims = vec2(width - %s, height - %s);", precisionString,
753                              profileSizeName, profileSizeName);
754     fragBuilder->codeAppendf("%s float center = 2.0 * floor(%s/2.0 + .25) - 1.0;", precisionString,
755                              profileSizeName);
756     fragBuilder->codeAppendf("%s vec2 wh = smallDims - vec2(center,center);", precisionString);
757 
758     OutputRectBlurProfileLookup(fragBuilder, args.fSamplers[0], "horiz_lookup", profileSizeName,
759                                 "translatedPos.x", "width", "wh.x");
760     OutputRectBlurProfileLookup(fragBuilder, args.fSamplers[0], "vert_lookup", profileSizeName,
761                                 "translatedPos.y", "height", "wh.y");
762 
763     fragBuilder->codeAppendf("float final = horiz_lookup * vert_lookup;");
764     fragBuilder->codeAppendf("%s = src * final;", args.fOutputColor);
765 }
766 
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & proc)767 void GrGLRectBlurEffect::onSetData(const GrGLSLProgramDataManager& pdman,
768                                    const GrProcessor& proc) {
769     const GrRectBlurEffect& rbe = proc.cast<GrRectBlurEffect>();
770     SkRect rect = rbe.getRect();
771 
772     pdman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
773     pdman.set1f(fProfileSizeUniform, SkScalarCeilToScalar(6*rbe.getSigma()));
774 }
775 
CreateBlurProfileTexture(GrTextureProvider * textureProvider,float sigma)776 GrTexture* GrRectBlurEffect::CreateBlurProfileTexture(GrTextureProvider* textureProvider,
777                                                       float sigma) {
778     GrSurfaceDesc texDesc;
779 
780     unsigned int profileSize = SkScalarCeilToInt(6*sigma);
781 
782     texDesc.fWidth = profileSize;
783     texDesc.fHeight = 1;
784     texDesc.fConfig = kAlpha_8_GrPixelConfig;
785 
786     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
787     GrUniqueKey key;
788     GrUniqueKey::Builder builder(&key, kDomain, 1);
789     builder[0] = profileSize;
790     builder.finish();
791 
792     GrTexture *blurProfile = textureProvider->findAndRefTextureByUniqueKey(key);
793 
794     if (!blurProfile) {
795         SkAutoTDeleteArray<uint8_t> profile(SkBlurMask::ComputeBlurProfile(sigma));
796 
797         blurProfile = textureProvider->createTexture(texDesc, SkBudgeted::kYes, profile.get(), 0);
798         if (blurProfile) {
799             textureProvider->assignUniqueKeyToTexture(key, blurProfile);
800         }
801     }
802 
803     return blurProfile;
804 }
805 
GrRectBlurEffect(const SkRect & rect,float sigma,GrTexture * blurProfile,GrSLPrecision precision)806 GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blurProfile,
807                                    GrSLPrecision precision)
808     : fRect(rect)
809     , fSigma(sigma)
810     , fBlurProfileAccess(blurProfile)
811     , fPrecision(precision) {
812     this->initClassID<GrRectBlurEffect>();
813     this->addTextureAccess(&fBlurProfileAccess);
814     this->setWillReadFragmentPosition();
815 }
816 
onGetGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const817 void GrRectBlurEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
818                                              GrProcessorKeyBuilder* b) const {
819     GrGLRectBlurEffect::GenKey(*this, caps, b);
820 }
821 
onCreateGLSLInstance() const822 GrGLSLFragmentProcessor* GrRectBlurEffect::onCreateGLSLInstance() const {
823     return new GrGLRectBlurEffect;
824 }
825 
onIsEqual(const GrFragmentProcessor & sBase) const826 bool GrRectBlurEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
827     const GrRectBlurEffect& s = sBase.cast<GrRectBlurEffect>();
828     return this->getSigma() == s.getSigma() && this->getRect() == s.getRect();
829 }
830 
onComputeInvariantOutput(GrInvariantOutput * inout) const831 void GrRectBlurEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
832     inout->mulByUnknownSingleComponent();
833 }
834 
835 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRectBlurEffect);
836 
TestCreate(GrProcessorTestData * d)837 const GrFragmentProcessor* GrRectBlurEffect::TestCreate(GrProcessorTestData* d) {
838     float sigma = d->fRandom->nextRangeF(3,8);
839     float width = d->fRandom->nextRangeF(200,300);
840     float height = d->fRandom->nextRangeF(200,300);
841     return GrRectBlurEffect::Create(d->fContext->textureProvider(), SkRect::MakeWH(width, height),
842                                     sigma);
843 }
844 
845 
directFilterMaskGPU(GrTextureProvider * texProvider,GrDrawContext * drawContext,GrPaint * grp,const GrClip & clip,const SkMatrix & viewMatrix,const SkStrokeRec & strokeRec,const SkPath & path) const846 bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvider,
847                                                GrDrawContext* drawContext,
848                                                GrPaint* grp,
849                                                const GrClip& clip,
850                                                const SkMatrix& viewMatrix,
851                                                const SkStrokeRec& strokeRec,
852                                                const SkPath& path) const {
853     SkASSERT(drawContext);
854 
855     if (fBlurStyle != kNormal_SkBlurStyle) {
856         return false;
857     }
858 
859     // TODO: we could handle blurred stroked circles
860     if (!strokeRec.isFillStyle()) {
861         return false;
862     }
863 
864     SkScalar xformedSigma = this->computeXformedSigma(viewMatrix);
865 
866     SkAutoTUnref<const GrFragmentProcessor> fp;
867 
868     SkRect rect;
869     if (path.isRect(&rect)) {
870         int pad = SkScalarCeilToInt(6*xformedSigma)/2;
871         rect.outset(SkIntToScalar(pad), SkIntToScalar(pad));
872 
873         fp.reset(GrRectBlurEffect::Create(texProvider, rect, xformedSigma));
874     } else if (path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height())) {
875         fp.reset(GrCircleBlurFragmentProcessor::Create(texProvider, rect, xformedSigma));
876 
877         // expand the rect for the coverage geometry
878         int pad = SkScalarCeilToInt(6*xformedSigma)/2;
879         rect.outset(SkIntToScalar(pad), SkIntToScalar(pad));
880     } else {
881         return false;
882     }
883 
884     if (!fp) {
885         return false;
886     }
887 
888     grp->addCoverageFragmentProcessor(fp);
889 
890     SkMatrix inverse;
891     if (!viewMatrix.invert(&inverse)) {
892         return false;
893     }
894 
895     drawContext->fillRectWithLocalMatrix(clip, *grp, SkMatrix::I(), rect, inverse);
896     return true;
897 }
898 
899 //////////////////////////////////////////////////////////////////////////////
900 
901 class GrRRectBlurEffect : public GrFragmentProcessor {
902 public:
903 
904     static const GrFragmentProcessor* Create(GrTextureProvider*, float sigma, const SkRRect&);
905 
~GrRRectBlurEffect()906     virtual ~GrRRectBlurEffect() {};
name() const907     const char* name() const override { return "GrRRectBlur"; }
908 
getRRect() const909     const SkRRect& getRRect() const { return fRRect; }
getSigma() const910     float getSigma() const { return fSigma; }
911 
912 private:
913     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
914 
915     GrRRectBlurEffect(float sigma, const SkRRect&, GrTexture* profileTexture);
916 
917     virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps,
918                                        GrProcessorKeyBuilder* b) const override;
919 
920     bool onIsEqual(const GrFragmentProcessor& other) const override;
921 
922     void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
923 
924     SkRRect             fRRect;
925     float               fSigma;
926     GrTextureAccess     fNinePatchAccess;
927 
928     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
929 
930     typedef GrFragmentProcessor INHERITED;
931 };
932 
933 
Create(GrTextureProvider * texProvider,float sigma,const SkRRect & rrect)934 const GrFragmentProcessor* GrRRectBlurEffect::Create(GrTextureProvider* texProvider, float sigma,
935                                                      const SkRRect& rrect) {
936     if (rrect.isCircle()) {
937         return GrCircleBlurFragmentProcessor::Create(texProvider, rrect.rect(), sigma);
938     }
939 
940     if (!rrect.isSimpleCircular()) {
941         return nullptr;
942     }
943 
944     // Make sure we can successfully ninepatch this rrect -- the blur sigma has to be
945     // sufficiently small relative to both the size of the corner radius and the
946     // width (and height) of the rrect.
947 
948     unsigned int blurRadius = 3*SkScalarCeilToInt(sigma-1/6.0f);
949     unsigned int cornerRadius = SkScalarCeilToInt(rrect.getSimpleRadii().x());
950     if (cornerRadius + blurRadius > rrect.width()/2 ||
951         cornerRadius + blurRadius > rrect.height()/2) {
952         return nullptr;
953     }
954 
955     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
956     GrUniqueKey key;
957     GrUniqueKey::Builder builder(&key, kDomain, 2);
958     builder[0] = blurRadius;
959     builder[1] = cornerRadius;
960     builder.finish();
961 
962     SkAutoTUnref<GrTexture> blurNinePatchTexture(texProvider->findAndRefTextureByUniqueKey(key));
963 
964     if (!blurNinePatchTexture) {
965         SkMask mask;
966 
967         unsigned int smallRectSide = 2*(blurRadius + cornerRadius) + 1;
968 
969         mask.fBounds = SkIRect::MakeWH(smallRectSide, smallRectSide);
970         mask.fFormat = SkMask::kA8_Format;
971         mask.fRowBytes = mask.fBounds.width();
972         mask.fImage = SkMask::AllocImage(mask.computeTotalImageSize());
973         SkAutoMaskFreeImage amfi(mask.fImage);
974 
975         memset(mask.fImage, 0, mask.computeTotalImageSize());
976 
977         SkRect smallRect;
978         smallRect.setWH(SkIntToScalar(smallRectSide), SkIntToScalar(smallRectSide));
979 
980         SkRRect smallRRect;
981         smallRRect.setRectXY(smallRect, SkIntToScalar(cornerRadius), SkIntToScalar(cornerRadius));
982 
983         SkPath path;
984         path.addRRect(smallRRect);
985 
986         SkDraw::DrawToMask(path, &mask.fBounds, nullptr, nullptr, &mask,
987                            SkMask::kJustRenderImage_CreateMode, SkPaint::kFill_Style);
988 
989         SkMask blurredMask;
990         if (!SkBlurMask::BoxBlur(&blurredMask, mask, sigma, kNormal_SkBlurStyle,
991                                  kHigh_SkBlurQuality, nullptr, true)) {
992             return nullptr;
993         }
994 
995         unsigned int texSide = smallRectSide + 2*blurRadius;
996         GrSurfaceDesc texDesc;
997         texDesc.fWidth = texSide;
998         texDesc.fHeight = texSide;
999         texDesc.fConfig = kAlpha_8_GrPixelConfig;
1000 
1001         blurNinePatchTexture.reset(
1002             texProvider->createTexture(texDesc, SkBudgeted::kYes , blurredMask.fImage, 0));
1003         SkMask::FreeImage(blurredMask.fImage);
1004         if (!blurNinePatchTexture) {
1005             return nullptr;
1006         }
1007         texProvider->assignUniqueKeyToTexture(key, blurNinePatchTexture);
1008     }
1009     return new GrRRectBlurEffect(sigma, rrect, blurNinePatchTexture);
1010 }
1011 
onComputeInvariantOutput(GrInvariantOutput * inout) const1012 void GrRRectBlurEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
1013     inout->mulByUnknownSingleComponent();
1014 }
1015 
GrRRectBlurEffect(float sigma,const SkRRect & rrect,GrTexture * ninePatchTexture)1016 GrRRectBlurEffect::GrRRectBlurEffect(float sigma, const SkRRect& rrect, GrTexture *ninePatchTexture)
1017     : fRRect(rrect),
1018       fSigma(sigma),
1019       fNinePatchAccess(ninePatchTexture) {
1020     this->initClassID<GrRRectBlurEffect>();
1021     this->addTextureAccess(&fNinePatchAccess);
1022     this->setWillReadFragmentPosition();
1023 }
1024 
onIsEqual(const GrFragmentProcessor & other) const1025 bool GrRRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const {
1026     const GrRRectBlurEffect& rrbe = other.cast<GrRRectBlurEffect>();
1027     return fRRect.getSimpleRadii().fX == rrbe.fRRect.getSimpleRadii().fX && fSigma == rrbe.fSigma;
1028 }
1029 
1030 //////////////////////////////////////////////////////////////////////////////
1031 
1032 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRRectBlurEffect);
1033 
TestCreate(GrProcessorTestData * d)1034 const GrFragmentProcessor* GrRRectBlurEffect::TestCreate(GrProcessorTestData* d) {
1035     SkScalar w = d->fRandom->nextRangeScalar(100.f, 1000.f);
1036     SkScalar h = d->fRandom->nextRangeScalar(100.f, 1000.f);
1037     SkScalar r = d->fRandom->nextRangeF(1.f, 9.f);
1038     SkScalar sigma = d->fRandom->nextRangeF(1.f,10.f);
1039     SkRRect rrect;
1040     rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
1041     return GrRRectBlurEffect::Create(d->fContext->textureProvider(), sigma, rrect);
1042 }
1043 
1044 //////////////////////////////////////////////////////////////////////////////
1045 
1046 class GrGLRRectBlurEffect : public GrGLSLFragmentProcessor {
1047 public:
1048     void emitCode(EmitArgs&) override;
1049 
1050 protected:
1051     void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
1052 
1053 private:
1054     GrGLSLProgramDataManager::UniformHandle fProxyRectUniform;
1055     GrGLSLProgramDataManager::UniformHandle fCornerRadiusUniform;
1056     GrGLSLProgramDataManager::UniformHandle fBlurRadiusUniform;
1057     typedef GrGLSLFragmentProcessor INHERITED;
1058 };
1059 
emitCode(EmitArgs & args)1060 void GrGLRRectBlurEffect::emitCode(EmitArgs& args) {
1061     const char *rectName;
1062     const char *cornerRadiusName;
1063     const char *blurRadiusName;
1064 
1065     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1066     // The proxy rect has left, top, right, and bottom edges correspond to
1067     // components x, y, z, and w, respectively.
1068 
1069     fProxyRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
1070                                                    kVec4f_GrSLType,
1071                                                    kDefault_GrSLPrecision,
1072                                                    "proxyRect",
1073                                                    &rectName);
1074     fCornerRadiusUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
1075                                                       kFloat_GrSLType,
1076                                                       kDefault_GrSLPrecision,
1077                                                       "cornerRadius",
1078                                                       &cornerRadiusName);
1079     fBlurRadiusUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
1080                                                     kFloat_GrSLType,
1081                                                     kDefault_GrSLPrecision,
1082                                                     "blurRadius",
1083                                                     &blurRadiusName);
1084 
1085     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
1086     const char* fragmentPos = fragBuilder->fragmentPosition();
1087 
1088     // warp the fragment position to the appropriate part of the 9patch blur texture
1089 
1090     fragBuilder->codeAppendf("vec2 rectCenter = (%s.xy + %s.zw)/2.0;", rectName, rectName);
1091     fragBuilder->codeAppendf("vec2 translatedFragPos = %s.xy - %s.xy;", fragmentPos, rectName);
1092     fragBuilder->codeAppendf("float threshold = %s + 2.0*%s;", cornerRadiusName, blurRadiusName);
1093     fragBuilder->codeAppendf("vec2 middle = %s.zw - %s.xy - 2.0*threshold;", rectName, rectName);
1094 
1095     fragBuilder->codeAppendf(
1096            "if (translatedFragPos.x >= threshold && translatedFragPos.x < (middle.x+threshold)) {");
1097     fragBuilder->codeAppendf("translatedFragPos.x = threshold;\n");
1098     fragBuilder->codeAppendf("} else if (translatedFragPos.x >= (middle.x + threshold)) {");
1099     fragBuilder->codeAppendf("translatedFragPos.x -= middle.x - 1.0;");
1100     fragBuilder->codeAppendf("}");
1101 
1102     fragBuilder->codeAppendf(
1103             "if (translatedFragPos.y > threshold && translatedFragPos.y < (middle.y+threshold)) {");
1104     fragBuilder->codeAppendf("translatedFragPos.y = threshold;");
1105     fragBuilder->codeAppendf("} else if (translatedFragPos.y >= (middle.y + threshold)) {");
1106     fragBuilder->codeAppendf("translatedFragPos.y -= middle.y - 1.0;");
1107     fragBuilder->codeAppendf("}");
1108 
1109     fragBuilder->codeAppendf("vec2 proxyDims = vec2(2.0*threshold+1.0);");
1110     fragBuilder->codeAppendf("vec2 texCoord = translatedFragPos / proxyDims;");
1111 
1112     fragBuilder->codeAppendf("%s = ", args.fOutputColor);
1113     fragBuilder->appendTextureLookupAndModulate(args.fInputColor, args.fSamplers[0], "texCoord");
1114     fragBuilder->codeAppend(";");
1115 }
1116 
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & proc)1117 void GrGLRRectBlurEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1118                                     const GrProcessor& proc) {
1119     const GrRRectBlurEffect& brre = proc.cast<GrRRectBlurEffect>();
1120     SkRRect rrect = brre.getRRect();
1121 
1122     float blurRadius = 3.f*SkScalarCeilToScalar(brre.getSigma()-1/6.0f);
1123     pdman.set1f(fBlurRadiusUniform, blurRadius);
1124 
1125     SkRect rect = rrect.getBounds();
1126     rect.outset(blurRadius, blurRadius);
1127     pdman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
1128 
1129     SkScalar radius = 0;
1130     SkASSERT(rrect.isSimpleCircular() || rrect.isRect());
1131     radius = rrect.getSimpleRadii().fX;
1132     pdman.set1f(fCornerRadiusUniform, radius);
1133 }
1134 
onGetGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const1135 void GrRRectBlurEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1136                                               GrProcessorKeyBuilder* b) const {
1137     GrGLRRectBlurEffect::GenKey(*this, caps, b);
1138 }
1139 
onCreateGLSLInstance() const1140 GrGLSLFragmentProcessor* GrRRectBlurEffect::onCreateGLSLInstance() const {
1141     return new GrGLRRectBlurEffect;
1142 }
1143 
directFilterRRectMaskGPU(GrTextureProvider * texProvider,GrDrawContext * drawContext,GrPaint * grp,const GrClip & clip,const SkMatrix & viewMatrix,const SkStrokeRec & strokeRec,const SkRRect & rrect) const1144 bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrTextureProvider* texProvider,
1145                                                     GrDrawContext* drawContext,
1146                                                     GrPaint* grp,
1147                                                     const GrClip& clip,
1148                                                     const SkMatrix& viewMatrix,
1149                                                     const SkStrokeRec& strokeRec,
1150                                                     const SkRRect& rrect) const {
1151     SkASSERT(drawContext);
1152 
1153     if (fBlurStyle != kNormal_SkBlurStyle) {
1154         return false;
1155     }
1156 
1157     if (!strokeRec.isFillStyle()) {
1158         return false;
1159     }
1160 
1161     SkScalar xformedSigma = this->computeXformedSigma(viewMatrix);
1162     float extra=3.f*SkScalarCeilToScalar(xformedSigma-1/6.0f);
1163 
1164     SkRect proxyRect = rrect.rect();
1165     proxyRect.outset(extra, extra);
1166 
1167     SkAutoTUnref<const GrFragmentProcessor> fp(GrRRectBlurEffect::Create(texProvider,
1168                                                                          xformedSigma, rrect));
1169     if (!fp) {
1170         return false;
1171     }
1172 
1173     grp->addCoverageFragmentProcessor(fp);
1174 
1175     SkMatrix inverse;
1176     if (!viewMatrix.invert(&inverse)) {
1177         return false;
1178     }
1179 
1180     drawContext->fillRectWithLocalMatrix(clip, *grp, SkMatrix::I(), proxyRect, inverse);
1181     return true;
1182 }
1183 
canFilterMaskGPU(const SkRRect & devRRect,const SkIRect & clipBounds,const SkMatrix & ctm,SkRect * maskRect) const1184 bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRRect& devRRect,
1185                                             const SkIRect& clipBounds,
1186                                             const SkMatrix& ctm,
1187                                             SkRect* maskRect) const {
1188     SkScalar xformedSigma = this->computeXformedSigma(ctm);
1189     if (xformedSigma <= 0) {
1190         return false;
1191     }
1192 
1193     // We always do circles on the GPU
1194     if (!devRRect.isCircle()) {
1195         static const SkScalar kMIN_GPU_BLUR_SIZE  = SkIntToScalar(64);
1196         static const SkScalar kMIN_GPU_BLUR_SIGMA = SkIntToScalar(32);
1197 
1198         if (devRRect.width() <= kMIN_GPU_BLUR_SIZE &&
1199             devRRect.height() <= kMIN_GPU_BLUR_SIZE &&
1200             xformedSigma <= kMIN_GPU_BLUR_SIGMA) {
1201             // We prefer to blur small rects with small radii on the CPU.
1202             return false;
1203         }
1204     }
1205 
1206     if (nullptr == maskRect) {
1207         // don't need to compute maskRect
1208         return true;
1209     }
1210 
1211     float sigma3 = 3 * SkScalarToFloat(xformedSigma);
1212 
1213     SkRect clipRect = SkRect::Make(clipBounds);
1214     SkRect srcRect(devRRect.rect());
1215 
1216     // Outset srcRect and clipRect by 3 * sigma, to compute affected blur area.
1217     srcRect.outset(sigma3, sigma3);
1218     clipRect.outset(sigma3, sigma3);
1219     if (!srcRect.intersect(clipRect)) {
1220         srcRect.setEmpty();
1221     }
1222     *maskRect = srcRect;
1223     return true;
1224 }
1225 
filterMaskGPU(GrTexture * src,const SkMatrix & ctm,const SkRect & maskRect,GrTexture ** result,bool canOverwriteSrc) const1226 bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src,
1227                                          const SkMatrix& ctm,
1228                                          const SkRect& maskRect,
1229                                          GrTexture** result,
1230                                          bool canOverwriteSrc) const {
1231     SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
1232 
1233     GrContext* context = src->getContext();
1234 
1235     SkScalar xformedSigma = this->computeXformedSigma(ctm);
1236     SkASSERT(xformedSigma > 0);
1237 
1238     // If we're doing a normal blur, we can clobber the pathTexture in the
1239     // gaussianBlur.  Otherwise, we need to save it for later compositing.
1240     bool isNormalBlur = (kNormal_SkBlurStyle == fBlurStyle);
1241     *result = SkGpuBlurUtils::GaussianBlur(context, src, isNormalBlur && canOverwriteSrc,
1242                                            clipRect, nullptr, xformedSigma, xformedSigma);
1243     if (nullptr == *result) {
1244         return false;
1245     }
1246 
1247     if (!isNormalBlur) {
1248         GrPaint paint;
1249         SkMatrix matrix;
1250         matrix.setIDiv(src->width(), src->height());
1251         // Blend pathTexture over blurTexture.
1252         paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Create(src, matrix))->unref();
1253         if (kInner_SkBlurStyle == fBlurStyle) {
1254             // inner:  dst = dst * src
1255             paint.setCoverageSetOpXPFactory(SkRegion::kIntersect_Op);
1256         } else if (kSolid_SkBlurStyle == fBlurStyle) {
1257             // solid:  dst = src + dst - src * dst
1258             //             = src + (1 - src) * dst
1259             paint.setCoverageSetOpXPFactory(SkRegion::kUnion_Op);
1260         } else if (kOuter_SkBlurStyle == fBlurStyle) {
1261             // outer:  dst = dst * (1 - src)
1262             //             = 0 * src + (1 - src) * dst
1263             paint.setCoverageSetOpXPFactory(SkRegion::kDifference_Op);
1264         } else {
1265             paint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op);
1266         }
1267 
1268         SkAutoTUnref<GrDrawContext> drawContext(context->drawContext((*result)->asRenderTarget()));
1269         if (!drawContext) {
1270             return false;
1271         }
1272 
1273         drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), clipRect);
1274     }
1275 
1276     return true;
1277 }
1278 
1279 #endif // SK_SUPPORT_GPU
1280 
1281 
1282 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const1283 void SkBlurMaskFilterImpl::toString(SkString* str) const {
1284     str->append("SkBlurMaskFilterImpl: (");
1285 
1286     str->append("sigma: ");
1287     str->appendScalar(fSigma);
1288     str->append(" ");
1289 
1290     static const char* gStyleName[kLastEnum_SkBlurStyle + 1] = {
1291         "normal", "solid", "outer", "inner"
1292     };
1293 
1294     str->appendf("style: %s ", gStyleName[fBlurStyle]);
1295     str->append("flags: (");
1296     if (fBlurFlags) {
1297         bool needSeparator = false;
1298         SkAddFlagToString(str,
1299                           SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag),
1300                           "IgnoreXform", &needSeparator);
1301         SkAddFlagToString(str,
1302                           SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag),
1303                           "HighQuality", &needSeparator);
1304     } else {
1305         str->append("None");
1306     }
1307     str->append("))");
1308 }
1309 #endif
1310 
1311 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
1312     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
1313 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
1314