1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlurMaskFilter.h"
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlurMask.h"
10736dd031f177681bfa284e19291ef031ad0822d5robertphillips@google.com#include "SkGpuBlurUtils.h"
118b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
128b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.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
2030c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips#include "GrCircleBlurFragmentProcessor.h"
21491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#include "GrContext.h"
22ea4615034498aca2f9ca1753fb9a1ef10508d8ccrobertphillips#include "GrDrawContext.h"
23491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#include "GrTexture.h"
246251d17dfadbbeba8a7e72affde5cbdbd0c0c95fbsalomon#include "GrFragmentProcessor.h"
25605dd0fbce9dbb2a0d3313e13e161f2bd54870d7egdaniel#include "GrInvariantOutput.h"
263d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org#include "SkDraw.h"
27eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "effects/GrSimpleTextureEffect.h"
2864c4728c70001ed074fecf5c4e083781987b12e9egdaniel#include "glsl/GrGLSLFragmentProcessor.h"
292d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel#include "glsl/GrGLSLFragmentShaderBuilder.h"
30018fb62d12d1febf121fe265da5b6117b86a6541egdaniel#include "glsl/GrGLSLProgramDataManager.h"
317dc4bd06fca73a97dcf3ad4a7425597160f1edfcegdaniel#include "glsl/GrGLSLTextureSampler.h"
327ea439b2203855db97330b25945b87dd4b170b8begdaniel#include "glsl/GrGLSLUniformHandler.h"
33491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#endif
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
35508022cff04c5226cfd1714ba049528f57f9f25ecommit-bot@chromium.orgSkScalar SkBlurMaskFilter::ConvertRadiusToSigma(SkScalar radius) {
36508022cff04c5226cfd1714ba049528f57f9f25ecommit-bot@chromium.org    return SkBlurMask::ConvertRadiusToSigma(radius);
37508022cff04c5226cfd1714ba049528f57f9f25ecommit-bot@chromium.org}
38508022cff04c5226cfd1714ba049528f57f9f25ecommit-bot@chromium.org
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkBlurMaskFilterImpl : public SkMaskFilter {
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
41e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle, uint32_t flags);
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // overrides from SkMaskFilter
4436352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkMask::Format getFormat() const override;
45ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips    bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
46ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                    SkIPoint* margin) const override;
472e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
48491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#if SK_SUPPORT_GPU
4930c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    bool canFilterMaskGPU(const SkRRect& devRRect,
50ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                          const SkIRect& clipBounds,
51ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                          const SkMatrix& ctm,
52ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                          SkRect* maskRect) const override;
53ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips    bool directFilterMaskGPU(GrTextureProvider* texProvider,
54ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                             GrDrawContext* drawContext,
55ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                             GrPaint* grp,
56ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                             const GrClip&,
57ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                             const SkMatrix& viewMatrix,
58ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                             const SkStrokeRec& strokeRec,
59ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                             const SkPath& path) const override;
60ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips    bool directFilterRRectMaskGPU(GrTextureProvider* texProvider,
61ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                                  GrDrawContext* drawContext,
62ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                                  GrPaint* grp,
63ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                                  const GrClip&,
64ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                                  const SkMatrix& viewMatrix,
65ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                                  const SkStrokeRec& strokeRec,
66ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                                  const SkRRect& rrect) const override;
67ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips    bool filterMaskGPU(GrTexture* src,
68ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                       const SkMatrix& ctm,
69ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                       const SkRect& maskRect,
70ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                       GrTexture** result,
71ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                       bool canOverwriteSrc) const override;
72491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#endif
73491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
7436352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void computeFastBounds(const SkRect&, SkRect*) const override;
7536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool asABlur(BlurRec*) const override;
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
770f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org    SK_TO_STRING_OVERRIDE()
78ba28d03e94dc221d6a803bf2a84a420b9159255cdjsollen@google.com    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
80d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.comprotected:
81ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips    FilterReturn filterRectsToNine(const SkRect[], int count, const SkMatrix&,
82ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                                   const SkIRect& clipBounds,
83ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                                   NinePatch*) const override;
842e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
85ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips    FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&,
86ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                                   const SkIRect& clipBounds,
87ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                                   NinePatch*) const override;
88a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
892e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com    bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix,
907c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com                        SkIPoint* margin, SkMask::CreateMode createMode) const;
91a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org    bool filterRRectMask(SkMask* dstM, const SkRRect& r, const SkMatrix& matrix,
92a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org                        SkIPoint* margin, SkMask::CreateMode createMode) const;
93453995e01d884d62ce2e808e0067e494c0c9c7faskia.committer@gmail.com
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
95491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    // To avoid unseemly allocation requests (esp. for finite platforms like
96491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    // handset) we limit the radius so something manageable. (as opposed to
97491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    // a request like 10,000)
987ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    static const SkScalar kMAX_BLUR_SIGMA;
997ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com
100e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    SkScalar    fSigma;
101e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    SkBlurStyle fBlurStyle;
102e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    uint32_t    fBlurFlags;
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
104daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    SkBlurQuality getQuality() const {
105daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        return (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
106daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                kHigh_SkBlurQuality : kLow_SkBlurQuality;
107daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    }
108daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
1098b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org    SkBlurMaskFilterImpl(SkReadBuffer&);
11036352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void flatten(SkWriteBuffer&) const override;
1117ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com
1127ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkScalar computeXformedSigma(const SkMatrix& ctm) const {
113491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        bool ignoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
114491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
1157ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com        SkScalar xformedSigma = ignoreTransform ? fSigma : ctm.mapRadius(fSigma);
1167ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com        return SkMinScalar(xformedSigma, kMAX_BLUR_SIGMA);
117491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    }
118fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1199fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    friend class SkBlurMaskFilter;
1209fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    typedef SkMaskFilter INHERITED;
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1247ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.comconst SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_SIGMA = SkIntToScalar(128);
125491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
126e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.orgSkMaskFilter* SkBlurMaskFilter::Create(SkBlurStyle style, SkScalar sigma, uint32_t flags) {
127e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    if (!SkScalarIsFinite(sigma) || sigma <= 0) {
12896fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
12903016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com    }
130e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    if ((unsigned)style > (unsigned)kLastEnum_SkBlurStyle) {
13196fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
132e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    }
133e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    if (flags > SkBlurMaskFilter::kAll_BlurFlag) {
13496fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
135e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    }
136385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary    return new SkBlurMaskFilterImpl(sigma, style, flags);
137e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org}
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13903016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com///////////////////////////////////////////////////////////////////////////////
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
141e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.orgSkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle style, uint32_t flags)
142e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    : fSigma(sigma)
143e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    , fBlurStyle(style)
144e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    , fBlurFlags(flags) {
145e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    SkASSERT(fSigma > 0);
146e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    SkASSERT((unsigned)style <= kLastEnum_SkBlurStyle);
147038aff623d9fd47946cd31685f74cf473f7c84f0senorblanco@chromium.org    SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
15030711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.comSkMask::Format SkBlurMaskFilterImpl::getFormat() const {
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkMask::kA8_Format;
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
154daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.combool SkBlurMaskFilterImpl::asABlur(BlurRec* rec) const {
155daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
156daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        return false;
157daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    }
158daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
159daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    if (rec) {
160daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        rec->fSigma = fSigma;
161daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        rec->fStyle = fBlurStyle;
162daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        rec->fQuality = this->getQuality();
163daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    }
164daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    return true;
165daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com}
166daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
16703016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.combool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
16830711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.com                                      const SkMatrix& matrix,
16930c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips                                      SkIPoint* margin) const {
1707ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkScalar sigma = this->computeXformedSigma(matrix);
171daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    return SkBlurMask::BoxBlur(dst, src, sigma, fBlurStyle, this->getQuality(), margin);
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1747c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.combool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
1757c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com                                          const SkMatrix& matrix,
17630c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips                                          SkIPoint* margin, SkMask::CreateMode createMode) const {
1777ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkScalar sigma = computeXformedSigma(matrix);
1787c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com
17930c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    return SkBlurMask::BlurRect(sigma, dst, r, fBlurStyle, margin, createMode);
1807c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com}
1817c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com
182a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.orgbool SkBlurMaskFilterImpl::filterRRectMask(SkMask* dst, const SkRRect& r,
183a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org                                          const SkMatrix& matrix,
18430c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips                                          SkIPoint* margin, SkMask::CreateMode createMode) const {
185a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org    SkScalar sigma = computeXformedSigma(matrix);
186a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org
18730c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    return SkBlurMask::BlurRRect(sigma, dst, r, fBlurStyle, margin, createMode);
188a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org}
189a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org
190d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com#include "SkCanvas.h"
191d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
192a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.comstatic bool prepare_to_draw_into_mask(const SkRect& bounds, SkMask* mask) {
19396fcdcc219d2a0d3579719b84b28bede76efba64halcanary    SkASSERT(mask != nullptr);
194a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
195b07a94f1cba3976596ae1a7f23d8c2043ba353f3reed    mask->fBounds = bounds.roundOut();
196d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    mask->fRowBytes = SkAlign4(mask->fBounds.width());
197d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    mask->fFormat = SkMask::kA8_Format;
198a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const size_t size = mask->computeImageSize();
199d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    mask->fImage = SkMask::AllocImage(size);
20096fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (nullptr == mask->fImage) {
201d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com        return false;
202d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    }
203a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
204a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // FIXME: use sk_calloc in AllocImage?
205d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    sk_bzero(mask->fImage, size);
206a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    return true;
207a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com}
208a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
209a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.comstatic bool draw_rrect_into_mask(const SkRRect rrect, SkMask* mask) {
210a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    if (!prepare_to_draw_into_mask(rrect.rect(), mask)) {
211a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        return false;
212a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
213a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
214a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // FIXME: This code duplicates code in draw_rects_into_mask, below. Is there a
215a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // clean way to share more code?
216a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkBitmap bitmap;
217dac522589e9395b4654a1a708f1bd971f37f95a5commit-bot@chromium.org    bitmap.installMaskPixels(*mask);
218a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
219a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkCanvas canvas(bitmap);
220a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    canvas.translate(-SkIntToScalar(mask->fBounds.left()),
221a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com                     -SkIntToScalar(mask->fBounds.top()));
222a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
223a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkPaint paint;
224a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    paint.setAntiAlias(true);
225a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    canvas.drawRRect(rrect, paint);
226a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    return true;
227a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com}
228a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
229a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.comstatic bool draw_rects_into_mask(const SkRect rects[], int count, SkMask* mask) {
230a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    if (!prepare_to_draw_into_mask(rects[0], mask)) {
231a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        return false;
232a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
233d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
234d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    SkBitmap bitmap;
235e24ad23ae67ffcb0dc545b7e426cf08d102e0868commit-bot@chromium.org    bitmap.installPixels(SkImageInfo::Make(mask->fBounds.width(),
236e24ad23ae67ffcb0dc545b7e426cf08d102e0868commit-bot@chromium.org                                           mask->fBounds.height(),
237e24ad23ae67ffcb0dc545b7e426cf08d102e0868commit-bot@chromium.org                                           kAlpha_8_SkColorType,
238e24ad23ae67ffcb0dc545b7e426cf08d102e0868commit-bot@chromium.org                                           kPremul_SkAlphaType),
23900f8d6c75d22ce8f95f932c5b101354b196fa0dfcommit-bot@chromium.org                         mask->fImage, mask->fRowBytes);
240d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
241d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    SkCanvas canvas(bitmap);
242dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    canvas.translate(-SkIntToScalar(mask->fBounds.left()),
243dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com                     -SkIntToScalar(mask->fBounds.top()));
244d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
245d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    SkPaint paint;
246d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    paint.setAntiAlias(true);
247d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
248dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    if (1 == count) {
249dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        canvas.drawRect(rects[0], paint);
250dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    } else {
251dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        // todo: do I need a fast way to do this?
252dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        SkPath path;
253dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        path.addRect(rects[0]);
254dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        path.addRect(rects[1]);
255dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        path.setFillType(SkPath::kEvenOdd_FillType);
256dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        canvas.drawPath(path, paint);
257dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    }
258d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    return true;
259d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com}
260d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
261f276fa74f56d0c691716163d3149fce5de97c9eareed@google.comstatic bool rect_exceeds(const SkRect& r, SkScalar v) {
262f276fa74f56d0c691716163d3149fce5de97c9eareed@google.com    return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v ||
263f276fa74f56d0c691716163d3149fce5de97c9eareed@google.com           r.width() > v || r.height() > v;
26407784a041925f9a921e390e782195a622c76fbfareed@google.com}
26507784a041925f9a921e390e782195a622c76fbfareed@google.com
266eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao#include "SkMaskCache.h"
267eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao
268b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reedstatic SkCachedData* copy_mask_to_cacheddata(SkMask* mask) {
269b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed    const size_t size = mask->computeTotalImageSize();
270eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao    SkCachedData* data = SkResourceCache::NewCachedData(size);
271eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao    if (data) {
272b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed        memcpy(data->writable_data(), mask->fImage, size);
273b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed        SkMask::FreeImage(mask->fImage);
274b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed        mask->fImage = (uint8_t*)data->data();
275eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao    }
276b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed    return data;
277eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao}
278eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao
279b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reedstatic SkCachedData* find_cached_rrect(SkMask* mask, SkScalar sigma, SkBlurStyle style,
280b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed                                       SkBlurQuality quality, const SkRRect& rrect) {
281b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed    return SkMaskCache::FindAndRef(sigma, style, quality, rrect, mask);
282eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao}
283eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao
284b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reedstatic SkCachedData* add_cached_rrect(SkMask* mask, SkScalar sigma, SkBlurStyle style,
285b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed                                      SkBlurQuality quality, const SkRRect& rrect) {
286b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed    SkCachedData* cache = copy_mask_to_cacheddata(mask);
287b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed    if (cache) {
288b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed        SkMaskCache::Add(sigma, style, quality, rrect, *mask, cache);
289eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao    }
290b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed    return cache;
291eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao}
292eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao
293b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reedstatic SkCachedData* find_cached_rects(SkMask* mask, SkScalar sigma, SkBlurStyle style,
294b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed                                       SkBlurQuality quality, const SkRect rects[], int count) {
295b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed    return SkMaskCache::FindAndRef(sigma, style, quality, rects, count, mask);
296eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao}
297eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao
298b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reedstatic SkCachedData* add_cached_rects(SkMask* mask, SkScalar sigma, SkBlurStyle style,
299b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed                                      SkBlurQuality quality, const SkRect rects[], int count) {
300b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed    SkCachedData* cache = copy_mask_to_cacheddata(mask);
301b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed    if (cache) {
302b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed        SkMaskCache::Add(sigma, style, quality, rects, count, *mask, cache);
303eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao    }
304b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed    return cache;
305eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao}
306eabd0d73eebb940ec5ea06625f612a80156b61dbqiankun.miao
307a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org#ifdef SK_IGNORE_FAST_RRECT_BLUR
308a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholasSK_CONF_DECLARE(bool, c_analyticBlurRRect, "mask.filter.blur.analyticblurrrect", false, "Use the faster analytic blur approach for ninepatch rects");
309a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org#else
310a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholasSK_CONF_DECLARE(bool, c_analyticBlurRRect, "mask.filter.blur.analyticblurrrect", true, "Use the faster analytic blur approach for ninepatch round rects");
311a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org#endif
312a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org
313a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.comSkMaskFilter::FilterReturn
314a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.comSkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& matrix,
315a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com                                        const SkIRect& clipBounds,
316a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com                                        NinePatch* patch) const {
31796fcdcc219d2a0d3579719b84b28bede76efba64halcanary    SkASSERT(patch != nullptr);
318a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    switch (rrect.getType()) {
319a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        case SkRRect::kEmpty_Type:
320a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            // Nothing to draw.
321a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            return kFalse_FilterReturn;
322a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
323a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        case SkRRect::kRect_Type:
324a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            // We should have caught this earlier.
325a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            SkASSERT(false);
326a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            // Fall through.
327a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        case SkRRect::kOval_Type:
328a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            // The nine patch special case does not handle ovals, and we
329a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            // already have code for rectangles.
330a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            return kUnimplemented_FilterReturn;
331a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
332f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org        // These three can take advantage of this fast path.
333a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        case SkRRect::kSimple_Type:
334f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org        case SkRRect::kNinePatch_Type:
335a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        case SkRRect::kComplex_Type:
336a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com            break;
337a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
338a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
339a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // TODO: report correct metrics for innerstyle, where we do not grow the
340a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // total bounds, but we do need an inset the size of our blur-radius
341e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    if (kInner_SkBlurStyle == fBlurStyle) {
342a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        return kUnimplemented_FilterReturn;
343a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
344a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
345a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // TODO: take clipBounds into account to limit our coordinates up front
346a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // for now, just skip too-large src rects (to take the old code path).
347a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    if (rect_exceeds(rrect.rect(), SkIntToScalar(32767))) {
348a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        return kUnimplemented_FilterReturn;
349a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
350a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
351a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkIPoint margin;
352a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkMask  srcM, dstM;
353b07a94f1cba3976596ae1a7f23d8c2043ba353f3reed    srcM.fBounds = rrect.rect().roundOut();
354a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    srcM.fFormat = SkMask::kA8_Format;
355a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    srcM.fRowBytes = 0;
356a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
357a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org    bool filterResult = false;
358a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org    if (c_analyticBlurRRect) {
359a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org        // special case for fast round rect blur
360a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org        // don't actually do the blur the first time, just compute the correct size
361a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org        filterResult = this->filterRRectMask(&dstM, rrect, matrix, &margin,
362a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org                                            SkMask::kJustComputeBounds_CreateMode);
363a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org    }
364a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org
365a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org    if (!filterResult) {
366a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org        filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
367a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org    }
368a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org
369a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org    if (!filterResult) {
370a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        return kFalse_FilterReturn;
371a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
372a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
373a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // Now figure out the appropriate width and height of the smaller round rectangle
374a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // to stretch. It will take into account the larger radius per side as well as double
375a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // the margin, to account for inner and outer blur.
376a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkVector& UL = rrect.radii(SkRRect::kUpperLeft_Corner);
377a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkVector& UR = rrect.radii(SkRRect::kUpperRight_Corner);
378a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkVector& LR = rrect.radii(SkRRect::kLowerRight_Corner);
379a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkVector& LL = rrect.radii(SkRRect::kLowerLeft_Corner);
380a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
381a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkScalar leftUnstretched = SkTMax(UL.fX, LL.fX) + SkIntToScalar(2 * margin.fX);
382a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkScalar rightUnstretched = SkTMax(UR.fX, LR.fX) + SkIntToScalar(2 * margin.fX);
383a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
384a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // Extra space in the middle to ensure an unchanging piece for stretching. Use 3 to cover
385a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    // any fractional space on either side plus 1 for the part to stretch.
386a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkScalar stretchSize = SkIntToScalar(3);
387a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
388a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkScalar totalSmallWidth = leftUnstretched + rightUnstretched + stretchSize;
389a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    if (totalSmallWidth >= rrect.rect().width()) {
390a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        // There is no valid piece to stretch.
391a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        return kUnimplemented_FilterReturn;
392a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
393a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
394a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkScalar topUnstretched = SkTMax(UL.fY, UR.fY) + SkIntToScalar(2 * margin.fY);
395a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkScalar bottomUnstretched = SkTMax(LL.fY, LR.fY) + SkIntToScalar(2 * margin.fY);
396a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
397a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    const SkScalar totalSmallHeight = topUnstretched + bottomUnstretched + stretchSize;
398a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    if (totalSmallHeight >= rrect.rect().height()) {
399a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        // There is no valid piece to stretch.
400a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com        return kUnimplemented_FilterReturn;
401a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
402a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
403a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkRect smallR = SkRect::MakeWH(totalSmallWidth, totalSmallHeight);
404a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
405a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkRRect smallRR;
406a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkVector radii[4];
407a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    radii[SkRRect::kUpperLeft_Corner] = UL;
408a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    radii[SkRRect::kUpperRight_Corner] = UR;
409a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    radii[SkRRect::kLowerRight_Corner] = LR;
410a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    radii[SkRRect::kLowerLeft_Corner] = LL;
411a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    smallRR.setRectRadii(smallR, radii);
412a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
4134dca7a829635b552be369186ff508a94aba6a903reed    const SkScalar sigma = this->computeXformedSigma(matrix);
414b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed    SkCachedData* cache = find_cached_rrect(&patch->fMask, sigma, fBlurStyle,
415b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed                                            this->getQuality(), smallRR);
416b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed    if (!cache) {
4174dca7a829635b552be369186ff508a94aba6a903reed        bool analyticBlurWorked = false;
4184dca7a829635b552be369186ff508a94aba6a903reed        if (c_analyticBlurRRect) {
4194dca7a829635b552be369186ff508a94aba6a903reed            analyticBlurWorked =
4204dca7a829635b552be369186ff508a94aba6a903reed                this->filterRRectMask(&patch->fMask, smallRR, matrix, &margin,
4214dca7a829635b552be369186ff508a94aba6a903reed                                      SkMask::kComputeBoundsAndRenderImage_CreateMode);
422a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org        }
423ad99358bdd7ca4ffb047121946abf0d5fdbde1e8robertphillips@google.com
4244dca7a829635b552be369186ff508a94aba6a903reed        if (!analyticBlurWorked) {
4254dca7a829635b552be369186ff508a94aba6a903reed            if (!draw_rrect_into_mask(smallRR, &srcM)) {
4264dca7a829635b552be369186ff508a94aba6a903reed                return kFalse_FilterReturn;
4274dca7a829635b552be369186ff508a94aba6a903reed            }
428a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org
4294dca7a829635b552be369186ff508a94aba6a903reed            SkAutoMaskFreeImage amf(srcM.fImage);
4304dca7a829635b552be369186ff508a94aba6a903reed
4314dca7a829635b552be369186ff508a94aba6a903reed            if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
4324dca7a829635b552be369186ff508a94aba6a903reed                return kFalse_FilterReturn;
4334dca7a829635b552be369186ff508a94aba6a903reed            }
434a477154cfce6276277f4eacc20908a6c986c112ccommit-bot@chromium.org        }
435b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed        cache = add_cached_rrect(&patch->fMask, sigma, fBlurStyle, this->getQuality(), smallRR);
436a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    }
437a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
438a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    patch->fMask.fBounds.offsetTo(0, 0);
439a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    patch->fOuterRect = dstM.fBounds;
440a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    patch->fCenter.fX = SkScalarCeilToInt(leftUnstretched) + 1;
441a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    patch->fCenter.fY = SkScalarCeilToInt(topUnstretched) + 1;
44296fcdcc219d2a0d3579719b84b28bede76efba64halcanary    SkASSERT(nullptr == patch->fCache);
443b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed    patch->fCache = cache;  // transfer ownership to patch
444a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    return kTrue_FilterReturn;
445a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com}
446a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
447a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholasSK_CONF_DECLARE(bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", true, "Use the faster analytic blur approach for ninepatch rects");
4487c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com
449d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.comSkMaskFilter::FilterReturn
450dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.comSkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
451dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com                                        const SkMatrix& matrix,
452dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com                                        const SkIRect& clipBounds,
45330711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.com                                        NinePatch* patch) const {
454dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    if (count < 1 || count > 2) {
455dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        return kUnimplemented_FilterReturn;
456dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    }
4573458716b52aa25dcd1b270141c7628c380696e35skia.committer@gmail.com
45857850b9daddd941f880d94faaf83f2169355a0c8reed@google.com    // TODO: report correct metrics for innerstyle, where we do not grow the
45957850b9daddd941f880d94faaf83f2169355a0c8reed@google.com    // total bounds, but we do need an inset the size of our blur-radius
460e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    if (kInner_SkBlurStyle == fBlurStyle || kOuter_SkBlurStyle == fBlurStyle) {
46157850b9daddd941f880d94faaf83f2169355a0c8reed@google.com        return kUnimplemented_FilterReturn;
46257850b9daddd941f880d94faaf83f2169355a0c8reed@google.com    }
46357850b9daddd941f880d94faaf83f2169355a0c8reed@google.com
46407784a041925f9a921e390e782195a622c76fbfareed@google.com    // TODO: take clipBounds into account to limit our coordinates up front
46507784a041925f9a921e390e782195a622c76fbfareed@google.com    // for now, just skip too-large src rects (to take the old code path).
466f276fa74f56d0c691716163d3149fce5de97c9eareed@google.com    if (rect_exceeds(rects[0], SkIntToScalar(32767))) {
46707784a041925f9a921e390e782195a622c76fbfareed@google.com        return kUnimplemented_FilterReturn;
46807784a041925f9a921e390e782195a622c76fbfareed@google.com    }
4693458716b52aa25dcd1b270141c7628c380696e35skia.committer@gmail.com
470d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    SkIPoint margin;
471d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    SkMask  srcM, dstM;
472b07a94f1cba3976596ae1a7f23d8c2043ba353f3reed    srcM.fBounds = rects[0].roundOut();
473d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    srcM.fFormat = SkMask::kA8_Format;
474d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    srcM.fRowBytes = 0;
4752e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
4767c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    bool filterResult = false;
4777c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    if (count == 1 && c_analyticBlurNinepatch) {
4787c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        // special case for fast rect blur
4797c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        // don't actually do the blur the first time, just compute the correct size
4802e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com        filterResult = this->filterRectMask(&dstM, rects[0], matrix, &margin,
4817c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com                                            SkMask::kJustComputeBounds_CreateMode);
4827c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    } else {
4837c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
4847c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    }
4852e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
4867c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    if (!filterResult) {
487d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com        return kFalse_FilterReturn;
488d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    }
489d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
490d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    /*
491d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  smallR is the smallest version of 'rect' that will still guarantee that
492d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  we get the same blur results on all edges, plus 1 center row/col that is
493d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  representative of the extendible/stretchable edges of the ninepatch.
494d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  Since our actual edge may be fractional we inset 1 more to be sure we
495d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  don't miss any interior blur.
496d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  x is an added pixel of blur, and { and } are the (fractional) edge
497d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  pixels from the original rect.
498d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *
499d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *   x x { x x .... x x } x x
500d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *
501d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  Thus, in this case, we inset by a total of 5 (on each side) beginning
502d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     *  with our outer-rect (dstM.fBounds)
503d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com     */
504dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    SkRect smallR[2];
505dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    SkIPoint center;
506dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com
507dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    // +2 is from +1 for each edge (to account for possible fractional edges
508dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    int smallW = dstM.fBounds.width() - srcM.fBounds.width() + 2;
509dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    int smallH = dstM.fBounds.height() - srcM.fBounds.height() + 2;
510dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    SkIRect innerIR;
511dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com
512dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    if (1 == count) {
513dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        innerIR = srcM.fBounds;
514dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        center.set(smallW, smallH);
515dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    } else {
516dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        SkASSERT(2 == count);
517dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        rects[1].roundIn(&innerIR);
518dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        center.set(smallW + (innerIR.left() - srcM.fBounds.left()),
519dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com                   smallH + (innerIR.top() - srcM.fBounds.top()));
520dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    }
521dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com
522dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    // +1 so we get a clean, stretchable, center row/col
523dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    smallW += 1;
524dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    smallH += 1;
525dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com
526dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    // we want the inset amounts to be integral, so we don't change any
527dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    // fractional phase on the fRight or fBottom of our smallR.
528dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    const SkScalar dx = SkIntToScalar(innerIR.width() - smallW);
529dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    const SkScalar dy = SkIntToScalar(innerIR.height() - smallH);
530dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    if (dx < 0 || dy < 0) {
531dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        // we're too small, relative to our blur, to break into nine-patch,
532dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        // so we ask to have our normal filterMask() be called.
533dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        return kUnimplemented_FilterReturn;
534dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    }
535dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com
536dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    smallR[0].set(rects[0].left(), rects[0].top(), rects[0].right() - dx, rects[0].bottom() - dy);
537112a23e0fa027b423a656f0a1aa06868617e982arobertphillips@google.com    if (smallR[0].width() < 2 || smallR[0].height() < 2) {
538112a23e0fa027b423a656f0a1aa06868617e982arobertphillips@google.com        return kUnimplemented_FilterReturn;
539112a23e0fa027b423a656f0a1aa06868617e982arobertphillips@google.com    }
540dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    if (2 == count) {
541dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        smallR[1].set(rects[1].left(), rects[1].top(),
542dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com                      rects[1].right() - dx, rects[1].bottom() - dy);
543dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com        SkASSERT(!smallR[1].isEmpty());
544d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    }
545d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
5464dca7a829635b552be369186ff508a94aba6a903reed    const SkScalar sigma = this->computeXformedSigma(matrix);
547b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed    SkCachedData* cache = find_cached_rects(&patch->fMask, sigma, fBlurStyle,
548b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed                                            this->getQuality(), smallR, count);
549b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed    if (!cache) {
5504dca7a829635b552be369186ff508a94aba6a903reed        if (count > 1 || !c_analyticBlurNinepatch) {
5514dca7a829635b552be369186ff508a94aba6a903reed            if (!draw_rects_into_mask(smallR, count, &srcM)) {
5524dca7a829635b552be369186ff508a94aba6a903reed                return kFalse_FilterReturn;
5534dca7a829635b552be369186ff508a94aba6a903reed            }
5544dca7a829635b552be369186ff508a94aba6a903reed
5554dca7a829635b552be369186ff508a94aba6a903reed            SkAutoMaskFreeImage amf(srcM.fImage);
5564dca7a829635b552be369186ff508a94aba6a903reed
5574dca7a829635b552be369186ff508a94aba6a903reed            if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
5584dca7a829635b552be369186ff508a94aba6a903reed                return kFalse_FilterReturn;
5594dca7a829635b552be369186ff508a94aba6a903reed            }
5604dca7a829635b552be369186ff508a94aba6a903reed        } else {
5614dca7a829635b552be369186ff508a94aba6a903reed            if (!this->filterRectMask(&patch->fMask, smallR[0], matrix, &margin,
5624dca7a829635b552be369186ff508a94aba6a903reed                                      SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
5634dca7a829635b552be369186ff508a94aba6a903reed                return kFalse_FilterReturn;
5644dca7a829635b552be369186ff508a94aba6a903reed            }
5657c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        }
566b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed        cache = add_cached_rects(&patch->fMask, sigma, fBlurStyle, this->getQuality(), smallR, count);
567d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    }
568dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    patch->fMask.fBounds.offsetTo(0, 0);
569dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    patch->fOuterRect = dstM.fBounds;
570dab9b4fe035c1e8a79e110139953c19bd48d66f9reed@google.com    patch->fCenter = center;
57196fcdcc219d2a0d3579719b84b28bede76efba64halcanary    SkASSERT(nullptr == patch->fCache);
572b0df8be137d8fb49436e46d1fd1a5aec8b7ab562reed    patch->fCache = cache;  // transfer ownership to patch
573d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com    return kTrue_FilterReturn;
574d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com}
575d729b3e504ae547ee0978e8f7156bd8dd8124172reed@google.com
57630711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.comvoid SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
57730711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.com                                             SkRect* dst) const {
5787ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkScalar pad = 3.0f * fSigma;
57917ad2bd077af50dcaca18cf00607b194a1491a44robertphillips@google.com
58017ad2bd077af50dcaca18cf00607b194a1491a44robertphillips@google.com    dst->set(src.fLeft  - pad, src.fTop    - pad,
58117ad2bd077af50dcaca18cf00607b194a1491a44robertphillips@google.com             src.fRight + pad, src.fBottom + pad);
5829efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com}
5839efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com
5849fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkBlurMaskFilterImpl::CreateProc(SkReadBuffer& buffer) {
5859fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const SkScalar sigma = buffer.readScalar();
5869fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const unsigned style = buffer.readUInt();
5879fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const unsigned flags = buffer.readUInt();
5889fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    if (style <= kLastEnum_SkBlurStyle) {
5899fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        return SkBlurMaskFilter::Create((SkBlurStyle)style, sigma, flags);
5909fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    }
59196fcdcc219d2a0d3579719b84b28bede76efba64halcanary    return nullptr;
5929fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
5938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5948b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkBlurMaskFilterImpl::flatten(SkWriteBuffer& buffer) const {
59511e055518a0cbe5329232a55fe2cd177e83836d8robertphillips@google.com    buffer.writeScalar(fSigma);
5969fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    buffer.writeUInt(fBlurStyle);
597c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    buffer.writeUInt(fBlurFlags);
5988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
600491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#if SK_SUPPORT_GPU
6012b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com
602cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.orgclass GrGLRectBlurEffect;
603cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
604b0a8a377f832c59cee939ad721e1f87d378b7142joshualittclass GrRectBlurEffect : public GrFragmentProcessor {
605cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.orgpublic:
60630c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    ~GrRectBlurEffect() override { }
607cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
60836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "RectBlur"; }
609cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
61030c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    static GrFragmentProcessor* Create(GrTextureProvider *textureProvider,
61130c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips                                       const SkRect& rect, float sigma) {
6124a24cd8ff41a8b3d292d60e4351a631240a7ed75humper        int doubleProfileSize = SkScalarCeilToInt(12*sigma);
6134a24cd8ff41a8b3d292d60e4351a631240a7ed75humper
6144a24cd8ff41a8b3d292d60e4351a631240a7ed75humper        if (doubleProfileSize >= rect.width() || doubleProfileSize >= rect.height()) {
6154a24cd8ff41a8b3d292d60e4351a631240a7ed75humper            // if the blur sigma is too large so the gaussian overlaps the whole
6164a24cd8ff41a8b3d292d60e4351a631240a7ed75humper            // rect in either direction, fall back to CPU path for now.
61796fcdcc219d2a0d3579719b84b28bede76efba64halcanary            return nullptr;
618cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org        }
6194a24cd8ff41a8b3d292d60e4351a631240a7ed75humper
62030c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        SkAutoTUnref<GrTexture> blurProfile(CreateBlurProfileTexture(textureProvider, sigma));
62130c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        if (!blurProfile) {
62296fcdcc219d2a0d3579719b84b28bede76efba64halcanary           return nullptr;
6234a24cd8ff41a8b3d292d60e4351a631240a7ed75humper        }
624a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas        // in OpenGL ES, mediump floats have a minimum range of 2^14. If we have coordinates bigger
625a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas        // than that, the shader math will end up with infinities and result in the blur effect not
626a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas        // working correctly. To avoid this, we switch into highp when the coordinates are too big.
627a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas        // As 2^14 is the minimum range but the actual range can be bigger, we might end up
628a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas        // switching to highp sooner than strictly necessary, but most devices that have a bigger
629a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas        // range for mediump also have mediump being exactly the same as highp (e.g. all non-OpenGL
630a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas        // ES devices), and thus incur no additional penalty for the switch.
631a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas        static const SkScalar kMAX_BLUR_COORD = SkIntToScalar(16000);
632a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas        GrSLPrecision precision;
633a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas        if (SkScalarAbs(rect.top()) > kMAX_BLUR_COORD ||
634a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas            SkScalarAbs(rect.left()) > kMAX_BLUR_COORD ||
635a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas            SkScalarAbs(rect.bottom()) > kMAX_BLUR_COORD ||
636a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas            SkScalarAbs(rect.right()) > kMAX_BLUR_COORD ||
637a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas            SkScalarAbs(rect.width()) > kMAX_BLUR_COORD ||
638a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas            SkScalarAbs(rect.height()) > kMAX_BLUR_COORD) {
639a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas            precision = kHigh_GrSLPrecision;
640a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas        }
641a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas        else {
642a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas            precision = kDefault_GrSLPrecision;
643a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas        }
644a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas        return new GrRectBlurEffect(rect, sigma, blurProfile, precision);
645cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org    }
6464c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
6474a24cd8ff41a8b3d292d60e4351a631240a7ed75humper    const SkRect& getRect() const { return fRect; }
648cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org    float getSigma() const { return fSigma; }
649bf536af15f4c176d3bef65b77b7592718bfd9068robertphillips    GrSLPrecision precision() const { return fPrecision; }
650cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
651cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.orgprivate:
652a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas    GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blurProfile,
653a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas                     GrSLPrecision fPrecision);
654b1daa86732fe70aa4630c89d75ff0fd619d77c77wangyix
65557d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
6564b3050b410254d0cb38df9a30ae2e209124fa1a2wangyix
65757d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
6584b3050b410254d0cb38df9a30ae2e209124fa1a2wangyix
65936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onIsEqual(const GrFragmentProcessor&) const override;
6604c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
66136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
6621a8ecdfb73a15de600d5779b75d7c4b61863c50begdaniel
66330c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    static GrTexture* CreateBlurProfileTexture(GrTextureProvider*, float sigma);
6644c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
6654a24cd8ff41a8b3d292d60e4351a631240a7ed75humper    SkRect          fRect;
6664a24cd8ff41a8b3d292d60e4351a631240a7ed75humper    float           fSigma;
6674a24cd8ff41a8b3d292d60e4351a631240a7ed75humper    GrTextureAccess fBlurProfileAccess;
668a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas    GrSLPrecision   fPrecision;
669cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
670b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
671cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
672b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    typedef GrFragmentProcessor INHERITED;
673cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org};
674cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
67564c4728c70001ed074fecf5c4e083781987b12e9egdanielclass GrGLRectBlurEffect : public GrGLSLFragmentProcessor {
676cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.orgpublic:
67730c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    void emitCode(EmitArgs&) override;
678cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
679bf536af15f4c176d3bef65b77b7592718bfd9068robertphillips    static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
680a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas
681b1daa86732fe70aa4630c89d75ff0fd619d77c77wangyixprotected:
682018fb62d12d1febf121fe265da5b6117b86a6541egdaniel    void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
683cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
684cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.orgprivate:
685018fb62d12d1febf121fe265da5b6117b86a6541egdaniel    typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
686cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
6874a24cd8ff41a8b3d292d60e4351a631240a7ed75humper    UniformHandle       fProxyRectUniform;
6884a24cd8ff41a8b3d292d60e4351a631240a7ed75humper    UniformHandle       fProfileSizeUniform;
689cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
69064c4728c70001ed074fecf5c4e083781987b12e9egdaniel    typedef GrGLSLFragmentProcessor INHERITED;
691cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org};
692cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
6938528541dd7f09f5bd76f3f1ce5f45d08ac7347c7cdaltonvoid OutputRectBlurProfileLookup(GrGLSLFPFragmentBuilder* fragBuilder,
6947dc4bd06fca73a97dcf3ad4a7425597160f1edfcegdaniel                                 const GrGLSLTextureSampler& sampler,
6954a24cd8ff41a8b3d292d60e4351a631240a7ed75humper                                 const char *output,
6964a24cd8ff41a8b3d292d60e4351a631240a7ed75humper                                 const char *profileSize, const char *loc,
6974a24cd8ff41a8b3d292d60e4351a631240a7ed75humper                                 const char *blurred_width,
6984a24cd8ff41a8b3d292d60e4351a631240a7ed75humper                                 const char *sharp_width) {
6994ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("float %s;", output);
7004ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("{");
7014ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("float coord = ((abs(%s - 0.5 * %s) - 0.5 * %s)) / %s;",
7024a24cd8ff41a8b3d292d60e4351a631240a7ed75humper                           loc, blurred_width, sharp_width, profileSize);
7034ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("%s = ", output);
7044ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->appendTextureLookup(sampler, "vec2(coord,0.5)");
7054ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppend(".a;");
7064ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("}");
7074a24cd8ff41a8b3d292d60e4351a631240a7ed75humper}
7084a24cd8ff41a8b3d292d60e4351a631240a7ed75humper
709a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas
710bf536af15f4c176d3bef65b77b7592718bfd9068robertphillipsvoid GrGLRectBlurEffect::GenKey(const GrProcessor& proc, const GrGLSLCaps&,
711bf536af15f4c176d3bef65b77b7592718bfd9068robertphillips                                GrProcessorKeyBuilder* b) {
712bf536af15f4c176d3bef65b77b7592718bfd9068robertphillips    const GrRectBlurEffect& rbe = proc.cast<GrRectBlurEffect>();
713bf536af15f4c176d3bef65b77b7592718bfd9068robertphillips
714bf536af15f4c176d3bef65b77b7592718bfd9068robertphillips    b->add32(rbe.precision());
715a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas}
716a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas
717a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas
7187c157a988845fb00f9024d6db6dda142c3458033wangyixvoid GrGLRectBlurEffect::emitCode(EmitArgs& args) {
719bf536af15f4c176d3bef65b77b7592718bfd9068robertphillips    const GrRectBlurEffect& rbe = args.fFp.cast<GrRectBlurEffect>();
720bf536af15f4c176d3bef65b77b7592718bfd9068robertphillips
7217ea439b2203855db97330b25945b87dd4b170b8begdaniel    GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
7224c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
7234a24cd8ff41a8b3d292d60e4351a631240a7ed75humper    const char *rectName;
7244a24cd8ff41a8b3d292d60e4351a631240a7ed75humper    const char *profileSizeName;
7254a24cd8ff41a8b3d292d60e4351a631240a7ed75humper
726bf536af15f4c176d3bef65b77b7592718bfd9068robertphillips    const char* precisionString = GrGLSLShaderVar::PrecisionString(args.fGLSLCaps, rbe.precision());
7275e58ceea8569f0d90ff7e3daf5de2def50407212cdalton    fProxyRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
7287ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                   kVec4f_GrSLType,
729bf536af15f4c176d3bef65b77b7592718bfd9068robertphillips                                                   rbe.precision(),
7307ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                   "proxyRect",
7317ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                   &rectName);
7325e58ceea8569f0d90ff7e3daf5de2def50407212cdalton    fProfileSizeUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
7337ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                     kFloat_GrSLType,
7347ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                     kDefault_GrSLPrecision,
7357ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                     "profileSize",
7367ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                     &profileSizeName);
7374a24cd8ff41a8b3d292d60e4351a631240a7ed75humper
7388528541dd7f09f5bd76f3f1ce5f45d08ac7347c7cdalton    GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
7394ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    const char *fragmentPos = fragBuilder->fragmentPosition();
7404c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
7417c157a988845fb00f9024d6db6dda142c3458033wangyix    if (args.fInputColor) {
7424ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppendf("vec4 src=%s;", args.fInputColor);
743cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org    } else {
7444ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppendf("vec4 src=vec4(1);");
745cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org    }
7464c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
7474ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("%s vec2 translatedPos = %s.xy - %s.xy;", precisionString, fragmentPos,
7484ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                             rectName);
7494ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("%s float width = %s.z - %s.x;", precisionString, rectName, rectName);
7504ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("%s float height = %s.w - %s.y;", precisionString, rectName, rectName);
7514c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
7524ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("%s vec2 smallDims = vec2(width - %s, height - %s);", precisionString,
7534ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                             profileSizeName, profileSizeName);
7544ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("%s float center = 2.0 * floor(%s/2.0 + .25) - 1.0;", precisionString,
7554ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                             profileSizeName);
7564ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("%s vec2 wh = smallDims - vec2(center,center);", precisionString);
7574a24cd8ff41a8b3d292d60e4351a631240a7ed75humper
7584ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    OutputRectBlurProfileLookup(fragBuilder, args.fSamplers[0], "horiz_lookup", profileSizeName,
7597c157a988845fb00f9024d6db6dda142c3458033wangyix                                "translatedPos.x", "width", "wh.x");
7604ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    OutputRectBlurProfileLookup(fragBuilder, args.fSamplers[0], "vert_lookup", profileSizeName,
7617c157a988845fb00f9024d6db6dda142c3458033wangyix                                "translatedPos.y", "height", "wh.y");
7624a24cd8ff41a8b3d292d60e4351a631240a7ed75humper
7634ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("float final = horiz_lookup * vert_lookup;");
7644ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("%s = src * final;", args.fOutputColor);
765cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org}
766cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
767018fb62d12d1febf121fe265da5b6117b86a6541egdanielvoid GrGLRectBlurEffect::onSetData(const GrGLSLProgramDataManager& pdman,
76830c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips                                   const GrProcessor& proc) {
769b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    const GrRectBlurEffect& rbe = proc.cast<GrRectBlurEffect>();
7704a24cd8ff41a8b3d292d60e4351a631240a7ed75humper    SkRect rect = rbe.getRect();
7714a24cd8ff41a8b3d292d60e4351a631240a7ed75humper
7727510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    pdman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
7737510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    pdman.set1f(fProfileSizeUniform, SkScalarCeilToScalar(6*rbe.getSigma()));
774cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org}
775cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
77630c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillipsGrTexture* GrRectBlurEffect::CreateBlurProfileTexture(GrTextureProvider* textureProvider,
77730c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips                                                      float sigma) {
778f2703d83da3ab2ae18b45231fd4f11e16cce3184bsalomon    GrSurfaceDesc texDesc;
7794c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
78024db3b1c35fb935660229da164fc5ad31977387fbsalomon    unsigned int profileSize = SkScalarCeilToInt(6*sigma);
7814c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
78224db3b1c35fb935660229da164fc5ad31977387fbsalomon    texDesc.fWidth = profileSize;
783cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org    texDesc.fHeight = 1;
784cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org    texDesc.fConfig = kAlpha_8_GrPixelConfig;
7854c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
7868718aafec239c93485e45bbe8fed19d9a8def079bsalomon    static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
7878718aafec239c93485e45bbe8fed19d9a8def079bsalomon    GrUniqueKey key;
7888718aafec239c93485e45bbe8fed19d9a8def079bsalomon    GrUniqueKey::Builder builder(&key, kDomain, 1);
78924db3b1c35fb935660229da164fc5ad31977387fbsalomon    builder[0] = profileSize;
79024db3b1c35fb935660229da164fc5ad31977387fbsalomon    builder.finish();
7914c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
79230c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    GrTexture *blurProfile = textureProvider->findAndRefTextureByUniqueKey(key);
7934c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
79430c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    if (!blurProfile) {
79530c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        SkAutoTDeleteArray<uint8_t> profile(SkBlurMask::ComputeBlurProfile(sigma));
7964c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
7975ec26ae9bfca635ccc98283aad5deda11519d826bsalomon        blurProfile = textureProvider->createTexture(texDesc, SkBudgeted::kYes, profile.get(), 0);
79830c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        if (blurProfile) {
79930c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips            textureProvider->assignUniqueKeyToTexture(key, blurProfile);
800cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org        }
801cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org    }
8024c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
80330c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    return blurProfile;
804cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org}
805cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
806a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholasGrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blurProfile,
807a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas                                   GrSLPrecision precision)
80830c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    : fRect(rect)
80930c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    , fSigma(sigma)
810a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas    , fBlurProfileAccess(blurProfile)
811a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas    , fPrecision(precision) {
812eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    this->initClassID<GrRectBlurEffect>();
8134a24cd8ff41a8b3d292d60e4351a631240a7ed75humper    this->addTextureAccess(&fBlurProfileAccess);
8144a24cd8ff41a8b3d292d60e4351a631240a7ed75humper    this->setWillReadFragmentPosition();
815cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org}
816cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
81757d3b039c635945e1dc2fcbac3462ed8bfedb068egdanielvoid GrRectBlurEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
81857d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel                                             GrProcessorKeyBuilder* b) const {
819bf536af15f4c176d3bef65b77b7592718bfd9068robertphillips    GrGLRectBlurEffect::GenKey(*this, caps, b);
820eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt}
821eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
82257d3b039c635945e1dc2fcbac3462ed8bfedb068egdanielGrGLSLFragmentProcessor* GrRectBlurEffect::onCreateGLSLInstance() const {
823bf536af15f4c176d3bef65b77b7592718bfd9068robertphillips    return new GrGLRectBlurEffect;
824cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org}
825cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
8260e08fc17e4718f7ce4e38f793695896473e96948bsalomonbool GrRectBlurEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
82749586bec7383d4ccb81f85f8e2dc4162e2d4f6a8joshualitt    const GrRectBlurEffect& s = sBase.cast<GrRectBlurEffect>();
8284a24cd8ff41a8b3d292d60e4351a631240a7ed75humper    return this->getSigma() == s.getSigma() && this->getRect() == s.getRect();
829cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org}
830cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
831605dd0fbce9dbb2a0d3313e13e161f2bd54870d7egdanielvoid GrRectBlurEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
83256995b5cc00c9c83bd5fcf86bca9a67e939a96cbjoshualitt    inout->mulByUnknownSingleComponent();
833cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org}
834cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
835b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRectBlurEffect);
836cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
837c21b09eec91c9e263cb0b88467ea44e348ed4962bsalomonconst GrFragmentProcessor* GrRectBlurEffect::TestCreate(GrProcessorTestData* d) {
8380067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    float sigma = d->fRandom->nextRangeF(3,8);
8390067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    float width = d->fRandom->nextRangeF(200,300);
8400067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    float height = d->fRandom->nextRangeF(200,300);
8410067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    return GrRectBlurEffect::Create(d->fContext->textureProvider(), SkRect::MakeWH(width, height),
842d309e7aa0efa2d5dd7e7b1af97026fcd3a047e98bsalomon                                    sigma);
843cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org}
844cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
845cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
846ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillipsbool SkBlurMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvider,
847ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                                               GrDrawContext* drawContext,
848cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org                                               GrPaint* grp,
849570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt                                               const GrClip& clip,
8505531d51ce7426bdae7563547326fcf0bf926a083joshualitt                                               const SkMatrix& viewMatrix,
851cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org                                               const SkStrokeRec& strokeRec,
852cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org                                               const SkPath& path) const {
853ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips    SkASSERT(drawContext);
854ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips
855e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    if (fBlurStyle != kNormal_SkBlurStyle) {
856cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org        return false;
857cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org    }
8584c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
85930c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    // TODO: we could handle blurred stroked circles
860cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org    if (!strokeRec.isFillStyle()) {
861cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org        return false;
862cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org    }
8634c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
864ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips    SkScalar xformedSigma = this->computeXformedSigma(viewMatrix);
8654a24cd8ff41a8b3d292d60e4351a631240a7ed75humper
86630c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    SkAutoTUnref<const GrFragmentProcessor> fp;
86730c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips
86830c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    SkRect rect;
86930c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    if (path.isRect(&rect)) {
87030c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        int pad = SkScalarCeilToInt(6*xformedSigma)/2;
87130c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        rect.outset(SkIntToScalar(pad), SkIntToScalar(pad));
87230c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips
87330c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        fp.reset(GrRectBlurEffect::Create(texProvider, rect, xformedSigma));
87430c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    } else if (path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height())) {
87530c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        fp.reset(GrCircleBlurFragmentProcessor::Create(texProvider, rect, xformedSigma));
87630c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips
87730c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        // expand the rect for the coverage geometry
87830c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        int pad = SkScalarCeilToInt(6*xformedSigma)/2;
87930c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        rect.outset(SkIntToScalar(pad), SkIntToScalar(pad));
88030c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    } else {
88130c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        return false;
88230c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    }
8834c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
884b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    if (!fp) {
885cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org        return false;
886cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org    }
887cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
888ac856c97acc84dcb54d9cdb068ec8a02b8869647bsalomon    grp->addCoverageFragmentProcessor(fp);
8894c18e9fbb685cccf23342757e786027a032197daskia.committer@gmail.com
890c2625821b34d89e8df2ba89cc84db6957189f250joshualitt    SkMatrix inverse;
891c2625821b34d89e8df2ba89cc84db6957189f250joshualitt    if (!viewMatrix.invert(&inverse)) {
892c2625821b34d89e8df2ba89cc84db6957189f250joshualitt        return false;
893c2625821b34d89e8df2ba89cc84db6957189f250joshualitt    }
894ea4615034498aca2f9ca1753fb9a1ef10508d8ccrobertphillips
895a2e69fcdedbd9a7762620e0e9dcdd86596369cffbsalomon    drawContext->fillRectWithLocalMatrix(clip, *grp, SkMatrix::I(), rect, inverse);
896ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips    return true;
897cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org}
898cf34bc06347dd2734a7fdaef5cf8853e92979d5ecommit-bot@chromium.org
89930c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips//////////////////////////////////////////////////////////////////////////////
90030c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips
901b0a8a377f832c59cee939ad721e1f87d378b7142joshualittclass GrRRectBlurEffect : public GrFragmentProcessor {
9023d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.orgpublic:
9033d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
90430c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    static const GrFragmentProcessor* Create(GrTextureProvider*, float sigma, const SkRRect&);
9053d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
9063d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    virtual ~GrRRectBlurEffect() {};
90736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "GrRRectBlur"; }
9083d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
9093d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    const SkRRect& getRRect() const { return fRRect; }
9103d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    float getSigma() const { return fSigma; }
9113d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
9123d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.orgprivate:
91357d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
914b1daa86732fe70aa4630c89d75ff0fd619d77c77wangyix
9153d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    GrRRectBlurEffect(float sigma, const SkRRect&, GrTexture* profileTexture);
9163d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
91757d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps,
91857d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel                                       GrProcessorKeyBuilder* b) const override;
9194b3050b410254d0cb38df9a30ae2e209124fa1a2wangyix
92036352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onIsEqual(const GrFragmentProcessor& other) const override;
9213d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
92236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
9231a8ecdfb73a15de600d5779b75d7c4b61863c50begdaniel
9243d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    SkRRect             fRRect;
9253d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    float               fSigma;
9263d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    GrTextureAccess     fNinePatchAccess;
9273d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
928b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
9293d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
930b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    typedef GrFragmentProcessor INHERITED;
9313d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org};
9323d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
9333d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
93430c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillipsconst GrFragmentProcessor* GrRRectBlurEffect::Create(GrTextureProvider* texProvider, float sigma,
93530c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips                                                     const SkRRect& rrect) {
93630c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    if (rrect.isCircle()) {
93730c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        return GrCircleBlurFragmentProcessor::Create(texProvider, rrect.rect(), sigma);
93830c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    }
93930c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips
9403d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    if (!rrect.isSimpleCircular()) {
94196fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
9423d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    }
9433d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
9443d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    // Make sure we can successfully ninepatch this rrect -- the blur sigma has to be
9453d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    // sufficiently small relative to both the size of the corner radius and the
9463d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    // width (and height) of the rrect.
9473d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
9483d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    unsigned int blurRadius = 3*SkScalarCeilToInt(sigma-1/6.0f);
9493d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    unsigned int cornerRadius = SkScalarCeilToInt(rrect.getSimpleRadii().x());
9503d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    if (cornerRadius + blurRadius > rrect.width()/2 ||
9513d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org        cornerRadius + blurRadius > rrect.height()/2) {
95296fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
9533d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    }
9543d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
9558718aafec239c93485e45bbe8fed19d9a8def079bsalomon    static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
9568718aafec239c93485e45bbe8fed19d9a8def079bsalomon    GrUniqueKey key;
9578718aafec239c93485e45bbe8fed19d9a8def079bsalomon    GrUniqueKey::Builder builder(&key, kDomain, 2);
95824db3b1c35fb935660229da164fc5ad31977387fbsalomon    builder[0] = blurRadius;
95924db3b1c35fb935660229da164fc5ad31977387fbsalomon    builder[1] = cornerRadius;
96024db3b1c35fb935660229da164fc5ad31977387fbsalomon    builder.finish();
9613d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
962ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips    SkAutoTUnref<GrTexture> blurNinePatchTexture(texProvider->findAndRefTextureByUniqueKey(key));
9633d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
964d5b98404ece3b1d29bc47f75dec58430d16e39e5joshualitt    if (!blurNinePatchTexture) {
9653d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org        SkMask mask;
9663d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
96737f9a2694c15f08e361ebda74fe9f0fffbf452aabsalomon        unsigned int smallRectSide = 2*(blurRadius + cornerRadius) + 1;
96837f9a2694c15f08e361ebda74fe9f0fffbf452aabsalomon
9693d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org        mask.fBounds = SkIRect::MakeWH(smallRectSide, smallRectSide);
9703d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org        mask.fFormat = SkMask::kA8_Format;
9713d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org        mask.fRowBytes = mask.fBounds.width();
9723d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org        mask.fImage = SkMask::AllocImage(mask.computeTotalImageSize());
9733d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org        SkAutoMaskFreeImage amfi(mask.fImage);
9743d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
9753d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org        memset(mask.fImage, 0, mask.computeTotalImageSize());
9763d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
9773d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org        SkRect smallRect;
9783d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org        smallRect.setWH(SkIntToScalar(smallRectSide), SkIntToScalar(smallRectSide));
9793d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
9803d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org        SkRRect smallRRect;
9813d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org        smallRRect.setRectXY(smallRect, SkIntToScalar(cornerRadius), SkIntToScalar(cornerRadius));
9823d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
9833d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org        SkPath path;
984a8e5fbdf30fb1a09c781c4aab91ec70839590626ethannicholas        path.addRRect(smallRRect);
9853d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
98696fcdcc219d2a0d3579719b84b28bede76efba64halcanary        SkDraw::DrawToMask(path, &mask.fBounds, nullptr, nullptr, &mask,
98737f9a2694c15f08e361ebda74fe9f0fffbf452aabsalomon                           SkMask::kJustRenderImage_CreateMode, SkPaint::kFill_Style);
9883d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
989d5b98404ece3b1d29bc47f75dec58430d16e39e5joshualitt        SkMask blurredMask;
990e80eb928ba0248a5a5dea6e1f0005aa08ecf8740robertphillips        if (!SkBlurMask::BoxBlur(&blurredMask, mask, sigma, kNormal_SkBlurStyle,
991e80eb928ba0248a5a5dea6e1f0005aa08ecf8740robertphillips                                 kHigh_SkBlurQuality, nullptr, true)) {
992e80eb928ba0248a5a5dea6e1f0005aa08ecf8740robertphillips            return nullptr;
993e80eb928ba0248a5a5dea6e1f0005aa08ecf8740robertphillips        }
99437f9a2694c15f08e361ebda74fe9f0fffbf452aabsalomon
99537f9a2694c15f08e361ebda74fe9f0fffbf452aabsalomon        unsigned int texSide = smallRectSide + 2*blurRadius;
99637f9a2694c15f08e361ebda74fe9f0fffbf452aabsalomon        GrSurfaceDesc texDesc;
99737f9a2694c15f08e361ebda74fe9f0fffbf452aabsalomon        texDesc.fWidth = texSide;
99837f9a2694c15f08e361ebda74fe9f0fffbf452aabsalomon        texDesc.fHeight = texSide;
99937f9a2694c15f08e361ebda74fe9f0fffbf452aabsalomon        texDesc.fConfig = kAlpha_8_GrPixelConfig;
100037f9a2694c15f08e361ebda74fe9f0fffbf452aabsalomon
1001d309e7aa0efa2d5dd7e7b1af97026fcd3a047e98bsalomon        blurNinePatchTexture.reset(
10025ec26ae9bfca635ccc98283aad5deda11519d826bsalomon            texProvider->createTexture(texDesc, SkBudgeted::kYes , blurredMask.fImage, 0));
1003d5b98404ece3b1d29bc47f75dec58430d16e39e5joshualitt        SkMask::FreeImage(blurredMask.fImage);
10045f5a8d7599b8e248633ac122294b7a01401fedcbjoshualitt        if (!blurNinePatchTexture) {
100596fcdcc219d2a0d3579719b84b28bede76efba64halcanary            return nullptr;
10065f5a8d7599b8e248633ac122294b7a01401fedcbjoshualitt        }
1007ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips        texProvider->assignUniqueKeyToTexture(key, blurNinePatchTexture);
10083d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    }
1009385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary    return new GrRRectBlurEffect(sigma, rrect, blurNinePatchTexture);
10103d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org}
10113d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
1012605dd0fbce9dbb2a0d3313e13e161f2bd54870d7egdanielvoid GrRRectBlurEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
101356995b5cc00c9c83bd5fcf86bca9a67e939a96cbjoshualitt    inout->mulByUnknownSingleComponent();
10143d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org}
10153d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
10163d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.orgGrRRectBlurEffect::GrRRectBlurEffect(float sigma, const SkRRect& rrect, GrTexture *ninePatchTexture)
10173d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    : fRRect(rrect),
10183d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org      fSigma(sigma),
10193d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org      fNinePatchAccess(ninePatchTexture) {
1020eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    this->initClassID<GrRRectBlurEffect>();
10213d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    this->addTextureAccess(&fNinePatchAccess);
10223d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    this->setWillReadFragmentPosition();
10233d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org}
10243d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
10250e08fc17e4718f7ce4e38f793695896473e96948bsalomonbool GrRRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const {
102649586bec7383d4ccb81f85f8e2dc4162e2d4f6a8joshualitt    const GrRRectBlurEffect& rrbe = other.cast<GrRRectBlurEffect>();
10273d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    return fRRect.getSimpleRadii().fX == rrbe.fRRect.getSimpleRadii().fX && fSigma == rrbe.fSigma;
10283d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org}
10293d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
10303d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org//////////////////////////////////////////////////////////////////////////////
10313d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
1032b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRRectBlurEffect);
10333d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
1034c21b09eec91c9e263cb0b88467ea44e348ed4962bsalomonconst GrFragmentProcessor* GrRRectBlurEffect::TestCreate(GrProcessorTestData* d) {
10350067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    SkScalar w = d->fRandom->nextRangeScalar(100.f, 1000.f);
10360067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    SkScalar h = d->fRandom->nextRangeScalar(100.f, 1000.f);
10370067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    SkScalar r = d->fRandom->nextRangeF(1.f, 9.f);
10380067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    SkScalar sigma = d->fRandom->nextRangeF(1.f,10.f);
10393d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    SkRRect rrect;
10403d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
1041ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips    return GrRRectBlurEffect::Create(d->fContext->textureProvider(), sigma, rrect);
10423d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org}
10433d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
10443d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org//////////////////////////////////////////////////////////////////////////////
10453d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
104664c4728c70001ed074fecf5c4e083781987b12e9egdanielclass GrGLRRectBlurEffect : public GrGLSLFragmentProcessor {
10473d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.orgpublic:
10489cdb9920fcad286ecf7875ea19902022b644fbdcrobertphillips    void emitCode(EmitArgs&) override;
10493d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
1050b1daa86732fe70aa4630c89d75ff0fd619d77c77wangyixprotected:
1051018fb62d12d1febf121fe265da5b6117b86a6541egdaniel    void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
10523d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
10533d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.orgprivate:
1054018fb62d12d1febf121fe265da5b6117b86a6541egdaniel    GrGLSLProgramDataManager::UniformHandle fProxyRectUniform;
1055018fb62d12d1febf121fe265da5b6117b86a6541egdaniel    GrGLSLProgramDataManager::UniformHandle fCornerRadiusUniform;
1056018fb62d12d1febf121fe265da5b6117b86a6541egdaniel    GrGLSLProgramDataManager::UniformHandle fBlurRadiusUniform;
105764c4728c70001ed074fecf5c4e083781987b12e9egdaniel    typedef GrGLSLFragmentProcessor INHERITED;
10583d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org};
10593d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
10607c157a988845fb00f9024d6db6dda142c3458033wangyixvoid GrGLRRectBlurEffect::emitCode(EmitArgs& args) {
10613d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    const char *rectName;
10623d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    const char *cornerRadiusName;
10633d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    const char *blurRadiusName;
10643d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
10657ea439b2203855db97330b25945b87dd4b170b8begdaniel    GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
10663d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    // The proxy rect has left, top, right, and bottom edges correspond to
10673d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    // components x, y, z, and w, respectively.
10683d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
10695e58ceea8569f0d90ff7e3daf5de2def50407212cdalton    fProxyRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
10707ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                   kVec4f_GrSLType,
10712d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel                                                   kDefault_GrSLPrecision,
10727ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                   "proxyRect",
10737ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                   &rectName);
10745e58ceea8569f0d90ff7e3daf5de2def50407212cdalton    fCornerRadiusUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
10757ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                      kFloat_GrSLType,
10767ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                      kDefault_GrSLPrecision,
10777ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                      "cornerRadius",
10787ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                      &cornerRadiusName);
10795e58ceea8569f0d90ff7e3daf5de2def50407212cdalton    fBlurRadiusUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
10807ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                    kFloat_GrSLType,
10817ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                    kDefault_GrSLPrecision,
10827ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                    "blurRadius",
10837ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                    &blurRadiusName);
10842d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel
10858528541dd7f09f5bd76f3f1ce5f45d08ac7347c7cdalton    GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
10864ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    const char* fragmentPos = fragBuilder->fragmentPosition();
10873d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
10883d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    // warp the fragment position to the appropriate part of the 9patch blur texture
10893d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
10904ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("vec2 rectCenter = (%s.xy + %s.zw)/2.0;", rectName, rectName);
10914ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("vec2 translatedFragPos = %s.xy - %s.xy;", fragmentPos, rectName);
10924ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("float threshold = %s + 2.0*%s;", cornerRadiusName, blurRadiusName);
10934ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("vec2 middle = %s.zw - %s.xy - 2.0*threshold;", rectName, rectName);
10944ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
10954ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf(
10964ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel           "if (translatedFragPos.x >= threshold && translatedFragPos.x < (middle.x+threshold)) {");
10974ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("translatedFragPos.x = threshold;\n");
10984ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("} else if (translatedFragPos.x >= (middle.x + threshold)) {");
10994ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("translatedFragPos.x -= middle.x - 1.0;");
11004ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("}");
11014ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
11024ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf(
11034ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            "if (translatedFragPos.y > threshold && translatedFragPos.y < (middle.y+threshold)) {");
11044ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("translatedFragPos.y = threshold;");
11054ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("} else if (translatedFragPos.y >= (middle.y + threshold)) {");
11064ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("translatedFragPos.y -= middle.y - 1.0;");
11074ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("}");
11084ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
11094ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("vec2 proxyDims = vec2(2.0*threshold+1.0);");
11104ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("vec2 texCoord = translatedFragPos / proxyDims;");
11114ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
11124ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("%s = ", args.fOutputColor);
11134ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->appendTextureLookupAndModulate(args.fInputColor, args.fSamplers[0], "texCoord");
11144ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppend(";");
11153d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org}
11163d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
1117018fb62d12d1febf121fe265da5b6117b86a6541egdanielvoid GrGLRRectBlurEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1118018fb62d12d1febf121fe265da5b6117b86a6541egdaniel                                    const GrProcessor& proc) {
1119b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    const GrRRectBlurEffect& brre = proc.cast<GrRRectBlurEffect>();
11203d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    SkRRect rrect = brre.getRRect();
11213d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
11223d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    float blurRadius = 3.f*SkScalarCeilToScalar(brre.getSigma()-1/6.0f);
11237510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    pdman.set1f(fBlurRadiusUniform, blurRadius);
11243d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
11253d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    SkRect rect = rrect.getBounds();
11263d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    rect.outset(blurRadius, blurRadius);
11277510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    pdman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
11283d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
11293d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    SkScalar radius = 0;
11303d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    SkASSERT(rrect.isSimpleCircular() || rrect.isRect());
11313d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    radius = rrect.getSimpleRadii().fX;
11327510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    pdman.set1f(fCornerRadiusUniform, radius);
11333d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org}
11343d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
113557d3b039c635945e1dc2fcbac3462ed8bfedb068egdanielvoid GrRRectBlurEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
113657d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel                                              GrProcessorKeyBuilder* b) const {
1137eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    GrGLRRectBlurEffect::GenKey(*this, caps, b);
1138eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt}
1139eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
114057d3b039c635945e1dc2fcbac3462ed8bfedb068egdanielGrGLSLFragmentProcessor* GrRRectBlurEffect::onCreateGLSLInstance() const {
11419cdb9920fcad286ecf7875ea19902022b644fbdcrobertphillips    return new GrGLRRectBlurEffect;
1142eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt}
11433d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
1144ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillipsbool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrTextureProvider* texProvider,
1145ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips                                                    GrDrawContext* drawContext,
1146821397018fdabea6b434ecb96f84fb5449c4025fcommit-bot@chromium.org                                                    GrPaint* grp,
1147570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt                                                    const GrClip& clip,
11485531d51ce7426bdae7563547326fcf0bf926a083joshualitt                                                    const SkMatrix& viewMatrix,
1149821397018fdabea6b434ecb96f84fb5449c4025fcommit-bot@chromium.org                                                    const SkStrokeRec& strokeRec,
1150821397018fdabea6b434ecb96f84fb5449c4025fcommit-bot@chromium.org                                                    const SkRRect& rrect) const {
1151ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips    SkASSERT(drawContext);
1152ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips
11533d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    if (fBlurStyle != kNormal_SkBlurStyle) {
11543d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org        return false;
11553d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    }
11563d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
11573d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    if (!strokeRec.isFillStyle()) {
11583d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org        return false;
11593d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    }
11603d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
1161ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips    SkScalar xformedSigma = this->computeXformedSigma(viewMatrix);
11623d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    float extra=3.f*SkScalarCeilToScalar(xformedSigma-1/6.0f);
11633d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
1164ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips    SkRect proxyRect = rrect.rect();
1165ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips    proxyRect.outset(extra, extra);
1166ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips
116730c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    SkAutoTUnref<const GrFragmentProcessor> fp(GrRRectBlurEffect::Create(texProvider,
116830c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips                                                                         xformedSigma, rrect));
1169b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    if (!fp) {
11703d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org        return false;
11713d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org    }
11723d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
1173ac856c97acc84dcb54d9cdb068ec8a02b8869647bsalomon    grp->addCoverageFragmentProcessor(fp);
11743d8bf232bd2e4903d2ee2bb575637e7555361604commit-bot@chromium.org
1175c2625821b34d89e8df2ba89cc84db6957189f250joshualitt    SkMatrix inverse;
1176c2625821b34d89e8df2ba89cc84db6957189f250joshualitt    if (!viewMatrix.invert(&inverse)) {
1177c2625821b34d89e8df2ba89cc84db6957189f250joshualitt        return false;
1178c2625821b34d89e8df2ba89cc84db6957189f250joshualitt    }
1179ea4615034498aca2f9ca1753fb9a1ef10508d8ccrobertphillips
1180a2e69fcdedbd9a7762620e0e9dcdd86596369cffbsalomon    drawContext->fillRectWithLocalMatrix(clip, *grp, SkMatrix::I(), proxyRect, inverse);
1181ff0ca5ed825d9106edc2df6ab3865e1c17c326bfrobertphillips    return true;
1182821397018fdabea6b434ecb96f84fb5449c4025fcommit-bot@chromium.org}
1183821397018fdabea6b434ecb96f84fb5449c4025fcommit-bot@chromium.org
118430c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillipsbool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRRect& devRRect,
1185491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com                                            const SkIRect& clipBounds,
1186491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com                                            const SkMatrix& ctm,
1187491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com                                            SkRect* maskRect) const {
11887ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkScalar xformedSigma = this->computeXformedSigma(ctm);
11897ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    if (xformedSigma <= 0) {
1190491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        return false;
11912b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com    }
1192491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
119330c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    // We always do circles on the GPU
119430c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    if (!devRRect.isCircle()) {
119530c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        static const SkScalar kMIN_GPU_BLUR_SIZE  = SkIntToScalar(64);
119630c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        static const SkScalar kMIN_GPU_BLUR_SIGMA = SkIntToScalar(32);
1197491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
119830c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        if (devRRect.width() <= kMIN_GPU_BLUR_SIZE &&
119930c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips            devRRect.height() <= kMIN_GPU_BLUR_SIZE &&
120030c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips            xformedSigma <= kMIN_GPU_BLUR_SIGMA) {
120130c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips            // We prefer to blur small rects with small radii on the CPU.
120230c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips            return false;
120330c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        }
1204491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    }
1205491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
120696fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (nullptr == maskRect) {
1207491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        // don't need to compute maskRect
1208491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        return true;
1209491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    }
1210491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
12117ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    float sigma3 = 3 * SkScalarToFloat(xformedSigma);
1212491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
12134469938e92d779dff05e745559e67907bbf21e78reed@google.com    SkRect clipRect = SkRect::Make(clipBounds);
121430c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    SkRect srcRect(devRRect.rect());
1215491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
1216491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    // Outset srcRect and clipRect by 3 * sigma, to compute affected blur area.
12174b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org    srcRect.outset(sigma3, sigma3);
12184b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org    clipRect.outset(sigma3, sigma3);
1219f4e5995ac70d4614e0a05b92a8a03e2b7d76bd9crobertphillips    if (!srcRect.intersect(clipRect)) {
1220f4e5995ac70d4614e0a05b92a8a03e2b7d76bd9crobertphillips        srcRect.setEmpty();
1221f4e5995ac70d4614e0a05b92a8a03e2b7d76bd9crobertphillips    }
1222491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    *maskRect = srcRect;
12231842adf01320f9197b449de7375d08ccac43f389skia.committer@gmail.com    return true;
1224491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com}
1225491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
12261842adf01320f9197b449de7375d08ccac43f389skia.committer@gmail.combool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src,
1227439ff1b9ca2b74a9dc3b04346aa1032c11b142e9commit-bot@chromium.org                                         const SkMatrix& ctm,
12281842adf01320f9197b449de7375d08ccac43f389skia.committer@gmail.com                                         const SkRect& maskRect,
1229491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com                                         GrTexture** result,
1230491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com                                         bool canOverwriteSrc) const {
1231491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
1232491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
1233491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    GrContext* context = src->getContext();
1234491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
1235439ff1b9ca2b74a9dc3b04346aa1032c11b142e9commit-bot@chromium.org    SkScalar xformedSigma = this->computeXformedSigma(ctm);
12367ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkASSERT(xformedSigma > 0);
1237491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
1238491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    // If we're doing a normal blur, we can clobber the pathTexture in the
1239491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    // gaussianBlur.  Otherwise, we need to save it for later compositing.
1240e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    bool isNormalBlur = (kNormal_SkBlurStyle == fBlurStyle);
1241736dd031f177681bfa284e19291ef031ad0822d5robertphillips@google.com    *result = SkGpuBlurUtils::GaussianBlur(context, src, isNormalBlur && canOverwriteSrc,
12424e23cdaa6b892afeaa150c6d74099dc6c2065b7ereed                                           clipRect, nullptr, xformedSigma, xformedSigma);
124396fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (nullptr == *result) {
1244491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        return false;
1245491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    }
1246491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
1247491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    if (!isNormalBlur) {
1248491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        GrPaint paint;
1249491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        SkMatrix matrix;
1250491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        matrix.setIDiv(src->width(), src->height());
1251491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        // Blend pathTexture over blurTexture.
12524a339529612a43871d021877e58698e067d6c4cdbsalomon        paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Create(src, matrix))->unref();
1253e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org        if (kInner_SkBlurStyle == fBlurStyle) {
1254491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com            // inner:  dst = dst * src
1255b197b8ff31b73ccb20423023e03592df8ae78ea6egdaniel            paint.setCoverageSetOpXPFactory(SkRegion::kIntersect_Op);
1256e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org        } else if (kSolid_SkBlurStyle == fBlurStyle) {
1257491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com            // solid:  dst = src + dst - src * dst
1258b197b8ff31b73ccb20423023e03592df8ae78ea6egdaniel            //             = src + (1 - src) * dst
1259b197b8ff31b73ccb20423023e03592df8ae78ea6egdaniel            paint.setCoverageSetOpXPFactory(SkRegion::kUnion_Op);
1260e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org        } else if (kOuter_SkBlurStyle == fBlurStyle) {
1261491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com            // outer:  dst = dst * (1 - src)
1262491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com            //             = 0 * src + (1 - src) * dst
1263b197b8ff31b73ccb20423023e03592df8ae78ea6egdaniel            paint.setCoverageSetOpXPFactory(SkRegion::kDifference_Op);
1264c4b72720e75313079212e69e46a5ef7c474b2305egdaniel        } else {
1265c4b72720e75313079212e69e46a5ef7c474b2305egdaniel            paint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op);
1266491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com        }
1267ea4615034498aca2f9ca1753fb9a1ef10508d8ccrobertphillips
12682e1e51f04985f7c258b96f0decc190456f5dd74drobertphillips        SkAutoTUnref<GrDrawContext> drawContext(context->drawContext((*result)->asRenderTarget()));
1269ea4615034498aca2f9ca1753fb9a1ef10508d8ccrobertphillips        if (!drawContext) {
1270ea4615034498aca2f9ca1753fb9a1ef10508d8ccrobertphillips            return false;
1271ea4615034498aca2f9ca1753fb9a1ef10508d8ccrobertphillips        }
1272ea4615034498aca2f9ca1753fb9a1ef10508d8ccrobertphillips
12732e1e51f04985f7c258b96f0decc190456f5dd74drobertphillips        drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), clipRect);
1274491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    }
1275491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
1276491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com    return true;
12772b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com}
12782b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com
1279491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com#endif // SK_SUPPORT_GPU
1280491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
1281491493119c11206c5823b76eb6420a705be243a1robertphillips@google.com
12820f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING
12830bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.comvoid SkBlurMaskFilterImpl::toString(SkString* str) const {
12840bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    str->append("SkBlurMaskFilterImpl: (");
12850bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com
12867ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    str->append("sigma: ");
12877ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    str->appendScalar(fSigma);
12880bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    str->append(" ");
12890bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com
1290e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    static const char* gStyleName[kLastEnum_SkBlurStyle + 1] = {
12910bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com        "normal", "solid", "outer", "inner"
12920bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    };
12930bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com
12940bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    str->appendf("style: %s ", gStyleName[fBlurStyle]);
12950bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    str->append("flags: (");
12960bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    if (fBlurFlags) {
12970bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com        bool needSeparator = false;
12988eaddb0089a170760e157646192813bd940c26e7skia.committer@gmail.com        SkAddFlagToString(str,
12998eaddb0089a170760e157646192813bd940c26e7skia.committer@gmail.com                          SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag),
13000bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com                          "IgnoreXform", &needSeparator);
13018eaddb0089a170760e157646192813bd940c26e7skia.committer@gmail.com        SkAddFlagToString(str,
13028eaddb0089a170760e157646192813bd940c26e7skia.committer@gmail.com                          SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag),
13030bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com                          "HighQuality", &needSeparator);
13040bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    } else {
13050bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com        str->append("None");
13060bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    }
13070bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com    str->append("))");
13080bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com}
13090bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com#endif
13100bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com
1311d26147adbbdca85f07dff432025afee0c8614387caryclark@google.comSK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
1312d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
1313d26147adbbdca85f07dff432025afee0c8614387caryclark@google.comSK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
1314