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