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 "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 
     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 
     95     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 
    103     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 
    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 
    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 
    139 SkMask::Format SkBlurMaskFilterImpl::getFormat() const {
    140     return SkMask::kA8_Format;
    141 }
    142 
    143 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 
    156 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 
    163 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 
    172 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 
    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 
    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 
    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 
    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
    264 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
    397 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 
    516 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 
    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 
    533 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 
    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      */
    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 
    579     const SkRect& getRect() const { return fRect; }
    580     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 
    623 GrGLRectBlurEffect::GrGLRectBlurEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
    624     : INHERITED(factory) {
    625 }
    626 
    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 
    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 
    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 
    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 
    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 
    744 GrRectBlurEffect::~GrRectBlurEffect() {
    745 }
    746 
    747 const GrBackendEffectFactory& GrRectBlurEffect::getFactory() const {
    748     return GrTBackendEffectFactory<GrRectBlurEffect>::getInstance();
    749 }
    750 
    751 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 
    756 void GrRectBlurEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
    757     *validFlags = 0;
    758     return;
    759 }
    760 
    761 GR_DEFINE_EFFECT_TEST(GrRectBlurEffect);
    762 
    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 
    774 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 
    821     virtual ~GrRRectBlurEffect() {};
    822     static const char* Name() { return "GrRRectBlur"; }
    823 
    824     const SkRRect& getRRect() const { return fRRect; }
    825     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 
    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 
    921 void GrRRectBlurEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
    922     *validFlags = 0;
    923 }
    924 
    925 const GrBackendEffectFactory& GrRRectBlurEffect::getFactory() const {
    926     return GrTBackendEffectFactory<GrRRectBlurEffect>::getInstance();
    927 }
    928 
    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 
    937 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 
    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 
    982 GrGLRRectBlurEffect::GrGLRRectBlurEffect(const GrBackendEffectFactory& factory,
    983                              const GrDrawEffect& drawEffect)
    984     : INHERITED (factory) {
    985 }
    986 
    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.xy - %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 
   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 
   1061 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 
   1096 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 
   1133 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
   1186 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