1 
2 /*
3  * Copyright 2006 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 #include "SkBlurMaskFilter.h"
10 #include "SkBlurMask.h"
11 #include "SkGpuBlurUtils.h"
12 #include "SkReadBuffer.h"
13 #include "SkWriteBuffer.h"
14 #include "SkMaskFilter.h"
15 #include "SkRRect.h"
16 #include "SkRTConf.h"
17 #include "SkStringUtils.h"
18 #include "SkStrokeRec.h"
19 
20 #if SK_SUPPORT_GPU
21 #include "GrContext.h"
22 #include "GrTexture.h"
23 #include "GrFragmentProcessor.h"
24 #include "GrInvariantOutput.h"
25 #include "SkGrPixelRef.h"
26 #include "SkDraw.h"
27 #include "effects/GrSimpleTextureEffect.h"
28 #include "gl/GrGLProcessor.h"
29 #include "gl/builders/GrGLProgramBuilder.h"
30 #endif
31 
ConvertRadiusToSigma(SkScalar radius)32 SkScalar SkBlurMaskFilter::ConvertRadiusToSigma(SkScalar radius) {
33     return SkBlurMask::ConvertRadiusToSigma(radius);
34 }
35 
36 class SkBlurMaskFilterImpl : public SkMaskFilter {
37 public:
38     SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle, uint32_t flags);
39 
40     // overrides from SkMaskFilter
41     SkMask::Format getFormat() const override;
42     virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
43                             SkIPoint* margin) const override;
44 
45 #if SK_SUPPORT_GPU
46     virtual bool canFilterMaskGPU(const SkRect& devBounds,
47                                   const SkIRect& clipBounds,
48                                   const SkMatrix& ctm,
49                                   SkRect* maskRect) const override;
50     virtual bool directFilterMaskGPU(GrContext* context,
51                                      GrRenderTarget* rt,
52                                      GrPaint* grp,
53                                      const GrClip&,
54                                      const SkMatrix& viewMatrix,
55                                      const SkStrokeRec& strokeRec,
56                                      const SkPath& path) const override;
57     virtual bool directFilterRRectMaskGPU(GrContext* context,
58                                           GrRenderTarget* rt,
59                                           GrPaint* grp,
60                                           const GrClip&,
61                                           const SkMatrix& viewMatrix,
62                                           const SkStrokeRec& strokeRec,
63                                           const SkRRect& rrect) const override;
64 
65     virtual bool filterMaskGPU(GrTexture* src,
66                                const SkMatrix& ctm,
67                                const SkRect& maskRect,
68                                GrTexture** result,
69                                bool canOverwriteSrc) const override;
70 #endif
71 
72     void computeFastBounds(const SkRect&, SkRect*) const override;
73     bool asABlur(BlurRec*) const override;
74 
75     SK_TO_STRING_OVERRIDE()
76     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)
77 
78 protected:
79     virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMatrix&,
80                                            const SkIRect& clipBounds,
81                                            NinePatch*) const override;
82 
83     virtual FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&,
84                                            const SkIRect& clipBounds,
85                                            NinePatch*) const override;
86 
87     bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix,
88                         SkIPoint* margin, SkMask::CreateMode createMode) const;
89     bool filterRRectMask(SkMask* dstM, const SkRRect& r, const SkMatrix& matrix,
90                         SkIPoint* margin, SkMask::CreateMode createMode) const;
91 
92 private:
93     // To avoid unseemly allocation requests (esp. for finite platforms like
94     // handset) we limit the radius so something manageable. (as opposed to
95     // a request like 10,000)
96     static const SkScalar kMAX_BLUR_SIGMA;
97 
98     SkScalar    fSigma;
99     SkBlurStyle fBlurStyle;
100     uint32_t    fBlurFlags;
101 
getQuality() const102     SkBlurQuality getQuality() const {
103         return (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
104                 kHigh_SkBlurQuality : kLow_SkBlurQuality;
105     }
106 
107     SkBlurMaskFilterImpl(SkReadBuffer&);
108     void flatten(SkWriteBuffer&) const override;
109 
computeXformedSigma(const SkMatrix & ctm) const110     SkScalar computeXformedSigma(const SkMatrix& ctm) const {
111         bool ignoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
112 
113         SkScalar xformedSigma = ignoreTransform ? fSigma : ctm.mapRadius(fSigma);
114         return SkMinScalar(xformedSigma, kMAX_BLUR_SIGMA);
115     }
116 
117     friend class SkBlurMaskFilter;
118 
119     typedef SkMaskFilter INHERITED;
120 };
121 
122 const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_SIGMA = SkIntToScalar(128);
123 
Create(SkBlurStyle style,SkScalar sigma,uint32_t flags)124 SkMaskFilter* SkBlurMaskFilter::Create(SkBlurStyle style, SkScalar sigma, uint32_t flags) {
125     if (!SkScalarIsFinite(sigma) || sigma <= 0) {
126         return NULL;
127     }
128     if ((unsigned)style > (unsigned)kLastEnum_SkBlurStyle) {
129         return NULL;
130     }
131     if (flags > SkBlurMaskFilter::kAll_BlurFlag) {
132         return NULL;
133     }
134     return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags));
135 }
136 
137 ///////////////////////////////////////////////////////////////////////////////
138 
SkBlurMaskFilterImpl(SkScalar sigma,SkBlurStyle style,uint32_t flags)139 SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle style, uint32_t flags)
140     : fSigma(sigma)
141     , fBlurStyle(style)
142     , fBlurFlags(flags) {
143     SkASSERT(fSigma > 0);
144     SkASSERT((unsigned)style <= kLastEnum_SkBlurStyle);
145     SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
146 }
147 
getFormat() const148 SkMask::Format SkBlurMaskFilterImpl::getFormat() const {
149     return SkMask::kA8_Format;
150 }
151 
asABlur(BlurRec * rec) const152 bool SkBlurMaskFilterImpl::asABlur(BlurRec* rec) const {
153     if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
154         return false;
155     }
156 
157     if (rec) {
158         rec->fSigma = fSigma;
159         rec->fStyle = fBlurStyle;
160         rec->fQuality = this->getQuality();
161     }
162     return true;
163 }
164 
filterMask(SkMask * dst,const SkMask & src,const SkMatrix & matrix,SkIPoint * margin) const165 bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
166                                       const SkMatrix& matrix,
167                                       SkIPoint* margin) const{
168     SkScalar sigma = this->computeXformedSigma(matrix);
169     return SkBlurMask::BoxBlur(dst, src, sigma, fBlurStyle, this->getQuality(), margin);
170 }
171 
filterRectMask(SkMask * dst,const SkRect & r,const SkMatrix & matrix,SkIPoint * margin,SkMask::CreateMode createMode) const172 bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
173                                           const SkMatrix& matrix,
174                                           SkIPoint* margin, SkMask::CreateMode createMode) const{
175     SkScalar sigma = computeXformedSigma(matrix);
176 
177     return SkBlurMask::BlurRect(sigma, dst, r, fBlurStyle,
178                                 margin, createMode);
179 }
180 
filterRRectMask(SkMask * dst,const SkRRect & r,const SkMatrix & matrix,SkIPoint * margin,SkMask::CreateMode createMode) const181 bool SkBlurMaskFilterImpl::filterRRectMask(SkMask* dst, const SkRRect& r,
182                                           const SkMatrix& matrix,
183                                           SkIPoint* margin, SkMask::CreateMode createMode) const{
184     SkScalar sigma = computeXformedSigma(matrix);
185 
186     return SkBlurMask::BlurRRect(sigma, dst, r, fBlurStyle,
187                                 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 != NULL);
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 (NULL == 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 != NULL);
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.fImage = NULL;
355     srcM.fFormat = SkMask::kA8_Format;
356     srcM.fRowBytes = 0;
357 
358     bool filterResult = false;
359     if (c_analyticBlurRRect) {
360         // special case for fast round rect blur
361         // don't actually do the blur the first time, just compute the correct size
362         filterResult = this->filterRRectMask(&dstM, rrect, matrix, &margin,
363                                             SkMask::kJustComputeBounds_CreateMode);
364     }
365 
366     if (!filterResult) {
367         filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
368     }
369 
370     if (!filterResult) {
371         return kFalse_FilterReturn;
372     }
373 
374     // Now figure out the appropriate width and height of the smaller round rectangle
375     // to stretch. It will take into account the larger radius per side as well as double
376     // the margin, to account for inner and outer blur.
377     const SkVector& UL = rrect.radii(SkRRect::kUpperLeft_Corner);
378     const SkVector& UR = rrect.radii(SkRRect::kUpperRight_Corner);
379     const SkVector& LR = rrect.radii(SkRRect::kLowerRight_Corner);
380     const SkVector& LL = rrect.radii(SkRRect::kLowerLeft_Corner);
381 
382     const SkScalar leftUnstretched = SkTMax(UL.fX, LL.fX) + SkIntToScalar(2 * margin.fX);
383     const SkScalar rightUnstretched = SkTMax(UR.fX, LR.fX) + SkIntToScalar(2 * margin.fX);
384 
385     // Extra space in the middle to ensure an unchanging piece for stretching. Use 3 to cover
386     // any fractional space on either side plus 1 for the part to stretch.
387     const SkScalar stretchSize = SkIntToScalar(3);
388 
389     const SkScalar totalSmallWidth = leftUnstretched + rightUnstretched + stretchSize;
390     if (totalSmallWidth >= rrect.rect().width()) {
391         // There is no valid piece to stretch.
392         return kUnimplemented_FilterReturn;
393     }
394 
395     const SkScalar topUnstretched = SkTMax(UL.fY, UR.fY) + SkIntToScalar(2 * margin.fY);
396     const SkScalar bottomUnstretched = SkTMax(LL.fY, LR.fY) + SkIntToScalar(2 * margin.fY);
397 
398     const SkScalar totalSmallHeight = topUnstretched + bottomUnstretched + stretchSize;
399     if (totalSmallHeight >= rrect.rect().height()) {
400         // There is no valid piece to stretch.
401         return kUnimplemented_FilterReturn;
402     }
403 
404     SkRect smallR = SkRect::MakeWH(totalSmallWidth, totalSmallHeight);
405 
406     SkRRect smallRR;
407     SkVector radii[4];
408     radii[SkRRect::kUpperLeft_Corner] = UL;
409     radii[SkRRect::kUpperRight_Corner] = UR;
410     radii[SkRRect::kLowerRight_Corner] = LR;
411     radii[SkRRect::kLowerLeft_Corner] = LL;
412     smallRR.setRectRadii(smallR, radii);
413 
414     const SkScalar sigma = this->computeXformedSigma(matrix);
415     SkCachedData* cache = find_cached_rrect(&patch->fMask, sigma, fBlurStyle,
416                                             this->getQuality(), smallRR);
417     if (!cache) {
418         bool analyticBlurWorked = false;
419         if (c_analyticBlurRRect) {
420             analyticBlurWorked =
421                 this->filterRRectMask(&patch->fMask, smallRR, matrix, &margin,
422                                       SkMask::kComputeBoundsAndRenderImage_CreateMode);
423         }
424 
425         if (!analyticBlurWorked) {
426             if (!draw_rrect_into_mask(smallRR, &srcM)) {
427                 return kFalse_FilterReturn;
428             }
429 
430             SkAutoMaskFreeImage amf(srcM.fImage);
431 
432             if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
433                 return kFalse_FilterReturn;
434             }
435         }
436         cache = add_cached_rrect(&patch->fMask, sigma, fBlurStyle, this->getQuality(), smallRR);
437     }
438 
439     patch->fMask.fBounds.offsetTo(0, 0);
440     patch->fOuterRect = dstM.fBounds;
441     patch->fCenter.fX = SkScalarCeilToInt(leftUnstretched) + 1;
442     patch->fCenter.fY = SkScalarCeilToInt(topUnstretched) + 1;
443     SkASSERT(NULL == patch->fCache);
444     patch->fCache = cache;  // transfer ownership to patch
445     return kTrue_FilterReturn;
446 }
447 
448 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", true, "Use the faster analytic blur approach for ninepatch rects" );
449 
450 SkMaskFilter::FilterReturn
filterRectsToNine(const SkRect rects[],int count,const SkMatrix & matrix,const SkIRect & clipBounds,NinePatch * patch) const451 SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
452                                         const SkMatrix& matrix,
453                                         const SkIRect& clipBounds,
454                                         NinePatch* patch) const {
455     if (count < 1 || count > 2) {
456         return kUnimplemented_FilterReturn;
457     }
458 
459     // TODO: report correct metrics for innerstyle, where we do not grow the
460     // total bounds, but we do need an inset the size of our blur-radius
461     if (kInner_SkBlurStyle == fBlurStyle || kOuter_SkBlurStyle == fBlurStyle) {
462         return kUnimplemented_FilterReturn;
463     }
464 
465     // TODO: take clipBounds into account to limit our coordinates up front
466     // for now, just skip too-large src rects (to take the old code path).
467     if (rect_exceeds(rects[0], SkIntToScalar(32767))) {
468         return kUnimplemented_FilterReturn;
469     }
470 
471     SkIPoint margin;
472     SkMask  srcM, dstM;
473     srcM.fBounds = rects[0].roundOut();
474     srcM.fImage = NULL;
475     srcM.fFormat = SkMask::kA8_Format;
476     srcM.fRowBytes = 0;
477 
478     bool filterResult = false;
479     if (count == 1 && c_analyticBlurNinepatch) {
480         // special case for fast rect blur
481         // don't actually do the blur the first time, just compute the correct size
482         filterResult = this->filterRectMask(&dstM, rects[0], matrix, &margin,
483                                             SkMask::kJustComputeBounds_CreateMode);
484     } else {
485         filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
486     }
487 
488     if (!filterResult) {
489         return kFalse_FilterReturn;
490     }
491 
492     /*
493      *  smallR is the smallest version of 'rect' that will still guarantee that
494      *  we get the same blur results on all edges, plus 1 center row/col that is
495      *  representative of the extendible/stretchable edges of the ninepatch.
496      *  Since our actual edge may be fractional we inset 1 more to be sure we
497      *  don't miss any interior blur.
498      *  x is an added pixel of blur, and { and } are the (fractional) edge
499      *  pixels from the original rect.
500      *
501      *   x x { x x .... x x } x x
502      *
503      *  Thus, in this case, we inset by a total of 5 (on each side) beginning
504      *  with our outer-rect (dstM.fBounds)
505      */
506     SkRect smallR[2];
507     SkIPoint center;
508 
509     // +2 is from +1 for each edge (to account for possible fractional edges
510     int smallW = dstM.fBounds.width() - srcM.fBounds.width() + 2;
511     int smallH = dstM.fBounds.height() - srcM.fBounds.height() + 2;
512     SkIRect innerIR;
513 
514     if (1 == count) {
515         innerIR = srcM.fBounds;
516         center.set(smallW, smallH);
517     } else {
518         SkASSERT(2 == count);
519         rects[1].roundIn(&innerIR);
520         center.set(smallW + (innerIR.left() - srcM.fBounds.left()),
521                    smallH + (innerIR.top() - srcM.fBounds.top()));
522     }
523 
524     // +1 so we get a clean, stretchable, center row/col
525     smallW += 1;
526     smallH += 1;
527 
528     // we want the inset amounts to be integral, so we don't change any
529     // fractional phase on the fRight or fBottom of our smallR.
530     const SkScalar dx = SkIntToScalar(innerIR.width() - smallW);
531     const SkScalar dy = SkIntToScalar(innerIR.height() - smallH);
532     if (dx < 0 || dy < 0) {
533         // we're too small, relative to our blur, to break into nine-patch,
534         // so we ask to have our normal filterMask() be called.
535         return kUnimplemented_FilterReturn;
536     }
537 
538     smallR[0].set(rects[0].left(), rects[0].top(), rects[0].right() - dx, rects[0].bottom() - dy);
539     if (smallR[0].width() < 2 || smallR[0].height() < 2) {
540         return kUnimplemented_FilterReturn;
541     }
542     if (2 == count) {
543         smallR[1].set(rects[1].left(), rects[1].top(),
544                       rects[1].right() - dx, rects[1].bottom() - dy);
545         SkASSERT(!smallR[1].isEmpty());
546     }
547 
548     const SkScalar sigma = this->computeXformedSigma(matrix);
549     SkCachedData* cache = find_cached_rects(&patch->fMask, sigma, fBlurStyle,
550                                             this->getQuality(), smallR, count);
551     if (!cache) {
552         if (count > 1 || !c_analyticBlurNinepatch) {
553             if (!draw_rects_into_mask(smallR, count, &srcM)) {
554                 return kFalse_FilterReturn;
555             }
556 
557             SkAutoMaskFreeImage amf(srcM.fImage);
558 
559             if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
560                 return kFalse_FilterReturn;
561             }
562         } else {
563             if (!this->filterRectMask(&patch->fMask, smallR[0], matrix, &margin,
564                                       SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
565                 return kFalse_FilterReturn;
566             }
567         }
568         cache = add_cached_rects(&patch->fMask, sigma, fBlurStyle, this->getQuality(), smallR, count);
569     }
570     patch->fMask.fBounds.offsetTo(0, 0);
571     patch->fOuterRect = dstM.fBounds;
572     patch->fCenter = center;
573     SkASSERT(NULL == patch->fCache);
574     patch->fCache = cache;  // transfer ownership to patch
575     return kTrue_FilterReturn;
576 }
577 
computeFastBounds(const SkRect & src,SkRect * dst) const578 void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
579                                              SkRect* dst) const {
580     SkScalar pad = 3.0f * fSigma;
581 
582     dst->set(src.fLeft  - pad, src.fTop    - pad,
583              src.fRight + pad, src.fBottom + pad);
584 }
585 
CreateProc(SkReadBuffer & buffer)586 SkFlattenable* SkBlurMaskFilterImpl::CreateProc(SkReadBuffer& buffer) {
587     const SkScalar sigma = buffer.readScalar();
588     const unsigned style = buffer.readUInt();
589     const unsigned flags = buffer.readUInt();
590     if (style <= kLastEnum_SkBlurStyle) {
591         return SkBlurMaskFilter::Create((SkBlurStyle)style, sigma, flags);
592     }
593     return NULL;
594 }
595 
flatten(SkWriteBuffer & buffer) const596 void SkBlurMaskFilterImpl::flatten(SkWriteBuffer& buffer) const {
597     buffer.writeScalar(fSigma);
598     buffer.writeUInt(fBlurStyle);
599     buffer.writeUInt(fBlurFlags);
600 }
601 
602 #if SK_SUPPORT_GPU
603 
604 class GrGLRectBlurEffect;
605 
606 class GrRectBlurEffect : public GrFragmentProcessor {
607 public:
608     virtual ~GrRectBlurEffect();
609 
name() const610     const char* name() const override { return "RectBlur"; }
611 
612     virtual void getGLProcessorKey(const GrGLSLCaps& caps,
613                                    GrProcessorKeyBuilder* b) const override;
614 
615     GrGLFragmentProcessor* createGLInstance() const override;
616 
617     /**
618      * Create a simple filter effect with custom bicubic coefficients.
619      */
Create(GrTextureProvider * textureProvider,const SkRect & rect,float sigma)620     static GrFragmentProcessor* Create(GrTextureProvider *textureProvider, const SkRect& rect,
621                                        float sigma) {
622         GrTexture *blurProfileTexture = NULL;
623         int doubleProfileSize = SkScalarCeilToInt(12*sigma);
624 
625         if (doubleProfileSize >= rect.width() || doubleProfileSize >= rect.height()) {
626             // if the blur sigma is too large so the gaussian overlaps the whole
627             // rect in either direction, fall back to CPU path for now.
628 
629             return NULL;
630         }
631 
632         bool createdBlurProfileTexture = CreateBlurProfileTexture(
633             textureProvider, sigma, &blurProfileTexture);
634         SkAutoTUnref<GrTexture> hunref(blurProfileTexture);
635         if (!createdBlurProfileTexture) {
636            return NULL;
637         }
638         return SkNEW_ARGS(GrRectBlurEffect, (rect, sigma, blurProfileTexture));
639     }
640 
getRect() const641     const SkRect& getRect() const { return fRect; }
getSigma() const642     float getSigma() const { return fSigma; }
643 
644 private:
645     GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blur_profile);
646     bool onIsEqual(const GrFragmentProcessor&) const override;
647 
648     void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
649 
650     static bool CreateBlurProfileTexture(GrTextureProvider*, float sigma,
651                                          GrTexture **blurProfileTexture);
652 
653     SkRect          fRect;
654     float           fSigma;
655     GrTextureAccess fBlurProfileAccess;
656 
657     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
658 
659     typedef GrFragmentProcessor INHERITED;
660 };
661 
662 class GrGLRectBlurEffect : public GrGLFragmentProcessor {
663 public:
GrGLRectBlurEffect(const GrProcessor &)664     GrGLRectBlurEffect(const GrProcessor&) {}
665     virtual void emitCode(GrGLFPBuilder*,
666                           const GrFragmentProcessor&,
667                           const char* outputColor,
668                           const char* inputColor,
669                           const TransformedCoordsArray&,
670                           const TextureSamplerArray&) override;
671 
672     void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
673 
674 private:
675     typedef GrGLProgramDataManager::UniformHandle UniformHandle;
676 
677     UniformHandle       fProxyRectUniform;
678     UniformHandle       fProfileSizeUniform;
679 
680     typedef GrGLFragmentProcessor INHERITED;
681 };
682 
OutputRectBlurProfileLookup(GrGLFragmentBuilder * fsBuilder,const GrGLShaderBuilder::TextureSampler & sampler,const char * output,const char * profileSize,const char * loc,const char * blurred_width,const char * sharp_width)683 void OutputRectBlurProfileLookup(GrGLFragmentBuilder* fsBuilder,
684                                  const GrGLShaderBuilder::TextureSampler& sampler,
685                                  const char *output,
686                                  const char *profileSize, const char *loc,
687                                  const char *blurred_width,
688                                  const char *sharp_width) {
689     fsBuilder->codeAppendf("\tfloat %s;\n", output);
690     fsBuilder->codeAppendf("\t\t{\n");
691     fsBuilder->codeAppendf("\t\t\tfloat coord = (0.5 * (abs(2.0*%s - %s) - %s))/%s;\n",
692                            loc, blurred_width, sharp_width, profileSize);
693     fsBuilder->codeAppendf("\t\t\t%s = ", output);
694     fsBuilder->appendTextureLookup(sampler, "vec2(coord,0.5)");
695     fsBuilder->codeAppend(".a;\n");
696     fsBuilder->codeAppendf("\t\t}\n");
697 }
698 
emitCode(GrGLFPBuilder * builder,const GrFragmentProcessor &,const char * outputColor,const char * inputColor,const TransformedCoordsArray & coords,const TextureSamplerArray & samplers)699 void GrGLRectBlurEffect::emitCode(GrGLFPBuilder* builder,
700                                  const GrFragmentProcessor&,
701                                  const char* outputColor,
702                                  const char* inputColor,
703                                  const TransformedCoordsArray& coords,
704                                  const TextureSamplerArray& samplers) {
705 
706     const char *rectName;
707     const char *profileSizeName;
708 
709     fProxyRectUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
710                                             kVec4f_GrSLType,
711                                             kDefault_GrSLPrecision,
712                                             "proxyRect",
713                                             &rectName);
714     fProfileSizeUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
715                                             kFloat_GrSLType,
716                                             kDefault_GrSLPrecision,
717                                             "profileSize",
718                                             &profileSizeName);
719 
720     GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
721     const char *fragmentPos = fsBuilder->fragmentPosition();
722 
723     if (inputColor) {
724         fsBuilder->codeAppendf("\tvec4 src=%s;\n", inputColor);
725     } else {
726         fsBuilder->codeAppendf("\tvec4 src=vec4(1)\n;");
727     }
728 
729     fsBuilder->codeAppendf("\tvec2 translatedPos = %s.xy - %s.xy;\n", fragmentPos, rectName );
730     fsBuilder->codeAppendf("\tfloat width = %s.z - %s.x;\n", rectName, rectName);
731     fsBuilder->codeAppendf("\tfloat height = %s.w - %s.y;\n", rectName, rectName);
732 
733     fsBuilder->codeAppendf("\tvec2 smallDims = vec2(width - %s, height-%s);\n", profileSizeName, profileSizeName);
734     fsBuilder->codeAppendf("\tfloat center = 2.0 * floor(%s/2.0 + .25) - 1.0;\n", profileSizeName);
735     fsBuilder->codeAppendf("\tvec2 wh = smallDims - vec2(center,center);\n");
736 
737     OutputRectBlurProfileLookup(fsBuilder, samplers[0], "horiz_lookup", profileSizeName, "translatedPos.x", "width", "wh.x");
738     OutputRectBlurProfileLookup(fsBuilder, samplers[0], "vert_lookup", profileSizeName, "translatedPos.y", "height", "wh.y");
739 
740     fsBuilder->codeAppendf("\tfloat final = horiz_lookup * vert_lookup;\n");
741     fsBuilder->codeAppendf("\t%s = src * final;\n", outputColor );
742 }
743 
setData(const GrGLProgramDataManager & pdman,const GrProcessor & proc)744 void GrGLRectBlurEffect::setData(const GrGLProgramDataManager& pdman,
745                                  const GrProcessor& proc) {
746     const GrRectBlurEffect& rbe = proc.cast<GrRectBlurEffect>();
747     SkRect rect = rbe.getRect();
748 
749     pdman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
750     pdman.set1f(fProfileSizeUniform, SkScalarCeilToScalar(6*rbe.getSigma()));
751 }
752 
CreateBlurProfileTexture(GrTextureProvider * textureProvider,float sigma,GrTexture ** blurProfileTexture)753 bool GrRectBlurEffect::CreateBlurProfileTexture(GrTextureProvider* textureProvider, float sigma,
754                                                 GrTexture **blurProfileTexture) {
755     GrSurfaceDesc texDesc;
756 
757     unsigned int profileSize = SkScalarCeilToInt(6*sigma);
758 
759     texDesc.fWidth = profileSize;
760     texDesc.fHeight = 1;
761     texDesc.fConfig = kAlpha_8_GrPixelConfig;
762 
763     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
764     GrUniqueKey key;
765     GrUniqueKey::Builder builder(&key, kDomain, 1);
766     builder[0] = profileSize;
767     builder.finish();
768 
769     uint8_t *profile = NULL;
770     SkAutoTDeleteArray<uint8_t> ada(NULL);
771 
772     *blurProfileTexture = textureProvider->findAndRefTextureByUniqueKey(key);
773 
774     if (NULL == *blurProfileTexture) {
775 
776         SkBlurMask::ComputeBlurProfile(sigma, &profile);
777         ada.reset(profile);
778 
779         *blurProfileTexture = textureProvider->createTexture(texDesc, true, profile, 0);
780 
781         if (NULL == *blurProfileTexture) {
782             return false;
783         }
784         textureProvider->assignUniqueKeyToTexture(key, *blurProfileTexture);
785     }
786 
787     return true;
788 }
789 
GrRectBlurEffect(const SkRect & rect,float sigma,GrTexture * blur_profile)790 GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma,
791                                    GrTexture *blur_profile)
792   : fRect(rect),
793     fSigma(sigma),
794     fBlurProfileAccess(blur_profile) {
795     this->initClassID<GrRectBlurEffect>();
796     this->addTextureAccess(&fBlurProfileAccess);
797     this->setWillReadFragmentPosition();
798 }
799 
~GrRectBlurEffect()800 GrRectBlurEffect::~GrRectBlurEffect() {
801 }
802 
getGLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const803 void GrRectBlurEffect::getGLProcessorKey(const GrGLSLCaps& caps,
804                                          GrProcessorKeyBuilder* b) const {
805     GrGLRectBlurEffect::GenKey(*this, caps, b);
806 }
807 
createGLInstance() const808 GrGLFragmentProcessor* GrRectBlurEffect::createGLInstance() const {
809     return SkNEW_ARGS(GrGLRectBlurEffect, (*this));
810 }
811 
onIsEqual(const GrFragmentProcessor & sBase) const812 bool GrRectBlurEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
813     const GrRectBlurEffect& s = sBase.cast<GrRectBlurEffect>();
814     return this->getSigma() == s.getSigma() && this->getRect() == s.getRect();
815 }
816 
onComputeInvariantOutput(GrInvariantOutput * inout) const817 void GrRectBlurEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
818     inout->mulByUnknownSingleComponent();
819 }
820 
821 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRectBlurEffect);
822 
TestCreate(SkRandom * random,GrContext * context,const GrDrawTargetCaps &,GrTexture **)823 GrFragmentProcessor* GrRectBlurEffect::TestCreate(SkRandom* random,
824                                                   GrContext* context,
825                                                   const GrDrawTargetCaps&,
826                                                   GrTexture**) {
827     float sigma = random->nextRangeF(3,8);
828     float width = random->nextRangeF(200,300);
829     float height = random->nextRangeF(200,300);
830     return GrRectBlurEffect::Create(context->textureProvider(), SkRect::MakeWH(width, height),
831                                     sigma);
832 }
833 
834 
directFilterMaskGPU(GrContext * context,GrRenderTarget * rt,GrPaint * grp,const GrClip & clip,const SkMatrix & viewMatrix,const SkStrokeRec & strokeRec,const SkPath & path) const835 bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext* context,
836                                                GrRenderTarget* rt,
837                                                GrPaint* grp,
838                                                const GrClip& clip,
839                                                const SkMatrix& viewMatrix,
840                                                const SkStrokeRec& strokeRec,
841                                                const SkPath& path) const {
842     if (fBlurStyle != kNormal_SkBlurStyle) {
843         return false;
844     }
845 
846     SkRect rect;
847     if (!path.isRect(&rect)) {
848         return false;
849     }
850 
851     if (!strokeRec.isFillStyle()) {
852         return false;
853     }
854 
855     SkMatrix ctm = viewMatrix;
856     SkScalar xformedSigma = this->computeXformedSigma(ctm);
857 
858     int pad=SkScalarCeilToInt(6*xformedSigma)/2;
859     rect.outset(SkIntToScalar(pad), SkIntToScalar(pad));
860 
861     SkAutoTUnref<GrFragmentProcessor> fp(GrRectBlurEffect::Create(
862         context->textureProvider(), rect, xformedSigma));
863     if (!fp) {
864         return false;
865     }
866 
867     grp->addCoverageProcessor(fp);
868 
869     SkMatrix inverse;
870     if (!viewMatrix.invert(&inverse)) {
871         return false;
872     }
873     context->drawNonAARectWithLocalMatrix(rt, clip, *grp, SkMatrix::I(), rect, inverse);
874     return true;
875 }
876 
877 class GrRRectBlurEffect : public GrFragmentProcessor {
878 public:
879 
880     static GrFragmentProcessor* Create(GrContext* context, float sigma, const SkRRect&);
881 
~GrRRectBlurEffect()882     virtual ~GrRRectBlurEffect() {};
name() const883     const char* name() const override { return "GrRRectBlur"; }
884 
getRRect() const885     const SkRRect& getRRect() const { return fRRect; }
getSigma() const886     float getSigma() const { return fSigma; }
887 
888     virtual void getGLProcessorKey(const GrGLSLCaps& caps,
889                                    GrProcessorKeyBuilder* b) const override;
890 
891     GrGLFragmentProcessor* createGLInstance() const override;
892 
893 private:
894     GrRRectBlurEffect(float sigma, const SkRRect&, GrTexture* profileTexture);
895 
896     bool onIsEqual(const GrFragmentProcessor& other) const override;
897 
898     void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
899 
900     SkRRect             fRRect;
901     float               fSigma;
902     GrTextureAccess     fNinePatchAccess;
903 
904     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
905 
906     typedef GrFragmentProcessor INHERITED;
907 };
908 
909 
Create(GrContext * context,float sigma,const SkRRect & rrect)910 GrFragmentProcessor* GrRRectBlurEffect::Create(GrContext* context, float sigma,
911                                                const SkRRect& rrect) {
912     if (!rrect.isSimpleCircular()) {
913         return NULL;
914     }
915 
916     // Make sure we can successfully ninepatch this rrect -- the blur sigma has to be
917     // sufficiently small relative to both the size of the corner radius and the
918     // width (and height) of the rrect.
919 
920     unsigned int blurRadius = 3*SkScalarCeilToInt(sigma-1/6.0f);
921     unsigned int cornerRadius = SkScalarCeilToInt(rrect.getSimpleRadii().x());
922     if (cornerRadius + blurRadius > rrect.width()/2 ||
923         cornerRadius + blurRadius > rrect.height()/2) {
924         return NULL;
925     }
926 
927     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
928     GrUniqueKey key;
929     GrUniqueKey::Builder builder(&key, kDomain, 2);
930     builder[0] = blurRadius;
931     builder[1] = cornerRadius;
932     builder.finish();
933 
934     SkAutoTUnref<GrTexture> blurNinePatchTexture(
935         context->textureProvider()->findAndRefTextureByUniqueKey(key));
936 
937     if (!blurNinePatchTexture) {
938         SkMask mask;
939 
940         unsigned int smallRectSide = 2*(blurRadius + cornerRadius) + 1;
941 
942         mask.fBounds = SkIRect::MakeWH(smallRectSide, smallRectSide);
943         mask.fFormat = SkMask::kA8_Format;
944         mask.fRowBytes = mask.fBounds.width();
945         mask.fImage = SkMask::AllocImage(mask.computeTotalImageSize());
946         SkAutoMaskFreeImage amfi(mask.fImage);
947 
948         memset(mask.fImage, 0, mask.computeTotalImageSize());
949 
950         SkRect smallRect;
951         smallRect.setWH(SkIntToScalar(smallRectSide), SkIntToScalar(smallRectSide));
952 
953         SkRRect smallRRect;
954         smallRRect.setRectXY(smallRect, SkIntToScalar(cornerRadius), SkIntToScalar(cornerRadius));
955 
956         SkPath path;
957         path.addRRect( smallRRect );
958 
959         SkDraw::DrawToMask(path, &mask.fBounds, NULL, NULL, &mask,
960                            SkMask::kJustRenderImage_CreateMode, SkPaint::kFill_Style);
961 
962         SkMask blurredMask;
963         SkBlurMask::BoxBlur(&blurredMask, mask, sigma, kNormal_SkBlurStyle, kHigh_SkBlurQuality,
964                             NULL, true );
965 
966         unsigned int texSide = smallRectSide + 2*blurRadius;
967         GrSurfaceDesc texDesc;
968         texDesc.fWidth = texSide;
969         texDesc.fHeight = texSide;
970         texDesc.fConfig = kAlpha_8_GrPixelConfig;
971 
972         blurNinePatchTexture.reset(
973             context->textureProvider()->createTexture(texDesc, true, blurredMask.fImage, 0));
974         SkMask::FreeImage(blurredMask.fImage);
975         if (!blurNinePatchTexture) {
976             return NULL;
977         }
978         context->textureProvider()->assignUniqueKeyToTexture(key, blurNinePatchTexture);
979     }
980     return SkNEW_ARGS(GrRRectBlurEffect, (sigma, rrect, blurNinePatchTexture));
981 }
982 
onComputeInvariantOutput(GrInvariantOutput * inout) const983 void GrRRectBlurEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
984     inout->mulByUnknownSingleComponent();
985 }
986 
GrRRectBlurEffect(float sigma,const SkRRect & rrect,GrTexture * ninePatchTexture)987 GrRRectBlurEffect::GrRRectBlurEffect(float sigma, const SkRRect& rrect, GrTexture *ninePatchTexture)
988     : fRRect(rrect),
989       fSigma(sigma),
990       fNinePatchAccess(ninePatchTexture) {
991     this->initClassID<GrRRectBlurEffect>();
992     this->addTextureAccess(&fNinePatchAccess);
993     this->setWillReadFragmentPosition();
994 }
995 
onIsEqual(const GrFragmentProcessor & other) const996 bool GrRRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const {
997     const GrRRectBlurEffect& rrbe = other.cast<GrRRectBlurEffect>();
998     return fRRect.getSimpleRadii().fX == rrbe.fRRect.getSimpleRadii().fX && fSigma == rrbe.fSigma;
999 }
1000 
1001 //////////////////////////////////////////////////////////////////////////////
1002 
1003 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRRectBlurEffect);
1004 
TestCreate(SkRandom * random,GrContext * context,const GrDrawTargetCaps & caps,GrTexture * [])1005 GrFragmentProcessor* GrRRectBlurEffect::TestCreate(SkRandom* random,
1006                                         GrContext* context,
1007                                         const GrDrawTargetCaps& caps,
1008                                         GrTexture*[]) {
1009     SkScalar w = random->nextRangeScalar(100.f, 1000.f);
1010     SkScalar h = random->nextRangeScalar(100.f, 1000.f);
1011     SkScalar r = random->nextRangeF(1.f, 9.f);
1012     SkScalar sigma = random->nextRangeF(1.f,10.f);
1013     SkRRect rrect;
1014     rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
1015     return GrRRectBlurEffect::Create(context, sigma, rrect);
1016 }
1017 
1018 //////////////////////////////////////////////////////////////////////////////
1019 
1020 class GrGLRRectBlurEffect : public GrGLFragmentProcessor {
1021 public:
GrGLRRectBlurEffect(const GrProcessor &)1022     GrGLRRectBlurEffect(const GrProcessor&) {}
1023 
1024     virtual void emitCode(GrGLFPBuilder*,
1025                           const GrFragmentProcessor&,
1026                           const char* outputColor,
1027                           const char* inputColor,
1028                           const TransformedCoordsArray&,
1029                           const TextureSamplerArray&) override;
1030 
1031     void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
1032 
1033 private:
1034     GrGLProgramDataManager::UniformHandle fProxyRectUniform;
1035     GrGLProgramDataManager::UniformHandle fCornerRadiusUniform;
1036     GrGLProgramDataManager::UniformHandle fBlurRadiusUniform;
1037     typedef GrGLFragmentProcessor INHERITED;
1038 };
1039 
emitCode(GrGLFPBuilder * builder,const GrFragmentProcessor &,const char * outputColor,const char * inputColor,const TransformedCoordsArray &,const TextureSamplerArray & samplers)1040 void GrGLRRectBlurEffect::emitCode(GrGLFPBuilder* builder,
1041                                    const GrFragmentProcessor&,
1042                                    const char* outputColor,
1043                                    const char* inputColor,
1044                                    const TransformedCoordsArray&,
1045                                    const TextureSamplerArray& samplers) {
1046     const char *rectName;
1047     const char *cornerRadiusName;
1048     const char *blurRadiusName;
1049 
1050     // The proxy rect has left, top, right, and bottom edges correspond to
1051     // components x, y, z, and w, respectively.
1052 
1053     fProxyRectUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1054                                             kVec4f_GrSLType,
1055                                             kDefault_GrSLPrecision,
1056                                             "proxyRect",
1057                                             &rectName);
1058     fCornerRadiusUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1059                                                kFloat_GrSLType,
1060                                                kDefault_GrSLPrecision,
1061                                                "cornerRadius",
1062                                                &cornerRadiusName);
1063     fBlurRadiusUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1064                                              kFloat_GrSLType,
1065                                               kDefault_GrSLPrecision,
1066                                               "blurRadius",
1067                                               &blurRadiusName);
1068 
1069     GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1070     const char* fragmentPos = fsBuilder->fragmentPosition();
1071 
1072     // warp the fragment position to the appropriate part of the 9patch blur texture
1073 
1074     fsBuilder->codeAppendf("\t\tvec2 rectCenter = (%s.xy + %s.zw)/2.0;\n", rectName, rectName);
1075     fsBuilder->codeAppendf("\t\tvec2 translatedFragPos = %s.xy - %s.xy;\n", fragmentPos, rectName);
1076     fsBuilder->codeAppendf("\t\tfloat threshold = %s + 2.0*%s;\n", cornerRadiusName, blurRadiusName );
1077     fsBuilder->codeAppendf("\t\tvec2 middle = %s.zw - %s.xy - 2.0*threshold;\n", rectName, rectName );
1078 
1079     fsBuilder->codeAppendf("\t\tif (translatedFragPos.x >= threshold && translatedFragPos.x < (middle.x+threshold)) {\n" );
1080     fsBuilder->codeAppendf("\t\t\ttranslatedFragPos.x = threshold;\n");
1081     fsBuilder->codeAppendf("\t\t} else if (translatedFragPos.x >= (middle.x + threshold)) {\n");
1082     fsBuilder->codeAppendf("\t\t\ttranslatedFragPos.x -= middle.x - 1.0;\n");
1083     fsBuilder->codeAppendf("\t\t}\n");
1084 
1085     fsBuilder->codeAppendf("\t\tif (translatedFragPos.y > threshold && translatedFragPos.y < (middle.y+threshold)) {\n" );
1086     fsBuilder->codeAppendf("\t\t\ttranslatedFragPos.y = threshold;\n");
1087     fsBuilder->codeAppendf("\t\t} else if (translatedFragPos.y >= (middle.y + threshold)) {\n");
1088     fsBuilder->codeAppendf("\t\t\ttranslatedFragPos.y -= middle.y - 1.0;\n");
1089     fsBuilder->codeAppendf("\t\t}\n");
1090 
1091     fsBuilder->codeAppendf("\t\tvec2 proxyDims = vec2(2.0*threshold+1.0);\n");
1092     fsBuilder->codeAppendf("\t\tvec2 texCoord = translatedFragPos / proxyDims;\n");
1093 
1094     fsBuilder->codeAppendf("\t%s = ", outputColor);
1095     fsBuilder->appendTextureLookupAndModulate(inputColor, samplers[0], "texCoord");
1096     fsBuilder->codeAppend(";\n");
1097 }
1098 
setData(const GrGLProgramDataManager & pdman,const GrProcessor & proc)1099 void GrGLRRectBlurEffect::setData(const GrGLProgramDataManager& pdman,
1100                                   const GrProcessor& proc) {
1101     const GrRRectBlurEffect& brre = proc.cast<GrRRectBlurEffect>();
1102     SkRRect rrect = brre.getRRect();
1103 
1104     float blurRadius = 3.f*SkScalarCeilToScalar(brre.getSigma()-1/6.0f);
1105     pdman.set1f(fBlurRadiusUniform, blurRadius);
1106 
1107     SkRect rect = rrect.getBounds();
1108     rect.outset(blurRadius, blurRadius);
1109     pdman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
1110 
1111     SkScalar radius = 0;
1112     SkASSERT(rrect.isSimpleCircular() || rrect.isRect());
1113     radius = rrect.getSimpleRadii().fX;
1114     pdman.set1f(fCornerRadiusUniform, radius);
1115 }
1116 
getGLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const1117 void GrRRectBlurEffect::getGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
1118     GrGLRRectBlurEffect::GenKey(*this, caps, b);
1119 }
1120 
createGLInstance() const1121 GrGLFragmentProcessor* GrRRectBlurEffect::createGLInstance() const {
1122     return SkNEW_ARGS(GrGLRRectBlurEffect, (*this));
1123 }
1124 
directFilterRRectMaskGPU(GrContext * context,GrRenderTarget * rt,GrPaint * grp,const GrClip & clip,const SkMatrix & viewMatrix,const SkStrokeRec & strokeRec,const SkRRect & rrect) const1125 bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context,
1126                                                     GrRenderTarget* rt,
1127                                                     GrPaint* grp,
1128                                                     const GrClip& clip,
1129                                                     const SkMatrix& viewMatrix,
1130                                                     const SkStrokeRec& strokeRec,
1131                                                     const SkRRect& rrect) const {
1132     if (fBlurStyle != kNormal_SkBlurStyle) {
1133         return false;
1134     }
1135 
1136     if (!strokeRec.isFillStyle()) {
1137         return false;
1138     }
1139 
1140     SkRect proxy_rect = rrect.rect();
1141     SkMatrix ctm = viewMatrix;
1142     SkScalar xformedSigma = this->computeXformedSigma(ctm);
1143     float extra=3.f*SkScalarCeilToScalar(xformedSigma-1/6.0f);
1144     proxy_rect.outset(extra, extra);
1145 
1146     SkAutoTUnref<GrFragmentProcessor> fp(GrRRectBlurEffect::Create(context, xformedSigma, rrect));
1147     if (!fp) {
1148         return false;
1149     }
1150 
1151     grp->addCoverageProcessor(fp);
1152 
1153     SkMatrix inverse;
1154     if (!viewMatrix.invert(&inverse)) {
1155         return false;
1156     }
1157     context->drawNonAARectWithLocalMatrix(rt, clip, *grp, SkMatrix::I(), proxy_rect, inverse);
1158     return true;
1159 }
1160 
canFilterMaskGPU(const SkRect & srcBounds,const SkIRect & clipBounds,const SkMatrix & ctm,SkRect * maskRect) const1161 bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds,
1162                                             const SkIRect& clipBounds,
1163                                             const SkMatrix& ctm,
1164                                             SkRect* maskRect) const {
1165     SkScalar xformedSigma = this->computeXformedSigma(ctm);
1166     if (xformedSigma <= 0) {
1167         return false;
1168     }
1169 
1170     static const SkScalar kMIN_GPU_BLUR_SIZE  = SkIntToScalar(64);
1171     static const SkScalar kMIN_GPU_BLUR_SIGMA = SkIntToScalar(32);
1172 
1173     if (srcBounds.width() <= kMIN_GPU_BLUR_SIZE &&
1174         srcBounds.height() <= kMIN_GPU_BLUR_SIZE &&
1175         xformedSigma <= kMIN_GPU_BLUR_SIGMA) {
1176         // We prefer to blur small rect with small radius via CPU.
1177         return false;
1178     }
1179 
1180     if (NULL == maskRect) {
1181         // don't need to compute maskRect
1182         return true;
1183     }
1184 
1185     float sigma3 = 3 * SkScalarToFloat(xformedSigma);
1186 
1187     SkRect clipRect = SkRect::Make(clipBounds);
1188     SkRect srcRect(srcBounds);
1189 
1190     // Outset srcRect and clipRect by 3 * sigma, to compute affected blur area.
1191     srcRect.outset(sigma3, sigma3);
1192     clipRect.outset(sigma3, sigma3);
1193     if (!srcRect.intersect(clipRect)) {
1194         srcRect.setEmpty();
1195     }
1196     *maskRect = srcRect;
1197     return true;
1198 }
1199 
filterMaskGPU(GrTexture * src,const SkMatrix & ctm,const SkRect & maskRect,GrTexture ** result,bool canOverwriteSrc) const1200 bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src,
1201                                          const SkMatrix& ctm,
1202                                          const SkRect& maskRect,
1203                                          GrTexture** result,
1204                                          bool canOverwriteSrc) const {
1205     SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
1206 
1207     GrContext* context = src->getContext();
1208 
1209     SkScalar xformedSigma = this->computeXformedSigma(ctm);
1210     SkASSERT(xformedSigma > 0);
1211 
1212     // If we're doing a normal blur, we can clobber the pathTexture in the
1213     // gaussianBlur.  Otherwise, we need to save it for later compositing.
1214     bool isNormalBlur = (kNormal_SkBlurStyle == fBlurStyle);
1215     *result = SkGpuBlurUtils::GaussianBlur(context, src, isNormalBlur && canOverwriteSrc,
1216                                            clipRect, false, xformedSigma, xformedSigma);
1217     if (NULL == *result) {
1218         return false;
1219     }
1220 
1221     if (!isNormalBlur) {
1222         GrPaint paint;
1223         SkMatrix matrix;
1224         matrix.setIDiv(src->width(), src->height());
1225         // Blend pathTexture over blurTexture.
1226         paint.addCoverageProcessor(GrSimpleTextureEffect::Create(src, matrix))->unref();
1227         if (kInner_SkBlurStyle == fBlurStyle) {
1228             // inner:  dst = dst * src
1229             paint.setCoverageSetOpXPFactory(SkRegion::kIntersect_Op);
1230         } else if (kSolid_SkBlurStyle == fBlurStyle) {
1231             // solid:  dst = src + dst - src * dst
1232             //             = src + (1 - src) * dst
1233             paint.setCoverageSetOpXPFactory(SkRegion::kUnion_Op);
1234         } else if (kOuter_SkBlurStyle == fBlurStyle) {
1235             // outer:  dst = dst * (1 - src)
1236             //             = 0 * src + (1 - src) * dst
1237             paint.setCoverageSetOpXPFactory(SkRegion::kDifference_Op);
1238         }
1239         context->drawRect((*result)->asRenderTarget(), GrClip::WideOpen(), paint, SkMatrix::I(),
1240                           clipRect);
1241     }
1242 
1243     return true;
1244 }
1245 
1246 #endif // SK_SUPPORT_GPU
1247 
1248 
1249 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const1250 void SkBlurMaskFilterImpl::toString(SkString* str) const {
1251     str->append("SkBlurMaskFilterImpl: (");
1252 
1253     str->append("sigma: ");
1254     str->appendScalar(fSigma);
1255     str->append(" ");
1256 
1257     static const char* gStyleName[kLastEnum_SkBlurStyle + 1] = {
1258         "normal", "solid", "outer", "inner"
1259     };
1260 
1261     str->appendf("style: %s ", gStyleName[fBlurStyle]);
1262     str->append("flags: (");
1263     if (fBlurFlags) {
1264         bool needSeparator = false;
1265         SkAddFlagToString(str,
1266                           SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag),
1267                           "IgnoreXform", &needSeparator);
1268         SkAddFlagToString(str,
1269                           SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag),
1270                           "HighQuality", &needSeparator);
1271     } else {
1272         str->append("None");
1273     }
1274     str->append("))");
1275 }
1276 #endif
1277 
1278 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
1279     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
1280 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
1281