• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GrEffect.h"
24 #include "gl/GrGLEffect.h"
25 #include "effects/GrSimpleTextureEffect.h"
26 #include "GrTBackendEffectFactory.h"
27 #include "SkGrPixelRef.h"
28 #include "SkDraw.h"
29 #endif
30 
ConvertRadiusToSigma(SkScalar radius)31 SkScalar SkBlurMaskFilter::ConvertRadiusToSigma(SkScalar radius) {
32     return SkBlurMask::ConvertRadiusToSigma(radius);
33 }
34 
35 class SkBlurMaskFilterImpl : public SkMaskFilter {
36 public:
37     SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle, uint32_t flags);
38 
39     // overrides from SkMaskFilter
40     virtual SkMask::Format getFormat() const SK_OVERRIDE;
41     virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
42                             SkIPoint* margin) const SK_OVERRIDE;
43 
44 #if SK_SUPPORT_GPU
45     virtual bool canFilterMaskGPU(const SkRect& devBounds,
46                                   const SkIRect& clipBounds,
47                                   const SkMatrix& ctm,
48                                   SkRect* maskRect) const SK_OVERRIDE;
49     virtual bool directFilterMaskGPU(GrContext* context,
50                                      GrPaint* grp,
51                                      const SkStrokeRec& strokeRec,
52                                      const SkPath& path) const SK_OVERRIDE;
53     virtual bool directFilterRRectMaskGPU(GrContext* context,
54                                           GrPaint* grp,
55                                           const SkStrokeRec& strokeRec,
56                                           const SkRRect& rrect) const SK_OVERRIDE;
57 
58     virtual bool filterMaskGPU(GrTexture* src,
59                                const SkMatrix& ctm,
60                                const SkRect& maskRect,
61                                GrTexture** result,
62                                bool canOverwriteSrc) const SK_OVERRIDE;
63 #endif
64 
65     virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE;
66     virtual bool asABlur(BlurRec*) const SK_OVERRIDE;
67 
68     SK_TO_STRING_OVERRIDE()
69     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)
70 
71 protected:
72     virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMatrix&,
73                                            const SkIRect& clipBounds,
74                                            NinePatch*) const SK_OVERRIDE;
75 
76     virtual FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&,
77                                            const SkIRect& clipBounds,
78                                            NinePatch*) const SK_OVERRIDE;
79 
80     bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix,
81                         SkIPoint* margin, SkMask::CreateMode createMode) const;
82     bool filterRRectMask(SkMask* dstM, const SkRRect& r, const SkMatrix& matrix,
83                         SkIPoint* margin, SkMask::CreateMode createMode) const;
84 
85 private:
86     // To avoid unseemly allocation requests (esp. for finite platforms like
87     // handset) we limit the radius so something manageable. (as opposed to
88     // a request like 10,000)
89     static const SkScalar kMAX_BLUR_SIGMA;
90 
91     SkScalar    fSigma;
92     SkBlurStyle fBlurStyle;
93     uint32_t    fBlurFlags;
94 
getQuality() const95     SkBlurQuality getQuality() const {
96         return (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
97                 kHigh_SkBlurQuality : kLow_SkBlurQuality;
98     }
99 
100     SkBlurMaskFilterImpl(SkReadBuffer&);
101     virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
102 
computeXformedSigma(const SkMatrix & ctm) const103     SkScalar computeXformedSigma(const SkMatrix& ctm) const {
104         bool ignoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
105 
106         SkScalar xformedSigma = ignoreTransform ? fSigma : ctm.mapRadius(fSigma);
107         return SkMinScalar(xformedSigma, kMAX_BLUR_SIGMA);
108     }
109 
110     typedef SkMaskFilter INHERITED;
111 };
112 
113 const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_SIGMA = SkIntToScalar(128);
114 
Create(SkBlurStyle style,SkScalar sigma,uint32_t flags)115 SkMaskFilter* SkBlurMaskFilter::Create(SkBlurStyle style, SkScalar sigma, uint32_t flags) {
116     if (!SkScalarIsFinite(sigma) || sigma <= 0) {
117         return NULL;
118     }
119     if ((unsigned)style > (unsigned)kLastEnum_SkBlurStyle) {
120         return NULL;
121     }
122     if (flags > SkBlurMaskFilter::kAll_BlurFlag) {
123         return NULL;
124     }
125     return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags));
126 }
127 
128 ///////////////////////////////////////////////////////////////////////////////
129 
SkBlurMaskFilterImpl(SkScalar sigma,SkBlurStyle style,uint32_t flags)130 SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle style, uint32_t flags)
131     : fSigma(sigma)
132     , fBlurStyle(style)
133     , fBlurFlags(flags) {
134     SkASSERT(fSigma > 0);
135     SkASSERT((unsigned)style <= kLastEnum_SkBlurStyle);
136     SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
137 }
138 
getFormat() const139 SkMask::Format SkBlurMaskFilterImpl::getFormat() const {
140     return SkMask::kA8_Format;
141 }
142 
asABlur(BlurRec * rec) const143 bool SkBlurMaskFilterImpl::asABlur(BlurRec* rec) const {
144     if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
145         return false;
146     }
147 
148     if (rec) {
149         rec->fSigma = fSigma;
150         rec->fStyle = fBlurStyle;
151         rec->fQuality = this->getQuality();
152     }
153     return true;
154 }
155 
filterMask(SkMask * dst,const SkMask & src,const SkMatrix & matrix,SkIPoint * margin) const156 bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
157                                       const SkMatrix& matrix,
158                                       SkIPoint* margin) const{
159     SkScalar sigma = this->computeXformedSigma(matrix);
160     return SkBlurMask::BoxBlur(dst, src, sigma, fBlurStyle, this->getQuality(), margin);
161 }
162 
filterRectMask(SkMask * dst,const SkRect & r,const SkMatrix & matrix,SkIPoint * margin,SkMask::CreateMode createMode) const163 bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
164                                           const SkMatrix& matrix,
165                                           SkIPoint* margin, SkMask::CreateMode createMode) const{
166     SkScalar sigma = computeXformedSigma(matrix);
167 
168     return SkBlurMask::BlurRect(sigma, dst, r, fBlurStyle,
169                                 margin, createMode);
170 }
171 
filterRRectMask(SkMask * dst,const SkRRect & r,const SkMatrix & matrix,SkIPoint * margin,SkMask::CreateMode createMode) const172 bool SkBlurMaskFilterImpl::filterRRectMask(SkMask* dst, const SkRRect& r,
173                                           const SkMatrix& matrix,
174                                           SkIPoint* margin, SkMask::CreateMode createMode) const{
175     SkScalar sigma = computeXformedSigma(matrix);
176 
177     return SkBlurMask::BlurRRect(sigma, dst, r, fBlurStyle,
178                                 margin, createMode);
179 }
180 
181 #include "SkCanvas.h"
182 
prepare_to_draw_into_mask(const SkRect & bounds,SkMask * mask)183 static bool prepare_to_draw_into_mask(const SkRect& bounds, SkMask* mask) {
184     SkASSERT(mask != NULL);
185 
186     bounds.roundOut(&mask->fBounds);
187     mask->fRowBytes = SkAlign4(mask->fBounds.width());
188     mask->fFormat = SkMask::kA8_Format;
189     const size_t size = mask->computeImageSize();
190     mask->fImage = SkMask::AllocImage(size);
191     if (NULL == mask->fImage) {
192         return false;
193     }
194 
195     // FIXME: use sk_calloc in AllocImage?
196     sk_bzero(mask->fImage, size);
197     return true;
198 }
199 
draw_rrect_into_mask(const SkRRect rrect,SkMask * mask)200 static bool draw_rrect_into_mask(const SkRRect rrect, SkMask* mask) {
201     if (!prepare_to_draw_into_mask(rrect.rect(), mask)) {
202         return false;
203     }
204 
205     // FIXME: This code duplicates code in draw_rects_into_mask, below. Is there a
206     // clean way to share more code?
207     SkBitmap bitmap;
208     bitmap.installMaskPixels(*mask);
209 
210     SkCanvas canvas(bitmap);
211     canvas.translate(-SkIntToScalar(mask->fBounds.left()),
212                      -SkIntToScalar(mask->fBounds.top()));
213 
214     SkPaint paint;
215     paint.setAntiAlias(true);
216     canvas.drawRRect(rrect, paint);
217     return true;
218 }
219 
draw_rects_into_mask(const SkRect rects[],int count,SkMask * mask)220 static bool draw_rects_into_mask(const SkRect rects[], int count, SkMask* mask) {
221     if (!prepare_to_draw_into_mask(rects[0], mask)) {
222         return false;
223     }
224 
225     SkBitmap bitmap;
226     bitmap.installPixels(SkImageInfo::Make(mask->fBounds.width(),
227                                            mask->fBounds.height(),
228                                            kAlpha_8_SkColorType,
229                                            kPremul_SkAlphaType),
230                          mask->fImage, mask->fRowBytes);
231 
232     SkCanvas canvas(bitmap);
233     canvas.translate(-SkIntToScalar(mask->fBounds.left()),
234                      -SkIntToScalar(mask->fBounds.top()));
235 
236     SkPaint paint;
237     paint.setAntiAlias(true);
238 
239     if (1 == count) {
240         canvas.drawRect(rects[0], paint);
241     } else {
242         // todo: do I need a fast way to do this?
243         SkPath path;
244         path.addRect(rects[0]);
245         path.addRect(rects[1]);
246         path.setFillType(SkPath::kEvenOdd_FillType);
247         canvas.drawPath(path, paint);
248     }
249     return true;
250 }
251 
rect_exceeds(const SkRect & r,SkScalar v)252 static bool rect_exceeds(const SkRect& r, SkScalar v) {
253     return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v ||
254            r.width() > v || r.height() > v;
255 }
256 
257 #ifdef SK_IGNORE_FAST_RRECT_BLUR
258 SK_CONF_DECLARE( bool, c_analyticBlurRRect, "mask.filter.blur.analyticblurrrect", false, "Use the faster analytic blur approach for ninepatch rects" );
259 #else
260 SK_CONF_DECLARE( bool, c_analyticBlurRRect, "mask.filter.blur.analyticblurrrect", true, "Use the faster analytic blur approach for ninepatch round rects" );
261 #endif
262 
263 SkMaskFilter::FilterReturn
filterRRectToNine(const SkRRect & rrect,const SkMatrix & matrix,const SkIRect & clipBounds,NinePatch * patch) const264 SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& matrix,
265                                         const SkIRect& clipBounds,
266                                         NinePatch* patch) const {
267     SkASSERT(patch != NULL);
268     switch (rrect.getType()) {
269         case SkRRect::kUnknown_Type:
270             // Unknown should never be returned.
271             SkASSERT(false);
272             // Fall through.
273         case SkRRect::kEmpty_Type:
274             // Nothing to draw.
275             return kFalse_FilterReturn;
276 
277         case SkRRect::kRect_Type:
278             // We should have caught this earlier.
279             SkASSERT(false);
280             // Fall through.
281         case SkRRect::kOval_Type:
282             // The nine patch special case does not handle ovals, and we
283             // already have code for rectangles.
284             return kUnimplemented_FilterReturn;
285 
286         // These three can take advantage of this fast path.
287         case SkRRect::kSimple_Type:
288         case SkRRect::kNinePatch_Type:
289         case SkRRect::kComplex_Type:
290             break;
291     }
292 
293     // TODO: report correct metrics for innerstyle, where we do not grow the
294     // total bounds, but we do need an inset the size of our blur-radius
295     if (kInner_SkBlurStyle == fBlurStyle) {
296         return kUnimplemented_FilterReturn;
297     }
298 
299     // TODO: take clipBounds into account to limit our coordinates up front
300     // for now, just skip too-large src rects (to take the old code path).
301     if (rect_exceeds(rrect.rect(), SkIntToScalar(32767))) {
302         return kUnimplemented_FilterReturn;
303     }
304 
305     SkIPoint margin;
306     SkMask  srcM, dstM;
307     rrect.rect().roundOut(&srcM.fBounds);
308     srcM.fImage = NULL;
309     srcM.fFormat = SkMask::kA8_Format;
310     srcM.fRowBytes = 0;
311 
312     bool filterResult = false;
313     if (c_analyticBlurRRect) {
314         // special case for fast round rect blur
315         // don't actually do the blur the first time, just compute the correct size
316         filterResult = this->filterRRectMask(&dstM, rrect, matrix, &margin,
317                                             SkMask::kJustComputeBounds_CreateMode);
318     }
319 
320     if (!filterResult) {
321         filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
322     }
323 
324     if (!filterResult) {
325         return kFalse_FilterReturn;
326     }
327 
328     // Now figure out the appropriate width and height of the smaller round rectangle
329     // to stretch. It will take into account the larger radius per side as well as double
330     // the margin, to account for inner and outer blur.
331     const SkVector& UL = rrect.radii(SkRRect::kUpperLeft_Corner);
332     const SkVector& UR = rrect.radii(SkRRect::kUpperRight_Corner);
333     const SkVector& LR = rrect.radii(SkRRect::kLowerRight_Corner);
334     const SkVector& LL = rrect.radii(SkRRect::kLowerLeft_Corner);
335 
336     const SkScalar leftUnstretched = SkTMax(UL.fX, LL.fX) + SkIntToScalar(2 * margin.fX);
337     const SkScalar rightUnstretched = SkTMax(UR.fX, LR.fX) + SkIntToScalar(2 * margin.fX);
338 
339     // Extra space in the middle to ensure an unchanging piece for stretching. Use 3 to cover
340     // any fractional space on either side plus 1 for the part to stretch.
341     const SkScalar stretchSize = SkIntToScalar(3);
342 
343     const SkScalar totalSmallWidth = leftUnstretched + rightUnstretched + stretchSize;
344     if (totalSmallWidth >= rrect.rect().width()) {
345         // There is no valid piece to stretch.
346         return kUnimplemented_FilterReturn;
347     }
348 
349     const SkScalar topUnstretched = SkTMax(UL.fY, UR.fY) + SkIntToScalar(2 * margin.fY);
350     const SkScalar bottomUnstretched = SkTMax(LL.fY, LR.fY) + SkIntToScalar(2 * margin.fY);
351 
352     const SkScalar totalSmallHeight = topUnstretched + bottomUnstretched + stretchSize;
353     if (totalSmallHeight >= rrect.rect().height()) {
354         // There is no valid piece to stretch.
355         return kUnimplemented_FilterReturn;
356     }
357 
358     SkRect smallR = SkRect::MakeWH(totalSmallWidth, totalSmallHeight);
359 
360     SkRRect smallRR;
361     SkVector radii[4];
362     radii[SkRRect::kUpperLeft_Corner] = UL;
363     radii[SkRRect::kUpperRight_Corner] = UR;
364     radii[SkRRect::kLowerRight_Corner] = LR;
365     radii[SkRRect::kLowerLeft_Corner] = LL;
366     smallRR.setRectRadii(smallR, radii);
367 
368     bool analyticBlurWorked = false;
369     if (c_analyticBlurRRect) {
370         analyticBlurWorked =
371             this->filterRRectMask(&patch->fMask, smallRR, matrix, &margin,
372                                   SkMask::kComputeBoundsAndRenderImage_CreateMode);
373     }
374 
375     if (!analyticBlurWorked) {
376         if (!draw_rrect_into_mask(smallRR, &srcM)) {
377             return kFalse_FilterReturn;
378         }
379 
380         SkAutoMaskFreeImage amf(srcM.fImage);
381 
382         if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
383             return kFalse_FilterReturn;
384         }
385     }
386 
387     patch->fMask.fBounds.offsetTo(0, 0);
388     patch->fOuterRect = dstM.fBounds;
389     patch->fCenter.fX = SkScalarCeilToInt(leftUnstretched) + 1;
390     patch->fCenter.fY = SkScalarCeilToInt(topUnstretched) + 1;
391     return kTrue_FilterReturn;
392 }
393 
394 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", true, "Use the faster analytic blur approach for ninepatch rects" );
395 
396 SkMaskFilter::FilterReturn
filterRectsToNine(const SkRect rects[],int count,const SkMatrix & matrix,const SkIRect & clipBounds,NinePatch * patch) const397 SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
398                                         const SkMatrix& matrix,
399                                         const SkIRect& clipBounds,
400                                         NinePatch* patch) const {
401     if (count < 1 || count > 2) {
402         return kUnimplemented_FilterReturn;
403     }
404 
405     // TODO: report correct metrics for innerstyle, where we do not grow the
406     // total bounds, but we do need an inset the size of our blur-radius
407     if (kInner_SkBlurStyle == fBlurStyle || kOuter_SkBlurStyle == fBlurStyle) {
408         return kUnimplemented_FilterReturn;
409     }
410 
411     // TODO: take clipBounds into account to limit our coordinates up front
412     // for now, just skip too-large src rects (to take the old code path).
413     if (rect_exceeds(rects[0], SkIntToScalar(32767))) {
414         return kUnimplemented_FilterReturn;
415     }
416 
417     SkIPoint margin;
418     SkMask  srcM, dstM;
419     rects[0].roundOut(&srcM.fBounds);
420     srcM.fImage = NULL;
421     srcM.fFormat = SkMask::kA8_Format;
422     srcM.fRowBytes = 0;
423 
424     bool filterResult = false;
425     if (count == 1 && c_analyticBlurNinepatch) {
426         // special case for fast rect blur
427         // don't actually do the blur the first time, just compute the correct size
428         filterResult = this->filterRectMask(&dstM, rects[0], matrix, &margin,
429                                             SkMask::kJustComputeBounds_CreateMode);
430     } else {
431         filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
432     }
433 
434     if (!filterResult) {
435         return kFalse_FilterReturn;
436     }
437 
438     /*
439      *  smallR is the smallest version of 'rect' that will still guarantee that
440      *  we get the same blur results on all edges, plus 1 center row/col that is
441      *  representative of the extendible/stretchable edges of the ninepatch.
442      *  Since our actual edge may be fractional we inset 1 more to be sure we
443      *  don't miss any interior blur.
444      *  x is an added pixel of blur, and { and } are the (fractional) edge
445      *  pixels from the original rect.
446      *
447      *   x x { x x .... x x } x x
448      *
449      *  Thus, in this case, we inset by a total of 5 (on each side) beginning
450      *  with our outer-rect (dstM.fBounds)
451      */
452     SkRect smallR[2];
453     SkIPoint center;
454 
455     // +2 is from +1 for each edge (to account for possible fractional edges
456     int smallW = dstM.fBounds.width() - srcM.fBounds.width() + 2;
457     int smallH = dstM.fBounds.height() - srcM.fBounds.height() + 2;
458     SkIRect innerIR;
459 
460     if (1 == count) {
461         innerIR = srcM.fBounds;
462         center.set(smallW, smallH);
463     } else {
464         SkASSERT(2 == count);
465         rects[1].roundIn(&innerIR);
466         center.set(smallW + (innerIR.left() - srcM.fBounds.left()),
467                    smallH + (innerIR.top() - srcM.fBounds.top()));
468     }
469 
470     // +1 so we get a clean, stretchable, center row/col
471     smallW += 1;
472     smallH += 1;
473 
474     // we want the inset amounts to be integral, so we don't change any
475     // fractional phase on the fRight or fBottom of our smallR.
476     const SkScalar dx = SkIntToScalar(innerIR.width() - smallW);
477     const SkScalar dy = SkIntToScalar(innerIR.height() - smallH);
478     if (dx < 0 || dy < 0) {
479         // we're too small, relative to our blur, to break into nine-patch,
480         // so we ask to have our normal filterMask() be called.
481         return kUnimplemented_FilterReturn;
482     }
483 
484     smallR[0].set(rects[0].left(), rects[0].top(), rects[0].right() - dx, rects[0].bottom() - dy);
485     if (smallR[0].width() < 2 || smallR[0].height() < 2) {
486         return kUnimplemented_FilterReturn;
487     }
488     if (2 == count) {
489         smallR[1].set(rects[1].left(), rects[1].top(),
490                       rects[1].right() - dx, rects[1].bottom() - dy);
491         SkASSERT(!smallR[1].isEmpty());
492     }
493 
494     if (count > 1 || !c_analyticBlurNinepatch) {
495         if (!draw_rects_into_mask(smallR, count, &srcM)) {
496             return kFalse_FilterReturn;
497         }
498 
499         SkAutoMaskFreeImage amf(srcM.fImage);
500 
501         if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
502             return kFalse_FilterReturn;
503         }
504     } else {
505         if (!this->filterRectMask(&patch->fMask, smallR[0], matrix, &margin,
506                                   SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
507             return kFalse_FilterReturn;
508         }
509     }
510     patch->fMask.fBounds.offsetTo(0, 0);
511     patch->fOuterRect = dstM.fBounds;
512     patch->fCenter = center;
513     return kTrue_FilterReturn;
514 }
515 
computeFastBounds(const SkRect & src,SkRect * dst) const516 void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
517                                              SkRect* dst) const {
518     SkScalar pad = 3.0f * fSigma;
519 
520     dst->set(src.fLeft  - pad, src.fTop    - pad,
521              src.fRight + pad, src.fBottom + pad);
522 }
523 
SkBlurMaskFilterImpl(SkReadBuffer & buffer)524 SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkReadBuffer& buffer)
525         : SkMaskFilter(buffer) {
526     fSigma = buffer.readScalar();
527     fBlurStyle = (SkBlurStyle)buffer.readInt();
528     fBlurFlags = buffer.readUInt() & SkBlurMaskFilter::kAll_BlurFlag;
529     SkASSERT(fSigma > 0);
530     SkASSERT((unsigned)fBlurStyle <= kLastEnum_SkBlurStyle);
531 }
532 
flatten(SkWriteBuffer & buffer) const533 void SkBlurMaskFilterImpl::flatten(SkWriteBuffer& buffer) const {
534     this->INHERITED::flatten(buffer);
535     buffer.writeScalar(fSigma);
536     buffer.writeInt(fBlurStyle);
537     buffer.writeUInt(fBlurFlags);
538 }
539 
540 #if SK_SUPPORT_GPU
541 
542 class GrGLRectBlurEffect;
543 
544 class GrRectBlurEffect : public GrEffect {
545 public:
546     virtual ~GrRectBlurEffect();
547 
Name()548     static const char* Name() { return "RectBlur"; }
549 
550     typedef GrGLRectBlurEffect GLEffect;
551 
552     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
553     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
554 
555     /**
556      * Create a simple filter effect with custom bicubic coefficients.
557      */
Create(GrContext * context,const SkRect & rect,float sigma)558     static GrEffectRef* Create(GrContext *context, const SkRect& rect,
559                                float sigma) {
560         GrTexture *blurProfileTexture = NULL;
561         int doubleProfileSize = SkScalarCeilToInt(12*sigma);
562 
563         if (doubleProfileSize >= rect.width() || doubleProfileSize >= rect.height()) {
564             // if the blur sigma is too large so the gaussian overlaps the whole
565             // rect in either direction, fall back to CPU path for now.
566 
567             return NULL;
568         }
569 
570         bool createdBlurProfileTexture = CreateBlurProfileTexture(context, sigma, &blurProfileTexture);
571         SkAutoTUnref<GrTexture> hunref(blurProfileTexture);
572         if (!createdBlurProfileTexture) {
573            return NULL;
574         }
575         AutoEffectUnref effect(SkNEW_ARGS(GrRectBlurEffect, (rect, sigma, blurProfileTexture)));
576         return CreateEffectRef(effect);
577     }
578 
getRect() const579     const SkRect& getRect() const { return fRect; }
getSigma() const580     float getSigma() const { return fSigma; }
581 
582 private:
583     GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blur_profile);
584     virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
585 
586     static bool CreateBlurProfileTexture(GrContext *context, float sigma,
587                                        GrTexture **blurProfileTexture);
588 
589     SkRect          fRect;
590     float           fSigma;
591     GrTextureAccess fBlurProfileAccess;
592 
593     GR_DECLARE_EFFECT_TEST;
594 
595     typedef GrEffect INHERITED;
596 };
597 
598 class GrGLRectBlurEffect : public GrGLEffect {
599 public:
600     GrGLRectBlurEffect(const GrBackendEffectFactory& factory,
601                       const GrDrawEffect&);
602     virtual void emitCode(GrGLShaderBuilder*,
603                           const GrDrawEffect&,
604                           EffectKey,
605                           const char* outputColor,
606                           const char* inputColor,
607                           const TransformedCoordsArray&,
608                           const TextureSamplerArray&) SK_OVERRIDE;
609 
610     virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
611 
612 private:
613     typedef GrGLUniformManager::UniformHandle        UniformHandle;
614 
615     UniformHandle       fProxyRectUniform;
616     UniformHandle       fProfileSizeUniform;
617 
618     typedef GrGLEffect INHERITED;
619 };
620 
621 
622 
GrGLRectBlurEffect(const GrBackendEffectFactory & factory,const GrDrawEffect &)623 GrGLRectBlurEffect::GrGLRectBlurEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
624     : INHERITED(factory) {
625 }
626 
OutputRectBlurProfileLookup(GrGLShaderBuilder * builder,const GrGLShaderBuilder::TextureSampler & sampler,const char * output,const char * profileSize,const char * loc,const char * blurred_width,const char * sharp_width)627 void OutputRectBlurProfileLookup(GrGLShaderBuilder* builder,
628                                  const GrGLShaderBuilder::TextureSampler& sampler,
629                                  const char *output,
630                                  const char *profileSize, const char *loc,
631                                  const char *blurred_width,
632                                  const char *sharp_width) {
633     builder->fsCodeAppendf("\tfloat %s;\n", output);
634     builder->fsCodeAppendf("\t\t{\n");
635     builder->fsCodeAppendf("\t\t\tfloat coord = (0.5 * (abs(2.0*%s - %s) - %s))/%s;\n",
636                            loc, blurred_width, sharp_width, profileSize);
637     builder->fsCodeAppendf("\t\t\t%s = ", output);
638     builder->fsAppendTextureLookup(sampler, "vec2(coord,0.5)");
639     builder->fsCodeAppend(".a;\n");
640     builder->fsCodeAppendf("\t\t}\n");
641 }
642 
emitCode(GrGLShaderBuilder * builder,const GrDrawEffect &,EffectKey key,const char * outputColor,const char * inputColor,const TransformedCoordsArray & coords,const TextureSamplerArray & samplers)643 void GrGLRectBlurEffect::emitCode(GrGLShaderBuilder* builder,
644                                  const GrDrawEffect&,
645                                  EffectKey key,
646                                  const char* outputColor,
647                                  const char* inputColor,
648                                  const TransformedCoordsArray& coords,
649                                  const TextureSamplerArray& samplers) {
650 
651     const char *rectName;
652     const char *profileSizeName;
653 
654     fProxyRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
655                                             kVec4f_GrSLType,
656                                             "proxyRect",
657                                             &rectName);
658     fProfileSizeUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
659                                             kFloat_GrSLType,
660                                             "profileSize",
661                                             &profileSizeName);
662 
663     const char *fragmentPos = builder->fragmentPosition();
664 
665     if (inputColor) {
666         builder->fsCodeAppendf("\tvec4 src=%s;\n", inputColor);
667     } else {
668         builder->fsCodeAppendf("\tvec4 src=vec4(1)\n;");
669     }
670 
671     builder->fsCodeAppendf("\tvec2 translatedPos = %s.xy - %s.xy;\n", fragmentPos, rectName );
672     builder->fsCodeAppendf("\tfloat width = %s.z - %s.x;\n", rectName, rectName);
673     builder->fsCodeAppendf("\tfloat height = %s.w - %s.y;\n", rectName, rectName);
674 
675     builder->fsCodeAppendf("\tvec2 smallDims = vec2(width - %s, height-%s);\n", profileSizeName, profileSizeName);
676     builder->fsCodeAppendf("\tfloat center = 2.0 * floor(%s/2.0 + .25) - 1.0;\n", profileSizeName);
677     builder->fsCodeAppendf("\tvec2 wh = smallDims - vec2(center,center);\n");
678 
679     OutputRectBlurProfileLookup(builder, samplers[0], "horiz_lookup", profileSizeName, "translatedPos.x", "width", "wh.x");
680     OutputRectBlurProfileLookup(builder, samplers[0], "vert_lookup", profileSizeName, "translatedPos.y", "height", "wh.y");
681 
682     builder->fsCodeAppendf("\tfloat final = horiz_lookup * vert_lookup;\n");
683     builder->fsCodeAppendf("\t%s = src * vec4(final);\n", outputColor );
684 }
685 
setData(const GrGLUniformManager & uman,const GrDrawEffect & drawEffect)686 void GrGLRectBlurEffect::setData(const GrGLUniformManager& uman,
687                                  const GrDrawEffect& drawEffect) {
688     const GrRectBlurEffect& rbe = drawEffect.castEffect<GrRectBlurEffect>();
689     SkRect rect = rbe.getRect();
690 
691     uman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
692     uman.set1f(fProfileSizeUniform, SkScalarCeilToScalar(6*rbe.getSigma()));
693 }
694 
CreateBlurProfileTexture(GrContext * context,float sigma,GrTexture ** blurProfileTexture)695 bool GrRectBlurEffect::CreateBlurProfileTexture(GrContext *context, float sigma,
696                                               GrTexture **blurProfileTexture) {
697     GrTextureParams params;
698     GrTextureDesc texDesc;
699 
700     unsigned int profile_size = SkScalarCeilToInt(6*sigma);
701 
702     texDesc.fWidth = profile_size;
703     texDesc.fHeight = 1;
704     texDesc.fConfig = kAlpha_8_GrPixelConfig;
705 
706     static const GrCacheID::Domain gBlurProfileDomain = GrCacheID::GenerateDomain();
707     GrCacheID::Key key;
708     memset(&key, 0, sizeof(key));
709     key.fData32[0] = profile_size;
710     key.fData32[1] = 1;
711     GrCacheID blurProfileKey(gBlurProfileDomain, key);
712 
713     uint8_t *profile = NULL;
714     SkAutoTDeleteArray<uint8_t> ada(NULL);
715 
716     *blurProfileTexture = context->findAndRefTexture(texDesc, blurProfileKey, &params);
717 
718     if (NULL == *blurProfileTexture) {
719 
720         SkBlurMask::ComputeBlurProfile(sigma, &profile);
721         ada.reset(profile);
722 
723         *blurProfileTexture = context->createTexture(&params, texDesc, blurProfileKey,
724                                                      profile, 0);
725 
726         if (NULL == *blurProfileTexture) {
727             return false;
728         }
729     }
730 
731     return true;
732 }
733 
GrRectBlurEffect(const SkRect & rect,float sigma,GrTexture * blur_profile)734 GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma,
735                                    GrTexture *blur_profile)
736   : INHERITED(),
737     fRect(rect),
738     fSigma(sigma),
739     fBlurProfileAccess(blur_profile) {
740     this->addTextureAccess(&fBlurProfileAccess);
741     this->setWillReadFragmentPosition();
742 }
743 
~GrRectBlurEffect()744 GrRectBlurEffect::~GrRectBlurEffect() {
745 }
746 
getFactory() const747 const GrBackendEffectFactory& GrRectBlurEffect::getFactory() const {
748     return GrTBackendEffectFactory<GrRectBlurEffect>::getInstance();
749 }
750 
onIsEqual(const GrEffect & sBase) const751 bool GrRectBlurEffect::onIsEqual(const GrEffect& sBase) const {
752     const GrRectBlurEffect& s = CastEffect<GrRectBlurEffect>(sBase);
753     return this->getSigma() == s.getSigma() && this->getRect() == s.getRect();
754 }
755 
getConstantColorComponents(GrColor * color,uint32_t * validFlags) const756 void GrRectBlurEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
757     *validFlags = 0;
758     return;
759 }
760 
761 GR_DEFINE_EFFECT_TEST(GrRectBlurEffect);
762 
TestCreate(SkRandom * random,GrContext * context,const GrDrawTargetCaps &,GrTexture **)763 GrEffectRef* GrRectBlurEffect::TestCreate(SkRandom* random,
764                                          GrContext* context,
765                                          const GrDrawTargetCaps&,
766                                          GrTexture**) {
767     float sigma = random->nextRangeF(3,8);
768     float width = random->nextRangeF(200,300);
769     float height = random->nextRangeF(200,300);
770     return GrRectBlurEffect::Create(context, SkRect::MakeWH(width, height), sigma);
771 }
772 
773 
directFilterMaskGPU(GrContext * context,GrPaint * grp,const SkStrokeRec & strokeRec,const SkPath & path) const774 bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext* context,
775                                                GrPaint* grp,
776                                                const SkStrokeRec& strokeRec,
777                                                const SkPath& path) const {
778     if (fBlurStyle != kNormal_SkBlurStyle) {
779         return false;
780     }
781 
782     SkRect rect;
783     if (!path.isRect(&rect)) {
784         return false;
785     }
786 
787     if (!strokeRec.isFillStyle()) {
788         return false;
789     }
790 
791     SkMatrix ctm = context->getMatrix();
792     SkScalar xformedSigma = this->computeXformedSigma(ctm);
793 
794     int pad=SkScalarCeilToInt(6*xformedSigma)/2;
795     rect.outset(SkIntToScalar(pad), SkIntToScalar(pad));
796 
797     SkAutoTUnref<GrEffectRef> effect(GrRectBlurEffect::Create(
798             context, rect, xformedSigma));
799     if (!effect) {
800         return false;
801     }
802 
803     GrContext::AutoMatrix am;
804     if (!am.setIdentity(context, grp)) {
805        return false;
806     }
807 
808     grp->addCoverageEffect(effect);
809 
810     context->drawRect(*grp, rect);
811     return true;
812 }
813 
814 class GrGLRRectBlurEffect;
815 
816 class GrRRectBlurEffect : public GrEffect {
817 public:
818 
819     static GrEffectRef* Create(GrContext* context, float sigma, const SkRRect&);
820 
~GrRRectBlurEffect()821     virtual ~GrRRectBlurEffect() {};
Name()822     static const char* Name() { return "GrRRectBlur"; }
823 
getRRect() const824     const SkRRect& getRRect() const { return fRRect; }
getSigma() const825     float getSigma() const { return fSigma; }
826 
827     typedef GrGLRRectBlurEffect GLEffect;
828 
829     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
830 
831     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
832 
833 private:
834     GrRRectBlurEffect(float sigma, const SkRRect&, GrTexture* profileTexture);
835 
836     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
837 
838     SkRRect             fRRect;
839     float               fSigma;
840     GrTextureAccess     fNinePatchAccess;
841 
842     GR_DECLARE_EFFECT_TEST;
843 
844     typedef GrEffect INHERITED;
845 };
846 
847 
Create(GrContext * context,float sigma,const SkRRect & rrect)848 GrEffectRef* GrRRectBlurEffect::Create(GrContext* context, float sigma, const SkRRect& rrect) {
849     if (!rrect.isSimpleCircular()) {
850         return NULL;
851     }
852 
853     // Make sure we can successfully ninepatch this rrect -- the blur sigma has to be
854     // sufficiently small relative to both the size of the corner radius and the
855     // width (and height) of the rrect.
856 
857     unsigned int blurRadius = 3*SkScalarCeilToInt(sigma-1/6.0f);
858     unsigned int cornerRadius = SkScalarCeilToInt(rrect.getSimpleRadii().x());
859     if (cornerRadius + blurRadius > rrect.width()/2 ||
860         cornerRadius + blurRadius > rrect.height()/2) {
861         return NULL;
862     }
863 
864     static const GrCacheID::Domain gRRectBlurDomain = GrCacheID::GenerateDomain();
865     GrCacheID::Key key;
866     memset(&key, 0, sizeof(key));
867     key.fData32[0] = blurRadius;
868     key.fData32[1] = cornerRadius;
869     GrCacheID blurRRectNinePatchID(gRRectBlurDomain, key);
870 
871     GrTextureParams params;
872     params.setFilterMode(GrTextureParams::kBilerp_FilterMode);
873 
874     unsigned int smallRectSide = 2*(blurRadius + cornerRadius) + 1;
875     unsigned int texSide = smallRectSide + 2*blurRadius;
876     GrTextureDesc texDesc;
877     texDesc.fWidth = texSide;
878     texDesc.fHeight = texSide;
879     texDesc.fConfig = kAlpha_8_GrPixelConfig;
880 
881     GrTexture *blurNinePatchTexture = context->findAndRefTexture(texDesc, blurRRectNinePatchID, &params);
882 
883     if (NULL == blurNinePatchTexture) {
884         SkMask mask;
885 
886         mask.fBounds = SkIRect::MakeWH(smallRectSide, smallRectSide);
887         mask.fFormat = SkMask::kA8_Format;
888         mask.fRowBytes = mask.fBounds.width();
889         mask.fImage = SkMask::AllocImage(mask.computeTotalImageSize());
890         SkAutoMaskFreeImage amfi(mask.fImage);
891 
892         memset(mask.fImage, 0, mask.computeTotalImageSize());
893 
894         SkRect smallRect;
895         smallRect.setWH(SkIntToScalar(smallRectSide), SkIntToScalar(smallRectSide));
896 
897         SkRRect smallRRect;
898         smallRRect.setRectXY(smallRect, SkIntToScalar(cornerRadius), SkIntToScalar(cornerRadius));
899 
900         SkPath path;
901         path.addRRect( smallRRect );
902 
903         SkDraw::DrawToMask(path, &mask.fBounds, NULL, NULL, &mask, SkMask::kJustRenderImage_CreateMode, SkPaint::kFill_Style);
904 
905         SkMask blurred_mask;
906         SkBlurMask::BoxBlur(&blurred_mask, mask, sigma, kNormal_SkBlurStyle, kHigh_SkBlurQuality, NULL, true );
907 
908         blurNinePatchTexture = context->createTexture(&params, texDesc, blurRRectNinePatchID, blurred_mask.fImage, 0);
909         SkMask::FreeImage(blurred_mask.fImage);
910     }
911 
912     SkAutoTUnref<GrTexture> blurunref(blurNinePatchTexture);
913     if (NULL == blurNinePatchTexture) {
914         return NULL;
915     }
916 
917     return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(GrRRectBlurEffect,
918                                                       (sigma, rrect, blurNinePatchTexture))));
919 }
920 
getConstantColorComponents(GrColor * color,uint32_t * validFlags) const921 void GrRRectBlurEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
922     *validFlags = 0;
923 }
924 
getFactory() const925 const GrBackendEffectFactory& GrRRectBlurEffect::getFactory() const {
926     return GrTBackendEffectFactory<GrRRectBlurEffect>::getInstance();
927 }
928 
GrRRectBlurEffect(float sigma,const SkRRect & rrect,GrTexture * ninePatchTexture)929 GrRRectBlurEffect::GrRRectBlurEffect(float sigma, const SkRRect& rrect, GrTexture *ninePatchTexture)
930     : fRRect(rrect),
931       fSigma(sigma),
932       fNinePatchAccess(ninePatchTexture) {
933     this->addTextureAccess(&fNinePatchAccess);
934     this->setWillReadFragmentPosition();
935 }
936 
onIsEqual(const GrEffect & other) const937 bool GrRRectBlurEffect::onIsEqual(const GrEffect& other) const {
938     const GrRRectBlurEffect& rrbe = CastEffect<GrRRectBlurEffect>(other);
939     return fRRect.getSimpleRadii().fX == rrbe.fRRect.getSimpleRadii().fX && fSigma == rrbe.fSigma;
940 }
941 
942 //////////////////////////////////////////////////////////////////////////////
943 
944 GR_DEFINE_EFFECT_TEST(GrRRectBlurEffect);
945 
TestCreate(SkRandom * random,GrContext * context,const GrDrawTargetCaps & caps,GrTexture * [])946 GrEffectRef* GrRRectBlurEffect::TestCreate(SkRandom* random,
947                                      GrContext* context,
948                                      const GrDrawTargetCaps& caps,
949                                      GrTexture*[]) {
950     SkScalar w = random->nextRangeScalar(100.f, 1000.f);
951     SkScalar h = random->nextRangeScalar(100.f, 1000.f);
952     SkScalar r = random->nextRangeF(1.f, 9.f);
953     SkScalar sigma = random->nextRangeF(1.f,10.f);
954     SkRRect rrect;
955     rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
956     return GrRRectBlurEffect::Create(context, sigma, rrect);
957 }
958 
959 //////////////////////////////////////////////////////////////////////////////
960 
961 class GrGLRRectBlurEffect : public GrGLEffect {
962 public:
963     GrGLRRectBlurEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
964 
965     virtual void emitCode(GrGLShaderBuilder* builder,
966                           const GrDrawEffect& drawEffect,
967                           EffectKey key,
968                           const char* outputColor,
969                           const char* inputColor,
970                           const TransformedCoordsArray&,
971                           const TextureSamplerArray&) SK_OVERRIDE;
972 
973     virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
974 
975 private:
976     GrGLUniformManager::UniformHandle   fProxyRectUniform;
977     GrGLUniformManager::UniformHandle   fCornerRadiusUniform;
978     GrGLUniformManager::UniformHandle   fBlurRadiusUniform;
979     typedef GrGLEffect INHERITED;
980 };
981 
GrGLRRectBlurEffect(const GrBackendEffectFactory & factory,const GrDrawEffect & drawEffect)982 GrGLRRectBlurEffect::GrGLRRectBlurEffect(const GrBackendEffectFactory& factory,
983                              const GrDrawEffect& drawEffect)
984     : INHERITED (factory) {
985 }
986 
emitCode(GrGLShaderBuilder * builder,const GrDrawEffect & drawEffect,EffectKey key,const char * outputColor,const char * inputColor,const TransformedCoordsArray &,const TextureSamplerArray & samplers)987 void GrGLRRectBlurEffect::emitCode(GrGLShaderBuilder* builder,
988                              const GrDrawEffect& drawEffect,
989                              EffectKey key,
990                              const char* outputColor,
991                              const char* inputColor,
992                              const TransformedCoordsArray&,
993                              const TextureSamplerArray& samplers) {
994     const char *rectName;
995     const char *cornerRadiusName;
996     const char *blurRadiusName;
997 
998     // The proxy rect has left, top, right, and bottom edges correspond to
999     // components x, y, z, and w, respectively.
1000 
1001     fProxyRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1002                                             kVec4f_GrSLType,
1003                                             "proxyRect",
1004                                             &rectName);
1005     fCornerRadiusUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1006                                                  kFloat_GrSLType,
1007                                                  "cornerRadius",
1008                                                  &cornerRadiusName);
1009     fBlurRadiusUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1010                                                  kFloat_GrSLType,
1011                                                  "blurRadius",
1012                                                  &blurRadiusName);
1013     const char* fragmentPos = builder->fragmentPosition();
1014 
1015     // warp the fragment position to the appropriate part of the 9patch blur texture
1016 
1017     builder->fsCodeAppendf("\t\tvec2 rectCenter = (%s.xy + %s.zw)/2.0;\n", rectName, rectName);
1018     builder->fsCodeAppendf("\t\tvec2 translatedFragPos = %s - %s.xy;\n", fragmentPos, rectName);
1019     builder->fsCodeAppendf("\t\tfloat threshold = %s + 2.0*%s;\n", cornerRadiusName, blurRadiusName );
1020     builder->fsCodeAppendf("\t\tvec2 middle = %s.zw - %s.xy - 2.0*threshold;\n", rectName, rectName );
1021 
1022     builder->fsCodeAppendf("\t\tif (translatedFragPos.x >= threshold && translatedFragPos.x < (middle.x+threshold)) {\n" );
1023     builder->fsCodeAppendf("\t\t\ttranslatedFragPos.x = threshold;\n");
1024     builder->fsCodeAppendf("\t\t} else if (translatedFragPos.x >= (middle.x + threshold)) {\n");
1025     builder->fsCodeAppendf("\t\t\ttranslatedFragPos.x -= middle.x - 1.0;\n");
1026     builder->fsCodeAppendf("\t\t}\n");
1027 
1028     builder->fsCodeAppendf("\t\tif (translatedFragPos.y > threshold && translatedFragPos.y < (middle.y+threshold)) {\n" );
1029     builder->fsCodeAppendf("\t\t\ttranslatedFragPos.y = threshold;\n");
1030     builder->fsCodeAppendf("\t\t} else if (translatedFragPos.y >= (middle.y + threshold)) {\n");
1031     builder->fsCodeAppendf("\t\t\ttranslatedFragPos.y -= middle.y - 1.0;\n");
1032     builder->fsCodeAppendf("\t\t}\n");
1033 
1034     builder->fsCodeAppendf("\t\tvec2 proxyDims = vec2(2.0*threshold+1.0);\n");
1035     builder->fsCodeAppendf("\t\tvec2 texCoord = translatedFragPos / proxyDims;\n");
1036 
1037     builder->fsCodeAppendf("\t%s = ", outputColor);
1038     builder->fsAppendTextureLookupAndModulate(inputColor, samplers[0], "texCoord");
1039     builder->fsCodeAppend(";\n");
1040 }
1041 
setData(const GrGLUniformManager & uman,const GrDrawEffect & drawEffect)1042 void GrGLRRectBlurEffect::setData(const GrGLUniformManager& uman,
1043                                     const GrDrawEffect& drawEffect) {
1044     const GrRRectBlurEffect& brre = drawEffect.castEffect<GrRRectBlurEffect>();
1045     SkRRect rrect = brre.getRRect();
1046 
1047     float blurRadius = 3.f*SkScalarCeilToScalar(brre.getSigma()-1/6.0f);
1048     uman.set1f(fBlurRadiusUniform, blurRadius);
1049 
1050     SkRect rect = rrect.getBounds();
1051     rect.outset(blurRadius, blurRadius);
1052     uman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
1053 
1054     SkScalar radius = 0;
1055     SkASSERT(rrect.isSimpleCircular() || rrect.isRect());
1056     radius = rrect.getSimpleRadii().fX;
1057     uman.set1f(fCornerRadiusUniform, radius);
1058 }
1059 
1060 
directFilterRRectMaskGPU(GrContext * context,GrPaint * grp,const SkStrokeRec & strokeRec,const SkRRect & rrect) const1061 bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context,
1062                                                     GrPaint* grp,
1063                                                     const SkStrokeRec& strokeRec,
1064                                                     const SkRRect& rrect) const {
1065     if (fBlurStyle != kNormal_SkBlurStyle) {
1066         return false;
1067     }
1068 
1069     if (!strokeRec.isFillStyle()) {
1070         return false;
1071     }
1072 
1073     SkRect proxy_rect = rrect.rect();
1074     SkMatrix ctm = context->getMatrix();
1075     SkScalar xformedSigma = this->computeXformedSigma(ctm);
1076     float extra=3.f*SkScalarCeilToScalar(xformedSigma-1/6.0f);
1077     proxy_rect.outset(extra, extra);
1078 
1079     SkAutoTUnref<GrEffectRef> effect(GrRRectBlurEffect::Create(
1080             context, xformedSigma, rrect));
1081     if (!effect) {
1082         return false;
1083     }
1084 
1085     GrContext::AutoMatrix am;
1086     if (!am.setIdentity(context, grp)) {
1087        return false;
1088     }
1089 
1090     grp->addCoverageEffect(effect);
1091 
1092     context->drawRect(*grp, proxy_rect);
1093     return true;
1094 }
1095 
canFilterMaskGPU(const SkRect & srcBounds,const SkIRect & clipBounds,const SkMatrix & ctm,SkRect * maskRect) const1096 bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds,
1097                                             const SkIRect& clipBounds,
1098                                             const SkMatrix& ctm,
1099                                             SkRect* maskRect) const {
1100     SkScalar xformedSigma = this->computeXformedSigma(ctm);
1101     if (xformedSigma <= 0) {
1102         return false;
1103     }
1104 
1105     static const SkScalar kMIN_GPU_BLUR_SIZE  = SkIntToScalar(64);
1106     static const SkScalar kMIN_GPU_BLUR_SIGMA = SkIntToScalar(32);
1107 
1108     if (srcBounds.width() <= kMIN_GPU_BLUR_SIZE &&
1109         srcBounds.height() <= kMIN_GPU_BLUR_SIZE &&
1110         xformedSigma <= kMIN_GPU_BLUR_SIGMA) {
1111         // We prefer to blur small rect with small radius via CPU.
1112         return false;
1113     }
1114 
1115     if (NULL == maskRect) {
1116         // don't need to compute maskRect
1117         return true;
1118     }
1119 
1120     float sigma3 = 3 * SkScalarToFloat(xformedSigma);
1121 
1122     SkRect clipRect = SkRect::Make(clipBounds);
1123     SkRect srcRect(srcBounds);
1124 
1125     // Outset srcRect and clipRect by 3 * sigma, to compute affected blur area.
1126     srcRect.outset(sigma3, sigma3);
1127     clipRect.outset(sigma3, sigma3);
1128     srcRect.intersect(clipRect);
1129     *maskRect = srcRect;
1130     return true;
1131 }
1132 
filterMaskGPU(GrTexture * src,const SkMatrix & ctm,const SkRect & maskRect,GrTexture ** result,bool canOverwriteSrc) const1133 bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src,
1134                                          const SkMatrix& ctm,
1135                                          const SkRect& maskRect,
1136                                          GrTexture** result,
1137                                          bool canOverwriteSrc) const {
1138     SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
1139 
1140     GrContext* context = src->getContext();
1141 
1142     GrContext::AutoWideOpenIdentityDraw awo(context, NULL);
1143 
1144     SkScalar xformedSigma = this->computeXformedSigma(ctm);
1145     SkASSERT(xformedSigma > 0);
1146 
1147     // If we're doing a normal blur, we can clobber the pathTexture in the
1148     // gaussianBlur.  Otherwise, we need to save it for later compositing.
1149     bool isNormalBlur = (kNormal_SkBlurStyle == fBlurStyle);
1150     *result = SkGpuBlurUtils::GaussianBlur(context, src, isNormalBlur && canOverwriteSrc,
1151                                            clipRect, false, xformedSigma, xformedSigma);
1152     if (NULL == *result) {
1153         return false;
1154     }
1155 
1156     if (!isNormalBlur) {
1157         context->setIdentityMatrix();
1158         GrPaint paint;
1159         SkMatrix matrix;
1160         matrix.setIDiv(src->width(), src->height());
1161         // Blend pathTexture over blurTexture.
1162         GrContext::AutoRenderTarget art(context, (*result)->asRenderTarget());
1163         paint.addColorEffect(GrSimpleTextureEffect::Create(src, matrix))->unref();
1164         if (kInner_SkBlurStyle == fBlurStyle) {
1165             // inner:  dst = dst * src
1166             paint.setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff);
1167         } else if (kSolid_SkBlurStyle == fBlurStyle) {
1168             // solid:  dst = src + dst - src * dst
1169             //             = (1 - dst) * src + 1 * dst
1170             paint.setBlendFunc(kIDC_GrBlendCoeff, kOne_GrBlendCoeff);
1171         } else if (kOuter_SkBlurStyle == fBlurStyle) {
1172             // outer:  dst = dst * (1 - src)
1173             //             = 0 * src + (1 - src) * dst
1174             paint.setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff);
1175         }
1176         context->drawRect(paint, clipRect);
1177     }
1178 
1179     return true;
1180 }
1181 
1182 #endif // SK_SUPPORT_GPU
1183 
1184 
1185 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const1186 void SkBlurMaskFilterImpl::toString(SkString* str) const {
1187     str->append("SkBlurMaskFilterImpl: (");
1188 
1189     str->append("sigma: ");
1190     str->appendScalar(fSigma);
1191     str->append(" ");
1192 
1193     static const char* gStyleName[kLastEnum_SkBlurStyle + 1] = {
1194         "normal", "solid", "outer", "inner"
1195     };
1196 
1197     str->appendf("style: %s ", gStyleName[fBlurStyle]);
1198     str->append("flags: (");
1199     if (fBlurFlags) {
1200         bool needSeparator = false;
1201         SkAddFlagToString(str,
1202                           SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag),
1203                           "IgnoreXform", &needSeparator);
1204         SkAddFlagToString(str,
1205                           SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag),
1206                           "HighQuality", &needSeparator);
1207     } else {
1208         str->append("None");
1209     }
1210     str->append("))");
1211 }
1212 #endif
1213 
1214 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
1215     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
1216 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
1217