diff --git a/src/core/SkMaskCache.cpp b/src/core/SkMaskCache.cpp index b4b8b4faf3..207ea0e77d 100644 --- a/src/core/SkMaskCache.cpp +++ b/src/core/SkMaskCache.cpp @@ -18,6 +18,28 @@ struct MaskValue { namespace { static unsigned gRRectBlurKeyNamespaceLabel; +static bool copy_cacheddata_to_mask(SkCachedData* data, SkMask* mask) { + const size_t size = data->size(); + SkASSERT(mask->computeTotalImageSize() <= size); + + mask->fImage = SkMask::AllocImage(size); + if (mask->fImage) { + memcpy(mask->fImage, data->data(), size); + return true; + } + return false; +} + +static SkCachedData* copy_mask_to_cacheddata(const SkMask& mask) { + const size_t size = mask.computeTotalImageSize(); + SkCachedData* data = SkResourceCache::NewCachedData(size); + if (data) { + memcpy(data->writable_data(), mask.fImage, size); + return data; + } + return NULL; +} + struct RRectBlurKey : public SkResourceCache::Key { public: RRectBlurKey(SkScalar sigma, const SkRRect& rrect, SkBlurStyle style, SkBlurQuality quality) @@ -90,6 +112,20 @@ void SkMaskCache::Add(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality, return CHECK_LOCAL(localCache, add, Add, SkNEW_ARGS(RRectBlurRec, (key, mask, data))); } +bool SkMaskCache::FindAndCopy(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality, + const SkRRect& rrect, SkMask* mask) { + SkAutoTUnref data(SkMaskCache::FindAndRef(sigma, style, quality, rrect, mask)); + return data.get() && copy_cacheddata_to_mask(data, mask); +} + +void SkMaskCache::AddAndCopy(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality, + const SkRRect& rrect, const SkMask& mask) { + SkAutoTUnref data(copy_mask_to_cacheddata(mask)); + if (data.get()) { + SkMaskCache::Add(sigma, style, quality, rrect, mask, data); + } +} + ////////////////////////////////////////////////////////////////////////////////////////// namespace { @@ -181,3 +217,17 @@ void SkMaskCache::Add(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality, RectsBlurKey key(sigma, style, quality, rects, count); return CHECK_LOCAL(localCache, add, Add, SkNEW_ARGS(RectsBlurRec, (key, mask, data))); } + +bool SkMaskCache::FindAndCopy(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality, + const SkRect rects[], int count, SkMask* mask) { + SkAutoTUnref data(SkMaskCache::FindAndRef(sigma, style, quality, rects, count, mask)); + return data.get() && copy_cacheddata_to_mask(data, mask); +} + +void SkMaskCache::AddAndCopy(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality, + const SkRect rects[], int count, const SkMask& mask) { + SkAutoTUnref data(copy_mask_to_cacheddata(mask)); + if (data.get()) { + SkMaskCache::Add(sigma, style, quality, rects, count, mask, data); + } +} diff --git a/src/core/SkMaskCache.h b/src/core/SkMaskCache.h index f98387b206..2cfb971dde 100644 --- a/src/core/SkMaskCache.h +++ b/src/core/SkMaskCache.h @@ -39,6 +39,25 @@ public: static void Add(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality, const SkRect rects[], int count, const SkMask& mask, SkCachedData* data, SkResourceCache* localCache = NULL); + + /** + * On success, set mask with cached value, allocate memory for mask->fImage, + * copy pixels from SkCachedData in the cache to mask->fImage, then return true. + * + * On failure, return false, no memory allocated for mask->fImage. + */ + static bool FindAndCopy(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality, + const SkRRect& rrect, SkMask* mask); + static bool FindAndCopy(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality, + const SkRect rects[], int count, SkMask* mask); + + /** + * Create a new SkCachedData, copy pixels from mask.fImage to it, then add it into cache. + */ + static void AddAndCopy(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality, + const SkRRect& rrect, const SkMask& mask); + static void AddAndCopy(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality, + const SkRect rects[], int count, const SkMask& mask); }; #endif diff --git a/src/core/SkMaskFilter.cpp b/src/core/SkMaskFilter.cpp index c9783e76d6..3a4e3a41e9 100644 --- a/src/core/SkMaskFilter.cpp +++ b/src/core/SkMaskFilter.cpp @@ -10,6 +10,7 @@ #include "SkMaskFilter.h" #include "SkBlitter.h" #include "SkDraw.h" +#include "SkMaskCache.h" #include "SkRasterClip.h" #include "SkRRect.h" #include "SkTypes.h" @@ -263,9 +264,41 @@ bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix, } SkAutoMaskFreeImage autoSrc(srcM.fImage); - if (!this->filterMask(&dstM, srcM, matrix, NULL)) { - return false; + BlurRec rec; + if (this->asABlur(&rec) && rectCount) { + SkScalar scaledSigma = matrix.mapRadius(rec.fSigma); + if (!SkMaskCache::FindAndCopy(scaledSigma, rec.fStyle, rec.fQuality, + rects, rectCount, &dstM)) { + if (!this->filterMask(&dstM, srcM, matrix, NULL)) { + return false; + } + SkMaskCache::AddAndCopy(scaledSigma, rec.fStyle, rec.fQuality, rects, rectCount, dstM); + } else { + // Compute the correct bounds of dst mask if dst mask is got from cache. + SkMask tmpSrc, tmpDst; + tmpSrc = srcM; + tmpSrc.fImage = NULL; + if (!this->filterMask(&tmpDst, tmpSrc, matrix, NULL)) { + return false; + } + + // Fallback to original calculation if size of bounds is different with + // size of the cached mask. + if (dstM.fBounds.width() != tmpDst.fBounds.width() || + dstM.fBounds.height() != tmpDst.fBounds.height()) { + if (!this->filterMask(&dstM, srcM, matrix, NULL)) { + return false; + } + } else { + dstM.fBounds = tmpDst.fBounds; + } + } + } else { + if (!this->filterMask(&dstM, srcM, matrix, NULL)) { + return false; + } } + SkAutoMaskFreeImage autoDst(dstM.fImage); // if we get here, we need to (possibly) resolve the clip and blitter diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp index 97ae436367..38b2acca9e 100644 --- a/src/effects/SkBlurMaskFilter.cpp +++ b/src/effects/SkBlurMaskFilter.cpp @@ -11,6 +11,7 @@ #include "SkGpuBlurUtils.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" +#include "SkMaskCache.h" #include "SkMaskFilter.h" #include "SkRRect.h" #include "SkRTConf.h" @@ -260,58 +261,6 @@ static bool rect_exceeds(const SkRect& r, SkScalar v) { r.width() > v || r.height() > v; } -#include "SkMaskCache.h" - -static bool copy_cacheddata_to_mask(SkCachedData* data, SkMask* mask) { - const size_t size = data->size(); - SkASSERT(mask->computeTotalImageSize() <= size); - - mask->fImage = SkMask::AllocImage(size); - if (mask->fImage) { - memcpy(mask->fImage, data->data(), size); - return true; - } - return false; -} - -static SkCachedData* copy_mask_to_cacheddata(const SkMask& mask) { - const size_t size = mask.computeTotalImageSize(); - SkCachedData* data = SkResourceCache::NewCachedData(size); - if (data) { - memcpy(data->writable_data(), mask.fImage, size); - return data; - } - return NULL; -} - -static bool find_cached_rrect(SkMask* mask, SkScalar sigma, SkBlurStyle style, - SkBlurQuality quality, const SkRRect& rrect) { - SkAutoTUnref data(SkMaskCache::FindAndRef(sigma, style, quality, rrect, mask)); - return data.get() && copy_cacheddata_to_mask(data, mask); -} - -static void add_cached_rrect(const SkMask& mask, SkScalar sigma, SkBlurStyle style, - SkBlurQuality quality, const SkRRect& rrect) { - SkAutoTUnref data(copy_mask_to_cacheddata(mask)); - if (data.get()) { - SkMaskCache::Add(sigma, style, quality, rrect, mask, data); - } -} - -static bool find_cached_rects(SkMask* mask, SkScalar sigma, SkBlurStyle style, - SkBlurQuality quality, const SkRect rects[], int count) { - SkAutoTUnref data(SkMaskCache::FindAndRef(sigma, style, quality, rects, count, mask)); - return data.get() && copy_cacheddata_to_mask(data, mask); -} - -static void add_cached_rects(const SkMask& mask, SkScalar sigma, SkBlurStyle style, - SkBlurQuality quality, const SkRect rects[], int count) { - SkAutoTUnref data(copy_mask_to_cacheddata(mask)); - if (data.get()) { - SkMaskCache::Add(sigma, style, quality, rects, count, mask, data); - } -} - #ifdef SK_IGNORE_FAST_RRECT_BLUR SK_CONF_DECLARE( bool, c_analyticBlurRRect, "mask.filter.blur.analyticblurrrect", false, "Use the faster analytic blur approach for ninepatch rects" ); #else @@ -420,7 +369,7 @@ SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma smallRR.setRectRadii(smallR, radii); const SkScalar sigma = this->computeXformedSigma(matrix); - if (!find_cached_rrect(&patch->fMask, sigma, fBlurStyle, this->getQuality(), smallRR)) { + if (!SkMaskCache::FindAndCopy(sigma, fBlurStyle, this->getQuality(), smallRR, &patch->fMask)) { bool analyticBlurWorked = false; if (c_analyticBlurRRect) { analyticBlurWorked = @@ -439,7 +388,7 @@ SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma return kFalse_FilterReturn; } } - add_cached_rrect(patch->fMask, sigma, fBlurStyle, this->getQuality(), smallRR); + SkMaskCache::AddAndCopy(sigma, fBlurStyle, this->getQuality(), smallRR, patch->fMask); } patch->fMask.fBounds.offsetTo(0, 0); @@ -550,7 +499,8 @@ SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count, } const SkScalar sigma = this->computeXformedSigma(matrix); - if (!find_cached_rects(&patch->fMask, sigma, fBlurStyle, this->getQuality(), smallR, count)) { + if (!SkMaskCache::FindAndCopy(sigma, fBlurStyle, this->getQuality(), + smallR, count, &patch->fMask)) { if (count > 1 || !c_analyticBlurNinepatch) { if (!draw_rects_into_mask(smallR, count, &srcM)) { return kFalse_FilterReturn; @@ -567,7 +517,7 @@ SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count, return kFalse_FilterReturn; } } - add_cached_rects(patch->fMask, sigma, fBlurStyle, this->getQuality(), smallR, count); + SkMaskCache::AddAndCopy(sigma, fBlurStyle, this->getQuality(), smallR, count, patch->fMask); } patch->fMask.fBounds.offsetTo(0, 0); patch->fOuterRect = dstM.fBounds;