• 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 "SkFlattenableBuffers.h"
13 #include "SkMaskFilter.h"
14 #include "SkRRect.h"
15 #include "SkRTConf.h"
16 #include "SkStringUtils.h"
17 #include "SkStrokeRec.h"
18 
19 #if SK_SUPPORT_GPU
20 #include "GrContext.h"
21 #include "GrTexture.h"
22 #include "effects/GrSimpleTextureEffect.h"
23 #include "SkGrPixelRef.h"
24 #endif
25 
26 class SkBlurMaskFilterImpl : public SkMaskFilter {
27 public:
28     SkBlurMaskFilterImpl(SkScalar sigma, SkBlurMaskFilter::BlurStyle, uint32_t flags);
29 
30     // overrides from SkMaskFilter
31     virtual SkMask::Format getFormat() const SK_OVERRIDE;
32     virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
33                             SkIPoint* margin) const SK_OVERRIDE;
34 
35 #if SK_SUPPORT_GPU
36     virtual bool canFilterMaskGPU(const SkRect& devBounds,
37                                   const SkIRect& clipBounds,
38                                   const SkMatrix& ctm,
39                                   SkRect* maskRect) const SK_OVERRIDE;
40     virtual bool filterMaskGPU(GrTexture* src,
41                                const SkRect& maskRect,
42                                GrTexture** result,
43                                bool canOverwriteSrc) const;
44 #endif
45 
46     virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE;
47 
48     SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;)
49     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)
50 
51 protected:
52     virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMatrix&,
53                                            const SkIRect& clipBounds,
54                                            NinePatch*) const SK_OVERRIDE;
55 
56     virtual FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&,
57                                            const SkIRect& clipBounds,
58                                            NinePatch*) const SK_OVERRIDE;
59 
60     bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix,
61                         SkIPoint* margin, SkMask::CreateMode createMode) const;
62 
63 private:
64     // To avoid unseemly allocation requests (esp. for finite platforms like
65     // handset) we limit the radius so something manageable. (as opposed to
66     // a request like 10,000)
67     static const SkScalar kMAX_BLUR_SIGMA;
68 
69     SkScalar                    fSigma;
70     SkBlurMaskFilter::BlurStyle fBlurStyle;
71     uint32_t                    fBlurFlags;
72 
73     SkBlurMaskFilterImpl(SkFlattenableReadBuffer&);
74     virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
75 
computeXformedSigma(const SkMatrix & ctm) const76     SkScalar computeXformedSigma(const SkMatrix& ctm) const {
77         bool ignoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
78 
79         SkScalar xformedSigma = ignoreTransform ? fSigma : ctm.mapRadius(fSigma);
80         return SkMinScalar(xformedSigma, kMAX_BLUR_SIGMA);
81     }
82 
83     typedef SkMaskFilter INHERITED;
84 };
85 
86 const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_SIGMA = SkIntToScalar(128);
87 
Create(SkScalar radius,SkBlurMaskFilter::BlurStyle style,uint32_t flags)88 SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius,
89                                        SkBlurMaskFilter::BlurStyle style,
90                                        uint32_t flags) {
91     // use !(radius > 0) instead of radius <= 0 to reject NaN values
92     if (!(radius > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
93         || flags > SkBlurMaskFilter::kAll_BlurFlag) {
94         return NULL;
95     }
96 
97     SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius);
98 
99     return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags));
100 }
101 
Create(SkBlurMaskFilter::BlurStyle style,SkScalar sigma,uint32_t flags)102 SkMaskFilter* SkBlurMaskFilter::Create(SkBlurMaskFilter::BlurStyle style,
103                                        SkScalar sigma,
104                                        uint32_t flags) {
105     // use !(sigma > 0) instead of sigma <= 0 to reject NaN values
106     if (!(sigma > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
107         || flags > SkBlurMaskFilter::kAll_BlurFlag) {
108         return NULL;
109     }
110 
111     return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags));
112 }
113 
114 ///////////////////////////////////////////////////////////////////////////////
115 
SkBlurMaskFilterImpl(SkScalar sigma,SkBlurMaskFilter::BlurStyle style,uint32_t flags)116 SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar sigma,
117                                            SkBlurMaskFilter::BlurStyle style,
118                                            uint32_t flags)
119     : fSigma(sigma), fBlurStyle(style), fBlurFlags(flags) {
120 #if 0
121     fGamma = NULL;
122     if (gammaScale) {
123         fGamma = new U8[256];
124         if (gammaScale > 0)
125             SkBlurMask::BuildSqrGamma(fGamma, gammaScale);
126         else
127             SkBlurMask::BuildSqrtGamma(fGamma, -gammaScale);
128     }
129 #endif
130     SkASSERT(fSigma >= 0);
131     SkASSERT((unsigned)style < SkBlurMaskFilter::kBlurStyleCount);
132     SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
133 }
134 
getFormat() const135 SkMask::Format SkBlurMaskFilterImpl::getFormat() const {
136     return SkMask::kA8_Format;
137 }
138 
filterMask(SkMask * dst,const SkMask & src,const SkMatrix & matrix,SkIPoint * margin) const139 bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
140                                       const SkMatrix& matrix,
141                                       SkIPoint* margin) const{
142     SkScalar sigma = this->computeXformedSigma(matrix);
143 
144     SkBlurMask::Quality blurQuality =
145         (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
146             SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;
147 
148     return SkBlurMask::BoxBlur(dst, src, sigma, (SkBlurMask::Style)fBlurStyle,
149                                blurQuality, margin);
150 }
151 
filterRectMask(SkMask * dst,const SkRect & r,const SkMatrix & matrix,SkIPoint * margin,SkMask::CreateMode createMode) const152 bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
153                                           const SkMatrix& matrix,
154                                           SkIPoint* margin, SkMask::CreateMode createMode) const{
155     SkScalar sigma = computeXformedSigma(matrix);
156 
157     return SkBlurMask::BlurRect(sigma, dst, r, (SkBlurMask::Style)fBlurStyle,
158                                 margin, createMode);
159 }
160 
161 #include "SkCanvas.h"
162 
prepare_to_draw_into_mask(const SkRect & bounds,SkMask * mask)163 static bool prepare_to_draw_into_mask(const SkRect& bounds, SkMask* mask) {
164     SkASSERT(mask != NULL);
165 
166     bounds.roundOut(&mask->fBounds);
167     mask->fRowBytes = SkAlign4(mask->fBounds.width());
168     mask->fFormat = SkMask::kA8_Format;
169     const size_t size = mask->computeImageSize();
170     mask->fImage = SkMask::AllocImage(size);
171     if (NULL == mask->fImage) {
172         return false;
173     }
174 
175     // FIXME: use sk_calloc in AllocImage?
176     sk_bzero(mask->fImage, size);
177     return true;
178 }
179 
draw_rrect_into_mask(const SkRRect rrect,SkMask * mask)180 static bool draw_rrect_into_mask(const SkRRect rrect, SkMask* mask) {
181     if (!prepare_to_draw_into_mask(rrect.rect(), mask)) {
182         return false;
183     }
184 
185     // FIXME: This code duplicates code in draw_rects_into_mask, below. Is there a
186     // clean way to share more code?
187     SkBitmap bitmap;
188     bitmap.setConfig(SkBitmap::kA8_Config,
189                      mask->fBounds.width(), mask->fBounds.height(),
190                      mask->fRowBytes);
191     bitmap.setPixels(mask->fImage);
192 
193     SkCanvas canvas(bitmap);
194     canvas.translate(-SkIntToScalar(mask->fBounds.left()),
195                      -SkIntToScalar(mask->fBounds.top()));
196 
197     SkPaint paint;
198     paint.setAntiAlias(true);
199     canvas.drawRRect(rrect, paint);
200     return true;
201 }
202 
draw_rects_into_mask(const SkRect rects[],int count,SkMask * mask)203 static bool draw_rects_into_mask(const SkRect rects[], int count, SkMask* mask) {
204     if (!prepare_to_draw_into_mask(rects[0], mask)) {
205         return false;
206     }
207 
208     SkBitmap bitmap;
209     bitmap.setConfig(SkBitmap::kA8_Config,
210                      mask->fBounds.width(), mask->fBounds.height(),
211                      mask->fRowBytes);
212     bitmap.setPixels(mask->fImage);
213 
214     SkCanvas canvas(bitmap);
215     canvas.translate(-SkIntToScalar(mask->fBounds.left()),
216                      -SkIntToScalar(mask->fBounds.top()));
217 
218     SkPaint paint;
219     paint.setAntiAlias(true);
220 
221     if (1 == count) {
222         canvas.drawRect(rects[0], paint);
223     } else {
224         // todo: do I need a fast way to do this?
225         SkPath path;
226         path.addRect(rects[0]);
227         path.addRect(rects[1]);
228         path.setFillType(SkPath::kEvenOdd_FillType);
229         canvas.drawPath(path, paint);
230     }
231     return true;
232 }
233 
rect_exceeds(const SkRect & r,SkScalar v)234 static bool rect_exceeds(const SkRect& r, SkScalar v) {
235     return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v ||
236            r.width() > v || r.height() > v;
237 }
238 
239 SkMaskFilter::FilterReturn
filterRRectToNine(const SkRRect & rrect,const SkMatrix & matrix,const SkIRect & clipBounds,NinePatch * patch) const240 SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& matrix,
241                                         const SkIRect& clipBounds,
242                                         NinePatch* patch) const {
243     SkASSERT(patch != NULL);
244     switch (rrect.getType()) {
245         case SkRRect::kUnknown_Type:
246             // Unknown should never be returned.
247             SkASSERT(false);
248             // Fall through.
249         case SkRRect::kEmpty_Type:
250             // Nothing to draw.
251             return kFalse_FilterReturn;
252 
253         case SkRRect::kRect_Type:
254             // We should have caught this earlier.
255             SkASSERT(false);
256             // Fall through.
257         case SkRRect::kOval_Type:
258             // The nine patch special case does not handle ovals, and we
259             // already have code for rectangles.
260             return kUnimplemented_FilterReturn;
261 
262         case SkRRect::kSimple_Type:
263             // Fall through.
264         case SkRRect::kComplex_Type:
265             // These can take advantage of this fast path.
266             break;
267     }
268 
269     // TODO: report correct metrics for innerstyle, where we do not grow the
270     // total bounds, but we do need an inset the size of our blur-radius
271     if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle) {
272         return kUnimplemented_FilterReturn;
273     }
274 
275     // TODO: take clipBounds into account to limit our coordinates up front
276     // for now, just skip too-large src rects (to take the old code path).
277     if (rect_exceeds(rrect.rect(), SkIntToScalar(32767))) {
278         return kUnimplemented_FilterReturn;
279     }
280 
281     SkIPoint margin;
282     SkMask  srcM, dstM;
283     rrect.rect().roundOut(&srcM.fBounds);
284     srcM.fImage = NULL;
285     srcM.fFormat = SkMask::kA8_Format;
286     srcM.fRowBytes = 0;
287 
288     if (!this->filterMask(&dstM, srcM, matrix, &margin)) {
289         return kFalse_FilterReturn;
290     }
291 
292     // Now figure out the appropriate width and height of the smaller round rectangle
293     // to stretch. It will take into account the larger radius per side as well as double
294     // the margin, to account for inner and outer blur.
295     const SkVector& UL = rrect.radii(SkRRect::kUpperLeft_Corner);
296     const SkVector& UR = rrect.radii(SkRRect::kUpperRight_Corner);
297     const SkVector& LR = rrect.radii(SkRRect::kLowerRight_Corner);
298     const SkVector& LL = rrect.radii(SkRRect::kLowerLeft_Corner);
299 
300     const SkScalar leftUnstretched = SkTMax(UL.fX, LL.fX) + SkIntToScalar(2 * margin.fX);
301     const SkScalar rightUnstretched = SkTMax(UR.fX, LR.fX) + SkIntToScalar(2 * margin.fX);
302 
303     // Extra space in the middle to ensure an unchanging piece for stretching. Use 3 to cover
304     // any fractional space on either side plus 1 for the part to stretch.
305     const SkScalar stretchSize = SkIntToScalar(3);
306 
307     const SkScalar totalSmallWidth = leftUnstretched + rightUnstretched + stretchSize;
308     if (totalSmallWidth >= rrect.rect().width()) {
309         // There is no valid piece to stretch.
310         return kUnimplemented_FilterReturn;
311     }
312 
313     const SkScalar topUnstretched = SkTMax(UL.fY, UR.fY) + SkIntToScalar(2 * margin.fY);
314     const SkScalar bottomUnstretched = SkTMax(LL.fY, LR.fY) + SkIntToScalar(2 * margin.fY);
315 
316     const SkScalar totalSmallHeight = topUnstretched + bottomUnstretched + stretchSize;
317     if (totalSmallHeight >= rrect.rect().height()) {
318         // There is no valid piece to stretch.
319         return kUnimplemented_FilterReturn;
320     }
321 
322     SkRect smallR = SkRect::MakeWH(totalSmallWidth, totalSmallHeight);
323 
324     SkRRect smallRR;
325     SkVector radii[4];
326     radii[SkRRect::kUpperLeft_Corner] = UL;
327     radii[SkRRect::kUpperRight_Corner] = UR;
328     radii[SkRRect::kLowerRight_Corner] = LR;
329     radii[SkRRect::kLowerLeft_Corner] = LL;
330     smallRR.setRectRadii(smallR, radii);
331 
332     if (!draw_rrect_into_mask(smallRR, &srcM)) {
333         return kFalse_FilterReturn;
334     }
335 
336     SkAutoMaskFreeImage amf(srcM.fImage);
337 
338     if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
339         return kFalse_FilterReturn;
340     }
341 
342     patch->fMask.fBounds.offsetTo(0, 0);
343     patch->fOuterRect = dstM.fBounds;
344     patch->fCenter.fX = SkScalarCeilToInt(leftUnstretched) + 1;
345     patch->fCenter.fY = SkScalarCeilToInt(topUnstretched) + 1;
346     return kTrue_FilterReturn;
347 }
348 
349 #ifdef SK_IGNORE_FAST_RECT_BLUR
350 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", false, "Use the faster analytic blur approach for ninepatch rects" );
351 #else
352 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", true, "Use the faster analytic blur approach for ninepatch rects" );
353 #endif
354 
355 SkMaskFilter::FilterReturn
filterRectsToNine(const SkRect rects[],int count,const SkMatrix & matrix,const SkIRect & clipBounds,NinePatch * patch) const356 SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
357                                         const SkMatrix& matrix,
358                                         const SkIRect& clipBounds,
359                                         NinePatch* patch) const {
360     if (count < 1 || count > 2) {
361         return kUnimplemented_FilterReturn;
362     }
363 
364     // TODO: report correct metrics for innerstyle, where we do not grow the
365     // total bounds, but we do need an inset the size of our blur-radius
366     if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle ||
367         SkBlurMaskFilter::kOuter_BlurStyle == fBlurStyle) {
368         return kUnimplemented_FilterReturn;
369     }
370 
371     // TODO: take clipBounds into account to limit our coordinates up front
372     // for now, just skip too-large src rects (to take the old code path).
373     if (rect_exceeds(rects[0], SkIntToScalar(32767))) {
374         return kUnimplemented_FilterReturn;
375     }
376 
377     SkIPoint margin;
378     SkMask  srcM, dstM;
379     rects[0].roundOut(&srcM.fBounds);
380     srcM.fImage = NULL;
381     srcM.fFormat = SkMask::kA8_Format;
382     srcM.fRowBytes = 0;
383 
384     bool filterResult = false;
385     if (count == 1 && c_analyticBlurNinepatch) {
386         // special case for fast rect blur
387         // don't actually do the blur the first time, just compute the correct size
388         filterResult = this->filterRectMask(&dstM, rects[0], matrix, &margin,
389                                             SkMask::kJustComputeBounds_CreateMode);
390     } else {
391         filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
392     }
393 
394     if (!filterResult) {
395         return kFalse_FilterReturn;
396     }
397 
398     /*
399      *  smallR is the smallest version of 'rect' that will still guarantee that
400      *  we get the same blur results on all edges, plus 1 center row/col that is
401      *  representative of the extendible/stretchable edges of the ninepatch.
402      *  Since our actual edge may be fractional we inset 1 more to be sure we
403      *  don't miss any interior blur.
404      *  x is an added pixel of blur, and { and } are the (fractional) edge
405      *  pixels from the original rect.
406      *
407      *   x x { x x .... x x } x x
408      *
409      *  Thus, in this case, we inset by a total of 5 (on each side) beginning
410      *  with our outer-rect (dstM.fBounds)
411      */
412     SkRect smallR[2];
413     SkIPoint center;
414 
415     // +2 is from +1 for each edge (to account for possible fractional edges
416     int smallW = dstM.fBounds.width() - srcM.fBounds.width() + 2;
417     int smallH = dstM.fBounds.height() - srcM.fBounds.height() + 2;
418     SkIRect innerIR;
419 
420     if (1 == count) {
421         innerIR = srcM.fBounds;
422         center.set(smallW, smallH);
423     } else {
424         SkASSERT(2 == count);
425         rects[1].roundIn(&innerIR);
426         center.set(smallW + (innerIR.left() - srcM.fBounds.left()),
427                    smallH + (innerIR.top() - srcM.fBounds.top()));
428     }
429 
430     // +1 so we get a clean, stretchable, center row/col
431     smallW += 1;
432     smallH += 1;
433 
434     // we want the inset amounts to be integral, so we don't change any
435     // fractional phase on the fRight or fBottom of our smallR.
436     const SkScalar dx = SkIntToScalar(innerIR.width() - smallW);
437     const SkScalar dy = SkIntToScalar(innerIR.height() - smallH);
438     if (dx < 0 || dy < 0) {
439         // we're too small, relative to our blur, to break into nine-patch,
440         // so we ask to have our normal filterMask() be called.
441         return kUnimplemented_FilterReturn;
442     }
443 
444     smallR[0].set(rects[0].left(), rects[0].top(), rects[0].right() - dx, rects[0].bottom() - dy);
445     if (smallR[0].width() < 2 || smallR[0].height() < 2) {
446         return kUnimplemented_FilterReturn;
447     }
448     if (2 == count) {
449         smallR[1].set(rects[1].left(), rects[1].top(),
450                       rects[1].right() - dx, rects[1].bottom() - dy);
451         SkASSERT(!smallR[1].isEmpty());
452     }
453 
454     if (count > 1 || !c_analyticBlurNinepatch) {
455         if (!draw_rects_into_mask(smallR, count, &srcM)) {
456             return kFalse_FilterReturn;
457         }
458 
459         SkAutoMaskFreeImage amf(srcM.fImage);
460 
461         if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
462             return kFalse_FilterReturn;
463         }
464     } else {
465         if (!this->filterRectMask(&patch->fMask, smallR[0], matrix, &margin,
466                                   SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
467             return kFalse_FilterReturn;
468         }
469     }
470     patch->fMask.fBounds.offsetTo(0, 0);
471     patch->fOuterRect = dstM.fBounds;
472     patch->fCenter = center;
473     return kTrue_FilterReturn;
474 }
475 
computeFastBounds(const SkRect & src,SkRect * dst) const476 void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
477                                              SkRect* dst) const {
478     SkScalar pad = 3.0f * fSigma;
479 
480     dst->set(src.fLeft  - pad, src.fTop    - pad,
481              src.fRight + pad, src.fBottom + pad);
482 }
483 
SkBlurMaskFilterImpl(SkFlattenableReadBuffer & buffer)484 SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkFlattenableReadBuffer& buffer)
485         : SkMaskFilter(buffer) {
486 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO
487     // TODO: when the skps are recaptured at > v15 the SkScalarAbs can be removed
488 #endif
489     fSigma = SkScalarAbs(buffer.readScalar());
490     fBlurStyle = (SkBlurMaskFilter::BlurStyle)buffer.readInt();
491     fBlurFlags = buffer.readUInt() & SkBlurMaskFilter::kAll_BlurFlag;
492     SkASSERT(fSigma >= 0);
493     SkASSERT((unsigned)fBlurStyle < SkBlurMaskFilter::kBlurStyleCount);
494 }
495 
flatten(SkFlattenableWriteBuffer & buffer) const496 void SkBlurMaskFilterImpl::flatten(SkFlattenableWriteBuffer& buffer) const {
497     this->INHERITED::flatten(buffer);
498     buffer.writeScalar(fSigma);
499     buffer.writeInt(fBlurStyle);
500     buffer.writeUInt(fBlurFlags);
501 }
502 
503 #if SK_SUPPORT_GPU
504 
canFilterMaskGPU(const SkRect & srcBounds,const SkIRect & clipBounds,const SkMatrix & ctm,SkRect * maskRect) const505 bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds,
506                                             const SkIRect& clipBounds,
507                                             const SkMatrix& ctm,
508                                             SkRect* maskRect) const {
509     SkScalar xformedSigma = this->computeXformedSigma(ctm);
510     if (xformedSigma <= 0) {
511         return false;
512     }
513 
514     static const SkScalar kMIN_GPU_BLUR_SIZE  = SkIntToScalar(64);
515     static const SkScalar kMIN_GPU_BLUR_SIGMA = SkIntToScalar(32);
516 
517     if (srcBounds.width() <= kMIN_GPU_BLUR_SIZE &&
518         srcBounds.height() <= kMIN_GPU_BLUR_SIZE &&
519         xformedSigma <= kMIN_GPU_BLUR_SIGMA) {
520         // We prefer to blur small rect with small radius via CPU.
521         return false;
522     }
523 
524     if (NULL == maskRect) {
525         // don't need to compute maskRect
526         return true;
527     }
528 
529     float sigma3 = 3 * SkScalarToFloat(xformedSigma);
530 
531     SkRect clipRect = SkRect::Make(clipBounds);
532     SkRect srcRect(srcBounds);
533 
534     // Outset srcRect and clipRect by 3 * sigma, to compute affected blur area.
535     srcRect.outset(sigma3, sigma3);
536     clipRect.outset(sigma3, sigma3);
537     srcRect.intersect(clipRect);
538     *maskRect = srcRect;
539     return true;
540 }
541 
filterMaskGPU(GrTexture * src,const SkRect & maskRect,GrTexture ** result,bool canOverwriteSrc) const542 bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src,
543                                          const SkRect& maskRect,
544                                          GrTexture** result,
545                                          bool canOverwriteSrc) const {
546     SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
547 
548     GrContext* context = src->getContext();
549 
550     GrContext::AutoWideOpenIdentityDraw awo(context, NULL);
551 
552     SkScalar xformedSigma = this->computeXformedSigma(context->getMatrix());
553     SkASSERT(xformedSigma > 0);
554 
555     // If we're doing a normal blur, we can clobber the pathTexture in the
556     // gaussianBlur.  Otherwise, we need to save it for later compositing.
557     bool isNormalBlur = (SkBlurMaskFilter::kNormal_BlurStyle == fBlurStyle);
558     *result = SkGpuBlurUtils::GaussianBlur(context, src, isNormalBlur && canOverwriteSrc,
559                                            clipRect, false, xformedSigma, xformedSigma);
560     if (NULL == *result) {
561         return false;
562     }
563 
564     if (!isNormalBlur) {
565         context->setIdentityMatrix();
566         GrPaint paint;
567         SkMatrix matrix;
568         matrix.setIDiv(src->width(), src->height());
569         // Blend pathTexture over blurTexture.
570         GrContext::AutoRenderTarget art(context, (*result)->asRenderTarget());
571         paint.addColorEffect(GrSimpleTextureEffect::Create(src, matrix))->unref();
572         if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle) {
573             // inner:  dst = dst * src
574             paint.setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff);
575         } else if (SkBlurMaskFilter::kSolid_BlurStyle == fBlurStyle) {
576             // solid:  dst = src + dst - src * dst
577             //             = (1 - dst) * src + 1 * dst
578             paint.setBlendFunc(kIDC_GrBlendCoeff, kOne_GrBlendCoeff);
579         } else if (SkBlurMaskFilter::kOuter_BlurStyle == fBlurStyle) {
580             // outer:  dst = dst * (1 - src)
581             //             = 0 * src + (1 - src) * dst
582             paint.setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff);
583         }
584         context->drawRect(paint, clipRect);
585     }
586 
587     return true;
588 }
589 
590 #endif // SK_SUPPORT_GPU
591 
592 
593 #ifdef SK_DEVELOPER
toString(SkString * str) const594 void SkBlurMaskFilterImpl::toString(SkString* str) const {
595     str->append("SkBlurMaskFilterImpl: (");
596 
597     str->append("sigma: ");
598     str->appendScalar(fSigma);
599     str->append(" ");
600 
601     static const char* gStyleName[SkBlurMaskFilter::kBlurStyleCount] = {
602         "normal", "solid", "outer", "inner"
603     };
604 
605     str->appendf("style: %s ", gStyleName[fBlurStyle]);
606     str->append("flags: (");
607     if (fBlurFlags) {
608         bool needSeparator = false;
609         SkAddFlagToString(str,
610                           SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag),
611                           "IgnoreXform", &needSeparator);
612         SkAddFlagToString(str,
613                           SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag),
614                           "HighQuality", &needSeparator);
615     } else {
616         str->append("None");
617     }
618     str->append("))");
619 }
620 #endif
621 
622 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
623     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
624 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
625