Home | History | Annotate | Download | only in effects
      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 
     76     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 
     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 
    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 
    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 
    135 SkMask::Format SkBlurMaskFilterImpl::getFormat() const {
    136     return SkMask::kA8_Format;
    137 }
    138 
    139 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 
    152 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 
    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 
    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 
    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 
    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
    240 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
    356 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 
    476 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 
    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 
    496 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 
    505 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 
    542 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
    594 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