SkBlurMaskFilter.cpp revision 11e055518a0cbe5329232a55fe2cd177e83836d8
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlurMaskFilter.h"
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlurMask.h"
11736dd031f177681bfa284e19291ef031ad0822d5robertphillips@google.com#include "SkGpuBlurUtils.h"
12c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com#include "SkFlattenableBuffers.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkMaskFilter.h"
14a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com#include "SkRRect.h"
157c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com#include "SkRTConf.h"
160bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com#include "SkStringUtils.h"
17491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#include "SkStrokeRec.h"
18491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
19491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#if SK_SUPPORT_GPU
20491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#include "GrContext.h"
21491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#include "GrTexture.h"
22491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#include "effects/GrSimpleTextureEffect.h"
23491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#include "SkGrPixelRef.h"
24491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#endif
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkBlurMaskFilterImpl : public SkMaskFilter {
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
287ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkBlurMaskFilterImpl(SkScalar sigma, SkBlurMaskFilter::BlurStyle, uint32_t flags);
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // overrides from SkMaskFilter
3130711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.com    virtual SkMask::Format getFormat() const SK_OVERRIDE;
3203016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com    virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
3330711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.com                            SkIPoint* margin) const SK_OVERRIDE;
342e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
35491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#if SK_SUPPORT_GPU
361842adf01320f9197b449de7375d08ccac43f389skia.committer@gmail.com    virtual bool canFilterMaskGPU(const SkRect& devBounds,
37491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com                                  const SkIRect& clipBounds,
38491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com                                  const SkMatrix& ctm,
39491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com                                  SkRect* maskRect) const SK_OVERRIDE;
401842adf01320f9197b449de7375d08ccac43f389skia.committer@gmail.com    virtual bool filterMaskGPU(GrTexture* src,
411842adf01320f9197b449de7375d08ccac43f389skia.committer@gmail.com                               const SkRect& maskRect,
42491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com                               GrTexture** result,
43491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com                               bool canOverwriteSrc) const;
44491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#endif
45491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
4630711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.com    virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE;
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
480bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;)
49ba28d03e94dc221d6a803bf2a84a420b9159255cdjsollen@google.com    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
51d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.comprotected:
52dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMatrix&,
53dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com                                           const SkIRect& clipBounds,
5430711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.com                                           NinePatch*) const SK_OVERRIDE;
552e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
56a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    virtual FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&,
57a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com                                           const SkIRect& clipBounds,
58a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com                                           NinePatch*) const SK_OVERRIDE;
59a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
602e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com    bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix,
617c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com                        SkIPoint* margin, SkMask::CreateMode createMode) const;
62453995e01d884d62ce2e808e0067e494c0c9c7faskia.committer@gmail.com
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
64491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    // To avoid unseemly allocation requests (esp. for finite platforms like
65491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    // handset) we limit the radius so something manageable. (as opposed to
66491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    // a request like 10,000)
677ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    static const SkScalar kMAX_BLUR_SIGMA;
687ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com
697ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkScalar                    fSigma;
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkBlurMaskFilter::BlurStyle fBlurStyle;
71038aff623d9fd47946cd31685f74cf473f7c84f0senorblanco@chromium.org    uint32_t                    fBlurFlags;
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkBlurMaskFilterImpl(SkFlattenableReadBuffer&);
7454924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.com    virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
757ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com
767ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkScalar computeXformedSigma(const SkMatrix& ctm) const {
77491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        bool ignoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
78491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
797ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com        SkScalar xformedSigma = ignoreTransform ? fSigma : ctm.mapRadius(fSigma);
807ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com        return SkMinScalar(xformedSigma, kMAX_BLUR_SIGMA);
81491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    }
82fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    typedef SkMaskFilter INHERITED;
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
867ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.comconst SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_SIGMA = SkIntToScalar(128);
87491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
8803016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.comSkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius,
8903016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com                                       SkBlurMaskFilter::BlurStyle style,
9003016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com                                       uint32_t flags) {
91e5828690239cbf899b881f4afa1c15e08414dd2creed@google.com    // use !(radius > 0) instead of radius <= 0 to reject NaN values
92fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    if (!(radius > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
9303016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com        || flags > SkBlurMaskFilter::kAll_BlurFlag) {
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return NULL;
9503016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com    }
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
977ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius);
987ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com
997ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags));
1007ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com}
1017ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com
1027ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.comSkMaskFilter* SkBlurMaskFilter::Create(SkBlurMaskFilter::BlurStyle style,
1037ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com                                       SkScalar sigma,
1047ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com                                       uint32_t flags) {
1057ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    // use !(sigma > 0) instead of sigma <= 0 to reject NaN values
1067ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    if (!(sigma > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
1077ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com        || flags > SkBlurMaskFilter::kAll_BlurFlag) {
1087ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com        return NULL;
1097ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    }
1107ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com
1117ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags));
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11403016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com///////////////////////////////////////////////////////////////////////////////
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1167ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.comSkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar sigma,
11703016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com                                           SkBlurMaskFilter::BlurStyle style,
118038aff623d9fd47946cd31685f74cf473f7c84f0senorblanco@chromium.org                                           uint32_t flags)
1197ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    : fSigma(sigma), fBlurStyle(style), fBlurFlags(flags) {
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if 0
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fGamma = NULL;
12203016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com    if (gammaScale) {
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fGamma = new U8[256];
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (gammaScale > 0)
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkBlurMask::BuildSqrGamma(fGamma, gammaScale);
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        else
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkBlurMask::BuildSqrtGamma(fGamma, -gammaScale);
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
1307ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkASSERT(fSigma >= 0);
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((unsigned)style < SkBlurMaskFilter::kBlurStyleCount);
132038aff623d9fd47946cd31685f74cf473f7c84f0senorblanco@chromium.org    SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13530711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.comSkMask::Format SkBlurMaskFilterImpl::getFormat() const {
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkMask::kA8_Format;
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13903016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.combool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
14030711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.com                                      const SkMatrix& matrix,
14130711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.com                                      SkIPoint* margin) const{
1427ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkScalar sigma = this->computeXformedSigma(matrix);
143038aff623d9fd47946cd31685f74cf473f7c84f0senorblanco@chromium.org
14403016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com    SkBlurMask::Quality blurQuality =
145fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
14603016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com            SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1487ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    return SkBlurMask::BoxBlur(dst, src, sigma, (SkBlurMask::Style)fBlurStyle,
1497ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com                               blurQuality, margin);
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1527c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.combool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
1537c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com                                          const SkMatrix& matrix,
1547c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com                                          SkIPoint* margin, SkMask::CreateMode createMode) const{
1557ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkScalar sigma = computeXformedSigma(matrix);
1567c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com
1577ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    return SkBlurMask::BlurRect(sigma, dst, r, (SkBlurMask::Style)fBlurStyle,
1587c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com                                margin, createMode);
1597c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com}
1607c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com
161d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com#include "SkCanvas.h"
162d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
163a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.comstatic bool prepare_to_draw_into_mask(const SkRect& bounds, SkMask* mask) {
164a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkASSERT(mask != NULL);
165a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
166a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    bounds.roundOut(&mask->fBounds);
167d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    mask->fRowBytes = SkAlign4(mask->fBounds.width());
168d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    mask->fFormat = SkMask::kA8_Format;
169a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const size_t size = mask->computeImageSize();
170d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    mask->fImage = SkMask::AllocImage(size);
171d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    if (NULL == mask->fImage) {
172d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com        return false;
173d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    }
174a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
175a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // FIXME: use sk_calloc in AllocImage?
176d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    sk_bzero(mask->fImage, size);
177a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    return true;
178a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com}
179a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
180a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.comstatic bool draw_rrect_into_mask(const SkRRect rrect, SkMask* mask) {
181a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    if (!prepare_to_draw_into_mask(rrect.rect(), mask)) {
182a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        return false;
183a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
184a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
185a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // FIXME: This code duplicates code in draw_rects_into_mask, below. Is there a
186a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // clean way to share more code?
187a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkBitmap bitmap;
188a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    bitmap.setConfig(SkBitmap::kA8_Config,
189a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com                     mask->fBounds.width(), mask->fBounds.height(),
190a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com                     mask->fRowBytes);
191a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    bitmap.setPixels(mask->fImage);
192a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
193a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkCanvas canvas(bitmap);
194a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    canvas.translate(-SkIntToScalar(mask->fBounds.left()),
195a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com                     -SkIntToScalar(mask->fBounds.top()));
196a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
197a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkPaint paint;
198a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    paint.setAntiAlias(true);
199a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    canvas.drawRRect(rrect, paint);
200a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    return true;
201a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com}
202a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
203a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.comstatic bool draw_rects_into_mask(const SkRect rects[], int count, SkMask* mask) {
204a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    if (!prepare_to_draw_into_mask(rects[0], mask)) {
205a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        return false;
206a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
207d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
208d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    SkBitmap bitmap;
209d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    bitmap.setConfig(SkBitmap::kA8_Config,
210d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com                     mask->fBounds.width(), mask->fBounds.height(),
211d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com                     mask->fRowBytes);
212d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    bitmap.setPixels(mask->fImage);
213d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
214d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    SkCanvas canvas(bitmap);
215dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    canvas.translate(-SkIntToScalar(mask->fBounds.left()),
216dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com                     -SkIntToScalar(mask->fBounds.top()));
217d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
218d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    SkPaint paint;
219d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    paint.setAntiAlias(true);
220d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
221dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    if (1 == count) {
222dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        canvas.drawRect(rects[0], paint);
223dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    } else {
224dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        // todo: do I need a fast way to do this?
225dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        SkPath path;
226dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        path.addRect(rects[0]);
227dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        path.addRect(rects[1]);
228dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        path.setFillType(SkPath::kEvenOdd_FillType);
229dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        canvas.drawPath(path, paint);
230dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    }
231d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    return true;
232d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com}
233d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
234f276fa74f56d0c691716163d3149fce5de97c9eareed@google.comstatic bool rect_exceeds(const SkRect& r, SkScalar v) {
235f276fa74f56d0c691716163d3149fce5de97c9eareed@google.com    return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v ||
236f276fa74f56d0c691716163d3149fce5de97c9eareed@google.com           r.width() > v || r.height() > v;
23707784a041925f9a921e390e782195a622c76fbfareed@google.com}
23807784a041925f9a921e390e782195a622c76fbfareed@google.com
239a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.comSkMaskFilter::FilterReturn
240a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.comSkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& matrix,
241a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com                                        const SkIRect& clipBounds,
242a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com                                        NinePatch* patch) const {
243a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkASSERT(patch != NULL);
244a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    switch (rrect.getType()) {
245a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        case SkRRect::kUnknown_Type:
246a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            // Unknown should never be returned.
247a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            SkASSERT(false);
248a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            // Fall through.
249a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        case SkRRect::kEmpty_Type:
250a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            // Nothing to draw.
251a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            return kFalse_FilterReturn;
252a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
253a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        case SkRRect::kRect_Type:
254a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            // We should have caught this earlier.
255a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            SkASSERT(false);
256a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            // Fall through.
257a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        case SkRRect::kOval_Type:
258a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            // The nine patch special case does not handle ovals, and we
259a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            // already have code for rectangles.
260a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            return kUnimplemented_FilterReturn;
261a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
262a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        case SkRRect::kSimple_Type:
263a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            // Fall through.
264a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        case SkRRect::kComplex_Type:
265a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            // These can take advantage of this fast path.
266a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            break;
267a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
268a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
269a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // TODO: report correct metrics for innerstyle, where we do not grow the
270a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // total bounds, but we do need an inset the size of our blur-radius
271a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle) {
272a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        return kUnimplemented_FilterReturn;
273a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
274a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
275a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // TODO: take clipBounds into account to limit our coordinates up front
276a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // for now, just skip too-large src rects (to take the old code path).
277a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    if (rect_exceeds(rrect.rect(), SkIntToScalar(32767))) {
278a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        return kUnimplemented_FilterReturn;
279a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
280a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
281a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkIPoint margin;
282a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkMask  srcM, dstM;
283a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    rrect.rect().roundOut(&srcM.fBounds);
284a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    srcM.fImage = NULL;
285a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    srcM.fFormat = SkMask::kA8_Format;
286a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    srcM.fRowBytes = 0;
287a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
288a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    if (!this->filterMask(&dstM, srcM, matrix, &margin)) {
289a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        return kFalse_FilterReturn;
290a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
291a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
292a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // Now figure out the appropriate width and height of the smaller round rectangle
293a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // to stretch. It will take into account the larger radius per side as well as double
294a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // the margin, to account for inner and outer blur.
295a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkVector& UL = rrect.radii(SkRRect::kUpperLeft_Corner);
296a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkVector& UR = rrect.radii(SkRRect::kUpperRight_Corner);
297a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkVector& LR = rrect.radii(SkRRect::kLowerRight_Corner);
298a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkVector& LL = rrect.radii(SkRRect::kLowerLeft_Corner);
299a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
300a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkScalar leftUnstretched = SkTMax(UL.fX, LL.fX) + SkIntToScalar(2 * margin.fX);
301a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkScalar rightUnstretched = SkTMax(UR.fX, LR.fX) + SkIntToScalar(2 * margin.fX);
302a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
303a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // Extra space in the middle to ensure an unchanging piece for stretching. Use 3 to cover
304a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // any fractional space on either side plus 1 for the part to stretch.
305a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkScalar stretchSize = SkIntToScalar(3);
306a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
307a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkScalar totalSmallWidth = leftUnstretched + rightUnstretched + stretchSize;
308a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    if (totalSmallWidth >= rrect.rect().width()) {
309a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        // There is no valid piece to stretch.
310a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        return kUnimplemented_FilterReturn;
311a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
312a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
313a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkScalar topUnstretched = SkTMax(UL.fY, UR.fY) + SkIntToScalar(2 * margin.fY);
314a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkScalar bottomUnstretched = SkTMax(LL.fY, LR.fY) + SkIntToScalar(2 * margin.fY);
315a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
316a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkScalar totalSmallHeight = topUnstretched + bottomUnstretched + stretchSize;
317a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    if (totalSmallHeight >= rrect.rect().height()) {
318a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        // There is no valid piece to stretch.
319a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        return kUnimplemented_FilterReturn;
320a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
321a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
322a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkRect smallR = SkRect::MakeWH(totalSmallWidth, totalSmallHeight);
323a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
324a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkRRect smallRR;
325a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkVector radii[4];
326a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    radii[SkRRect::kUpperLeft_Corner] = UL;
327a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    radii[SkRRect::kUpperRight_Corner] = UR;
328a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    radii[SkRRect::kLowerRight_Corner] = LR;
329a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    radii[SkRRect::kLowerLeft_Corner] = LL;
330a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    smallRR.setRectRadii(smallR, radii);
331a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
332a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    if (!draw_rrect_into_mask(smallRR, &srcM)) {
333a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        return kFalse_FilterReturn;
334a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
335a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
336ad99358bdd7ca4ffb047121946abf0d5fdbde1e8robertphillips@google.com    SkAutoMaskFreeImage amf(srcM.fImage);
337ad99358bdd7ca4ffb047121946abf0d5fdbde1e8robertphillips@google.com
338a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
339a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        return kFalse_FilterReturn;
340a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
341a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
342a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    patch->fMask.fBounds.offsetTo(0, 0);
343a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    patch->fOuterRect = dstM.fBounds;
344a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    patch->fCenter.fX = SkScalarCeilToInt(leftUnstretched) + 1;
345a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    patch->fCenter.fY = SkScalarCeilToInt(topUnstretched) + 1;
346a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    return kTrue_FilterReturn;
347a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com}
348a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
3497c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com#ifdef SK_IGNORE_FAST_RECT_BLUR
350e86af1f4bacd4a9aa99a09905e29b3cf4cea9322humper@google.comSK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", false, "Use the faster analytic blur approach for ninepatch rects" );
3517c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com#else
352e86af1f4bacd4a9aa99a09905e29b3cf4cea9322humper@google.comSK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", true, "Use the faster analytic blur approach for ninepatch rects" );
3537c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com#endif
3547c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com
355d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.comSkMaskFilter::FilterReturn
356dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.comSkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
357dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com                                        const SkMatrix& matrix,
358dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com                                        const SkIRect& clipBounds,
35930711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.com                                        NinePatch* patch) const {
360dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    if (count < 1 || count > 2) {
361dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        return kUnimplemented_FilterReturn;
362dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    }
3633458716b52aa25dcd1b270141c7628c380696e35skia.committer@gmail.com
36457850b9daddd941f880d94faaf83f2169355a0c8reed@google.com    // TODO: report correct metrics for innerstyle, where we do not grow the
36557850b9daddd941f880d94faaf83f2169355a0c8reed@google.com    // total bounds, but we do need an inset the size of our blur-radius
36696ac2f693b3a4b7bb504ec2a13b15eeeaa5ff1fdrobertphillips@google.com    if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle ||
36796ac2f693b3a4b7bb504ec2a13b15eeeaa5ff1fdrobertphillips@google.com        SkBlurMaskFilter::kOuter_BlurStyle == fBlurStyle) {
36857850b9daddd941f880d94faaf83f2169355a0c8reed@google.com        return kUnimplemented_FilterReturn;
36957850b9daddd941f880d94faaf83f2169355a0c8reed@google.com    }
37057850b9daddd941f880d94faaf83f2169355a0c8reed@google.com
37107784a041925f9a921e390e782195a622c76fbfareed@google.com    // TODO: take clipBounds into account to limit our coordinates up front
37207784a041925f9a921e390e782195a622c76fbfareed@google.com    // for now, just skip too-large src rects (to take the old code path).
373f276fa74f56d0c691716163d3149fce5de97c9eareed@google.com    if (rect_exceeds(rects[0], SkIntToScalar(32767))) {
37407784a041925f9a921e390e782195a622c76fbfareed@google.com        return kUnimplemented_FilterReturn;
37507784a041925f9a921e390e782195a622c76fbfareed@google.com    }
3763458716b52aa25dcd1b270141c7628c380696e35skia.committer@gmail.com
377d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    SkIPoint margin;
378d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    SkMask  srcM, dstM;
379dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    rects[0].roundOut(&srcM.fBounds);
380d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    srcM.fImage = NULL;
381d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    srcM.fFormat = SkMask::kA8_Format;
382d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    srcM.fRowBytes = 0;
3832e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
3847c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    bool filterResult = false;
3857c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    if (count == 1 && c_analyticBlurNinepatch) {
3867c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        // special case for fast rect blur
3877c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        // don't actually do the blur the first time, just compute the correct size
3882e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com        filterResult = this->filterRectMask(&dstM, rects[0], matrix, &margin,
3897c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com                                            SkMask::kJustComputeBounds_CreateMode);
3907c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    } else {
3917c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
3927c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    }
3932e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
3947c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    if (!filterResult) {
395d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com        return kFalse_FilterReturn;
396d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    }
397d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
398d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    /*
399d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  smallR is the smallest version of 'rect' that will still guarantee that
400d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  we get the same blur results on all edges, plus 1 center row/col that is
401d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  representative of the extendible/stretchable edges of the ninepatch.
402d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  Since our actual edge may be fractional we inset 1 more to be sure we
403d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  don't miss any interior blur.
404d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  x is an added pixel of blur, and { and } are the (fractional) edge
405d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  pixels from the original rect.
406d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *
407d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *   x x { x x .... x x } x x
408d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *
409d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  Thus, in this case, we inset by a total of 5 (on each side) beginning
410d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  with our outer-rect (dstM.fBounds)
411d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     */
412dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    SkRect smallR[2];
413dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    SkIPoint center;
414dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com
415dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    // +2 is from +1 for each edge (to account for possible fractional edges
416dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    int smallW = dstM.fBounds.width() - srcM.fBounds.width() + 2;
417dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    int smallH = dstM.fBounds.height() - srcM.fBounds.height() + 2;
418dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    SkIRect innerIR;
419dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com
420dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    if (1 == count) {
421dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        innerIR = srcM.fBounds;
422dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        center.set(smallW, smallH);
423dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    } else {
424dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        SkASSERT(2 == count);
425dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        rects[1].roundIn(&innerIR);
426dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        center.set(smallW + (innerIR.left() - srcM.fBounds.left()),
427dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com                   smallH + (innerIR.top() - srcM.fBounds.top()));
428dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    }
429dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com
430dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    // +1 so we get a clean, stretchable, center row/col
431dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    smallW += 1;
432dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    smallH += 1;
433dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com
434dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    // we want the inset amounts to be integral, so we don't change any
435dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    // fractional phase on the fRight or fBottom of our smallR.
436dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    const SkScalar dx = SkIntToScalar(innerIR.width() - smallW);
437dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    const SkScalar dy = SkIntToScalar(innerIR.height() - smallH);
438dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    if (dx < 0 || dy < 0) {
439dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        // we're too small, relative to our blur, to break into nine-patch,
440dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        // so we ask to have our normal filterMask() be called.
441dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        return kUnimplemented_FilterReturn;
442dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    }
443dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com
444dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    smallR[0].set(rects[0].left(), rects[0].top(), rects[0].right() - dx, rects[0].bottom() - dy);
445112a23e0fa027b423a656f0a1aa06868617e982arobertphillips@google.com    if (smallR[0].width() < 2 || smallR[0].height() < 2) {
446112a23e0fa027b423a656f0a1aa06868617e982arobertphillips@google.com        return kUnimplemented_FilterReturn;
447112a23e0fa027b423a656f0a1aa06868617e982arobertphillips@google.com    }
448dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    if (2 == count) {
449dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        smallR[1].set(rects[1].left(), rects[1].top(),
450dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com                      rects[1].right() - dx, rects[1].bottom() - dy);
451dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        SkASSERT(!smallR[1].isEmpty());
452d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    }
453d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
4547c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    if (count > 1 || !c_analyticBlurNinepatch) {
455a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        if (!draw_rects_into_mask(smallR, count, &srcM)) {
4567c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com            return kFalse_FilterReturn;
4577c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        }
458d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
4597c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        SkAutoMaskFreeImage amf(srcM.fImage);
460d198a5b8a706d2bcfa94e351d3a41f5379777e4areed@google.com
4617c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
4627c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com            return kFalse_FilterReturn;
4637c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        }
4647c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    } else {
4652e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com        if (!this->filterRectMask(&patch->fMask, smallR[0], matrix, &margin,
4667c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com                                  SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
4677c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com            return kFalse_FilterReturn;
4687c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        }
469d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    }
470dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    patch->fMask.fBounds.offsetTo(0, 0);
471dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    patch->fOuterRect = dstM.fBounds;
472dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    patch->fCenter = center;
473d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    return kTrue_FilterReturn;
474d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com}
475d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
47630711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.comvoid SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
47730711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.com                                             SkRect* dst) const {
4787ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkScalar pad = 3.0f * fSigma;
47917ad2bd077af50dcaca18cf00607b194a1491a44robertphillips@google.com
48017ad2bd077af50dcaca18cf00607b194a1491a44robertphillips@google.com    dst->set(src.fLeft  - pad, src.fTop    - pad,
48117ad2bd077af50dcaca18cf00607b194a1491a44robertphillips@google.com             src.fRight + pad, src.fBottom + pad);
4829efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com}
4839efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com
48403016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.comSkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkFlattenableReadBuffer& buffer)
48503016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com        : SkMaskFilter(buffer) {
48611e055518a0cbe5329232a55fe2cd177e83836d8robertphillips@google.com#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO
48711e055518a0cbe5329232a55fe2cd177e83836d8robertphillips@google.com    // TODO: when the skps are recaptured at > v15 the SkScalarAbs can be removed
4887ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com#endif
48911e055518a0cbe5329232a55fe2cd177e83836d8robertphillips@google.com    fSigma = SkScalarAbs(buffer.readScalar());
490c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    fBlurStyle = (SkBlurMaskFilter::BlurStyle)buffer.readInt();
491c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    fBlurFlags = buffer.readUInt() & SkBlurMaskFilter::kAll_BlurFlag;
4927ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkASSERT(fSigma >= 0);
4938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((unsigned)fBlurStyle < SkBlurMaskFilter::kBlurStyleCount);
4948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
49654924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.comvoid SkBlurMaskFilterImpl::flatten(SkFlattenableWriteBuffer& buffer) const {
4978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->INHERITED::flatten(buffer);
49811e055518a0cbe5329232a55fe2cd177e83836d8robertphillips@google.com    buffer.writeScalar(fSigma);
499c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    buffer.writeInt(fBlurStyle);
500c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    buffer.writeUInt(fBlurFlags);
5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
503491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#if SK_SUPPORT_GPU
5042b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com
505491493119c11206c5823b76eb6420a705be243a1robertphillips@google.combool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds,
506491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com                                            const SkIRect& clipBounds,
507491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com                                            const SkMatrix& ctm,
508491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com                                            SkRect* maskRect) const {
5097ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkScalar xformedSigma = this->computeXformedSigma(ctm);
5107ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    if (xformedSigma <= 0) {
511491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        return false;
5122b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com    }
513491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
5147ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    static const SkScalar kMIN_GPU_BLUR_SIZE  = SkIntToScalar(64);
5157ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    static const SkScalar kMIN_GPU_BLUR_SIGMA = SkIntToScalar(32);
516491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
517491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    if (srcBounds.width() <= kMIN_GPU_BLUR_SIZE &&
518491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        srcBounds.height() <= kMIN_GPU_BLUR_SIZE &&
5197ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com        xformedSigma <= kMIN_GPU_BLUR_SIGMA) {
520491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        // We prefer to blur small rect with small radius via CPU.
521491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        return false;
522491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    }
523491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
524491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    if (NULL == maskRect) {
525491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        // don't need to compute maskRect
526491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        return true;
527491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    }
528491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
5297ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    float sigma3 = 3 * SkScalarToFloat(xformedSigma);
530491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
5314469938e92d779dff05e745559e67907bbf21e78reed@google.com    SkRect clipRect = SkRect::Make(clipBounds);
532491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    SkRect srcRect(srcBounds);
533491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
534491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    // Outset srcRect and clipRect by 3 * sigma, to compute affected blur area.
5354b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org    srcRect.outset(sigma3, sigma3);
5364b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org    clipRect.outset(sigma3, sigma3);
537491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    srcRect.intersect(clipRect);
538491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    *maskRect = srcRect;
5391842adf01320f9197b449de7375d08ccac43f389skia.committer@gmail.com    return true;
540491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com}
541491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
5421842adf01320f9197b449de7375d08ccac43f389skia.committer@gmail.combool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src,
5431842adf01320f9197b449de7375d08ccac43f389skia.committer@gmail.com                                         const SkRect& maskRect,
544491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com                                         GrTexture** result,
545491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com                                         bool canOverwriteSrc) const {
546491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
547491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
548491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    GrContext* context = src->getContext();
549491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
550491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    GrContext::AutoWideOpenIdentityDraw awo(context, NULL);
551491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
5527ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkScalar xformedSigma = this->computeXformedSigma(context->getMatrix());
5537ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkASSERT(xformedSigma > 0);
554491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
555491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    // If we're doing a normal blur, we can clobber the pathTexture in the
556491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    // gaussianBlur.  Otherwise, we need to save it for later compositing.
557491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    bool isNormalBlur = (SkBlurMaskFilter::kNormal_BlurStyle == fBlurStyle);
558736dd031f177681bfa284e19291ef031ad0822d5robertphillips@google.com    *result = SkGpuBlurUtils::GaussianBlur(context, src, isNormalBlur && canOverwriteSrc,
5597ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com                                           clipRect, false, xformedSigma, xformedSigma);
5603cc820c0504dc6de081d08391affe68b69031c63robertphillips@google.com    if (NULL == *result) {
561491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        return false;
562491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    }
563491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
564491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    if (!isNormalBlur) {
565491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        context->setIdentityMatrix();
566491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        GrPaint paint;
567491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        SkMatrix matrix;
568491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        matrix.setIDiv(src->width(), src->height());
569491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        // Blend pathTexture over blurTexture.
570491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        GrContext::AutoRenderTarget art(context, (*result)->asRenderTarget());
57142dacab4e7366d9f53989558cc8d045c3d065bcdcommit-bot@chromium.org        paint.addColorEffect(GrSimpleTextureEffect::Create(src, matrix))->unref();
572491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle) {
573491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com            // inner:  dst = dst * src
574491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com            paint.setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff);
575491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        } else if (SkBlurMaskFilter::kSolid_BlurStyle == fBlurStyle) {
576491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com            // solid:  dst = src + dst - src * dst
577491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com            //             = (1 - dst) * src + 1 * dst
578491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com            paint.setBlendFunc(kIDC_GrBlendCoeff, kOne_GrBlendCoeff);
579491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        } else if (SkBlurMaskFilter::kOuter_BlurStyle == fBlurStyle) {
580491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com            // outer:  dst = dst * (1 - src)
581491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com            //             = 0 * src + (1 - src) * dst
582491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com            paint.setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff);
583491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        }
584491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        context->drawRect(paint, clipRect);
585491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    }
586491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
587491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    return true;
5882b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com}
5892b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com
590491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#endif // SK_SUPPORT_GPU
591491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
592491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
5930bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com#ifdef SK_DEVELOPER
5940bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.comvoid SkBlurMaskFilterImpl::toString(SkString* str) const {
5950bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    str->append("SkBlurMaskFilterImpl: (");
5960bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com
5977ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    str->append("sigma: ");
5987ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    str->appendScalar(fSigma);
5990bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    str->append(" ");
6000bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com
6010bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    static const char* gStyleName[SkBlurMaskFilter::kBlurStyleCount] = {
6020bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com        "normal", "solid", "outer", "inner"
6030bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    };
6040bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com
6050bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    str->appendf("style: %s ", gStyleName[fBlurStyle]);
6060bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    str->append("flags: (");
6070bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    if (fBlurFlags) {
6080bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com        bool needSeparator = false;
6098eaddb0089a170760e157646192813bd940c26e7skia.committer@gmail.com        SkAddFlagToString(str,
6108eaddb0089a170760e157646192813bd940c26e7skia.committer@gmail.com                          SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag),
6110bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com                          "IgnoreXform", &needSeparator);
6128eaddb0089a170760e157646192813bd940c26e7skia.committer@gmail.com        SkAddFlagToString(str,
6138eaddb0089a170760e157646192813bd940c26e7skia.committer@gmail.com                          SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag),
6140bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com                          "HighQuality", &needSeparator);
6150bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    } else {
6160bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com        str->append("None");
6170bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    }
6180bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    str->append("))");
6190bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com}
6200bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com#endif
6210bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com
622d26147adbbdca85f07dff432025afee0c8614387caryclark@google.comSK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
623d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
624d26147adbbdca85f07dff432025afee0c8614387caryclark@google.comSK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
625