diff options
author | Mike Reed <reed@google.com> | 2018-01-23 15:29:32 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-01-23 21:14:20 +0000 |
commit | 80747ef591ff3c09c2b610eb21258132d1ff4ef5 (patch) | |
tree | e7472d73f966f9400b0e52cb02ad9e8515de32c3 | |
parent | a7701e032bcc55a73360aa8d1b53ceef566de991 (diff) |
move the guts of SkMaskFilter.h into SkMaskFilterBase.h
Bug: skia:
Change-Id: I29ad0960156562867429542d3cfbf3d639529cab
Reviewed-on: https://skia-review.googlesource.com/98802
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
Reviewed-by: Brian Salomon <bsalomon@google.com>
31 files changed, 441 insertions, 378 deletions
diff --git a/include/core/SkMaskFilter.h b/include/core/SkMaskFilter.h index 3e10dc9ad3..55bf8bf4d5 100644 --- a/include/core/SkMaskFilter.h +++ b/include/core/SkMaskFilter.h @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -9,245 +8,19 @@ #ifndef SkMaskFilter_DEFINED #define SkMaskFilter_DEFINED -#include "SkBlurTypes.h" #include "SkFlattenable.h" -#include "SkMask.h" -#include "SkPaint.h" -#include "SkStrokeRec.h" -class GrClip; -class GrContext; -struct GrFPArgs; -class GrRenderTargetContext; -class GrPaint; -class GrFragmentProcessor; -class GrRenderTarget; -class GrResourceProvider; -class GrTexture; -class GrTextureProxy; -class SkBitmap; -class SkBlitter; -class SkCachedData; -class SkMatrix; -class SkPath; -class SkRasterClip; -class SkRRect; +class SkString; /** \class SkMaskFilter SkMaskFilter is the base class for object that perform transformations on - an alpha-channel mask before drawing it. A subclass of SkMaskFilter may be - installed into a SkPaint. Once there, each time a primitive is drawn, it - is first scan converted into a SkMask::kA8_Format mask, and handed to the - filter, calling its filterMask() method. If this returns true, then the - new mask is used to render into the device. - - Blur and emboss are implemented as subclasses of SkMaskFilter. + the mask before drawing it. An example subclass is Blur. */ class SK_API SkMaskFilter : public SkFlattenable { public: - /** Returns the format of the resulting mask that this subclass will return - when its filterMask() method is called. - */ - virtual SkMask::Format getFormat() const = 0; - - /** Create a new mask by filter the src mask. - If src.fImage == null, then do not allocate or create the dst image - but do fill out the other fields in dstMask. - If you do allocate a dst image, use SkMask::AllocImage() - If this returns false, dst mask is ignored. - @param dst the result of the filter. If src.fImage == null, dst should not allocate its image - @param src the original image to be filtered. - @param matrix the CTM - @param margin if not null, return the buffer dx/dy need when calculating the effect. Used when - drawing a clipped object to know how much larger to allocate the src before - applying the filter. If returning false, ignore this parameter. - @return true if the dst mask was correctly created. - */ - virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, - SkIPoint* margin) const; - -#if SK_SUPPORT_GPU - /** - * Returns a processor if the filter can be expressed a single-pass GrProcessor without - * requiring an explicit input mask. Per-pixel, the effect receives the incoming mask's - * coverage as the input color and outputs the filtered covereage value. This means that each - * pixel's filtered coverage must only depend on the unfiltered mask value for that pixel and - * not on surrounding values. - */ - std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs& args) const; - - /** - * Returns true iff asFragmentProcessor() will return a processor - */ - bool hasFragmentProcessor() const; - - /** - * If asFragmentProcessor() fails the filter may be implemented on the GPU by a subclass - * overriding filterMaskGPU (declared below). That code path requires constructing a - * src mask as input. Since that is a potentially expensive operation, the subclass must also - * override this function to indicate whether filterTextureMaskGPU would succeeed if the mask - * were to be created. - * - * 'maskRect' returns the device space portion of the mask that the filter needs. The mask - * passed into 'filterMaskGPU' should have the same extent as 'maskRect' but be - * translated to the upper-left corner of the mask (i.e., (maskRect.fLeft, maskRect.fTop) - * appears at (0, 0) in the mask). - * - * Logically, how this works is: - * canFilterMaskGPU is called - * if (it returns true) - * the returned mask rect is used for quick rejecting - * either directFilterMaskGPU or directFilterRRectMaskGPU is then called - * if (neither of them handle the blur) - * the mask rect is used to generate the mask - * filterMaskGPU is called to filter the mask - * - * TODO: this should work as: - * if (canFilterMaskGPU(devShape, ...)) // rect, rrect, drrect, path - * filterMaskGPU(devShape, ...) - * this would hide the RRect special case and the mask generation - */ - virtual bool canFilterMaskGPU(const SkRRect& devRRect, - const SkIRect& clipBounds, - const SkMatrix& ctm, - SkRect* maskRect) const; - - /** - * Try to directly render the mask filter into the target. Returns true if drawing was - * successful. If false is returned then paint is unmodified. - */ - virtual bool directFilterMaskGPU(GrContext*, - GrRenderTargetContext* renderTargetContext, - GrPaint&& paint, - const GrClip&, - const SkMatrix& viewMatrix, - const SkStrokeRec& strokeRec, - const SkPath& path) const; - /** - * Try to directly render a rounded rect mask filter into the target. Returns - * true if drawing was successful. If false is returned then paint is unmodified. - */ - virtual bool directFilterRRectMaskGPU(GrContext*, - GrRenderTargetContext* renderTargetContext, - GrPaint&& paint, - const GrClip&, - const SkMatrix& viewMatrix, - const SkStrokeRec& strokeRec, - const SkRRect& rrect, - const SkRRect& devRRect) const; - - /** - * This function is used to implement filters that require an explicit src mask. It should only - * be called if canFilterMaskGPU returned true and the maskRect param should be the output from - * that call. - * Implementations are free to get the GrContext from the src texture in order to create - * additional textures and perform multiple passes. - */ - virtual sk_sp<GrTextureProxy> filterMaskGPU(GrContext*, - sk_sp<GrTextureProxy> srcProxy, - const SkMatrix& ctm, - const SkIRect& maskRect) const; -#endif - - /** - * The fast bounds function is used to enable the paint to be culled early - * in the drawing pipeline. This function accepts the current bounds of the - * paint as its src param and the filter adjust those bounds using its - * current mask and returns the result using the dest param. Callers are - * allowed to provide the same struct for both src and dest so each - * implementation must accomodate that behavior. - * - * The default impl calls filterMask with the src mask having no image, - * but subclasses may override this if they can compute the rect faster. - */ - virtual void computeFastBounds(const SkRect& src, SkRect* dest) const; - - struct BlurRec { - SkScalar fSigma; - SkBlurStyle fStyle; - SkBlurQuality fQuality; - }; - /** - * If this filter can be represented by a BlurRec, return true and (if not null) fill in the - * provided BlurRec parameter. If this effect cannot be represented as a BlurRec, return false - * and ignore the BlurRec parameter. - */ - virtual bool asABlur(BlurRec*) const; - SK_TO_STRING_PUREVIRT() SK_DEFINE_FLATTENABLE_TYPE(SkMaskFilter) - -protected: - SkMaskFilter() {} - -#if SK_SUPPORT_GPU - virtual std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs&) const; - virtual bool onHasFragmentProcessor() const; -#endif - - enum FilterReturn { - kFalse_FilterReturn, - kTrue_FilterReturn, - kUnimplemented_FilterReturn - }; - - class NinePatch : ::SkNoncopyable { - public: - NinePatch() : fCache(nullptr) { } - ~NinePatch(); - - SkMask fMask; // fBounds must have [0,0] in its top-left - SkIRect fOuterRect; // width/height must be >= fMask.fBounds' - SkIPoint fCenter; // identifies center row/col for stretching - SkCachedData* fCache; - }; - - /** - * Override if your subclass can filter a rect, and return the answer as - * a ninepatch mask to be stretched over the returned outerRect. On success - * return kTrue_FilterReturn. On failure (e.g. out of memory) return - * kFalse_FilterReturn. If the normal filterMask() entry-point should be - * called (the default) return kUnimplemented_FilterReturn. - * - * By convention, the caller will take the center rol/col from the returned - * mask as the slice it can replicate horizontally and vertically as we - * stretch the mask to fit inside outerRect. It is an error for outerRect - * to be smaller than the mask's bounds. This would imply that the width - * and height of the mask should be odd. This is not required, just that - * the caller will call mask.fBounds.centerX() and centerY() to find the - * strips that will be replicated. - */ - virtual FilterReturn filterRectsToNine(const SkRect[], int count, - const SkMatrix&, - const SkIRect& clipBounds, - NinePatch*) const; - /** - * Similar to filterRectsToNine, except it performs the work on a round rect. - */ - virtual FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&, - const SkIRect& clipBounds, - NinePatch*) const; - -private: - friend class SkDraw; - - /** Helper method that, given a path in device space, will rasterize it into a kA8_Format mask - and then call filterMask(). If this returns true, the specified blitter will be called - to render that mask. Returns false if filterMask() returned false. - This method is not exported to java. - */ - bool filterPath(const SkPath& devPath, const SkMatrix& ctm, const SkRasterClip&, SkBlitter*, - SkStrokeRec::InitStyle) const; - - /** Helper method that, given a roundRect in device space, will rasterize it into a kA8_Format - mask and then call filterMask(). If this returns true, the specified blitter will be called - to render that mask. Returns false if filterMask() returned false. - */ - bool filterRRect(const SkRRect& devRRect, const SkMatrix& ctm, const SkRasterClip&, - SkBlitter*) const; - - typedef SkFlattenable INHERITED; }; #endif diff --git a/include/effects/SkBlurMaskFilter.h b/include/effects/SkBlurMaskFilter.h index 8b032e50ee..af074ffff3 100644 --- a/include/effects/SkBlurMaskFilter.h +++ b/include/effects/SkBlurMaskFilter.h @@ -10,9 +10,12 @@ // we include this since our callers will need to at least be able to ref/unref #include "SkMaskFilter.h" +#include "SkRect.h" #include "SkScalar.h" #include "SkBlurTypes.h" +class SkRRect; + class SK_API SkBlurMaskFilter { public: /** diff --git a/include/effects/SkRRectsGaussianEdgeMaskFilter.h b/include/effects/SkRRectsGaussianEdgeMaskFilter.h index d9e30248e2..cd7effc118 100644 --- a/include/effects/SkRRectsGaussianEdgeMaskFilter.h +++ b/include/effects/SkRRectsGaussianEdgeMaskFilter.h @@ -9,6 +9,7 @@ #define SkRRectsGaussianEdgeMaskFilter_DEFINED #include "SkMaskFilter.h" +#include "SkScalar.h" class SkRRect; diff --git a/include/effects/SkTableMaskFilter.h b/include/effects/SkTableMaskFilter.h index f226dd1760..eb6ccb08b1 100644 --- a/include/effects/SkTableMaskFilter.h +++ b/include/effects/SkTableMaskFilter.h @@ -16,7 +16,7 @@ Applies a table lookup on each of the alpha values in the mask. Helper methods create some common tables (e.g. gamma, clipping) */ -class SK_API SkTableMaskFilter : public SkMaskFilter { +class SK_API SkTableMaskFilter { public: /** Utility that sets the gamma table */ @@ -27,40 +27,11 @@ public: */ static void MakeClipTable(uint8_t table[256], uint8_t min, uint8_t max); - static SkMaskFilter* Create(const uint8_t table[256]) { - return new SkTableMaskFilter(table); - } + static SkMaskFilter* Create(const uint8_t table[256]); + static SkMaskFilter* CreateGamma(SkScalar gamma); + static SkMaskFilter* CreateClip(uint8_t min, uint8_t max); - static SkMaskFilter* CreateGamma(SkScalar gamma) { - uint8_t table[256]; - MakeGammaTable(table, gamma); - return new SkTableMaskFilter(table); - } - - static SkMaskFilter* CreateClip(uint8_t min, uint8_t max) { - uint8_t table[256]; - MakeClipTable(table, min, max); - return new SkTableMaskFilter(table); - } - - SkMask::Format getFormat() const override; - bool filterMask(SkMask*, const SkMask&, const SkMatrix&, SkIPoint*) const override; - - SK_TO_STRING_OVERRIDE() - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTableMaskFilter) - -protected: - ~SkTableMaskFilter() override; - - void flatten(SkWriteBuffer&) const override; - -private: - SkTableMaskFilter(); - explicit SkTableMaskFilter(const uint8_t table[256]); - - uint8_t fTable[256]; - - typedef SkMaskFilter INHERITED; + SkTableMaskFilter() = delete; }; #endif diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp index c438ecd2a2..0e88e03b06 100644 --- a/src/core/SkBitmap.cpp +++ b/src/core/SkBitmap.cpp @@ -16,6 +16,7 @@ #include "SkImageInfoPriv.h" #include "SkMallocPixelRef.h" #include "SkMask.h" +#include "SkMaskFilterBase.h" #include "SkMath.h" #include "SkPixelRef.h" #include "SkPixmapPriv.h" @@ -543,7 +544,7 @@ bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint, // compute our (larger?) dst bounds if we have a filter if (filter) { identity.reset(); - if (!filter->filterMask(&dstM, srcM, identity, nullptr)) { + if (!as_MFB(filter)->filterMask(&dstM, srcM, identity, nullptr)) { goto NO_FILTER_CASE; } dstM.fRowBytes = SkAlign4(dstM.fBounds.width()); @@ -567,7 +568,7 @@ bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint, SkAutoMaskFreeImage srcCleanup(srcM.fImage); GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes); - if (!filter->filterMask(&dstM, srcM, identity, nullptr)) { + if (!as_MFB(filter)->filterMask(&dstM, srcM, identity, nullptr)) { goto NO_FILTER_CASE; } SkAutoMaskFreeImage dstCleanup(dstM.fImage); diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp index 1f21e28dad..f4de215972 100644 --- a/src/core/SkBlitter.cpp +++ b/src/core/SkBlitter.cpp @@ -13,7 +13,7 @@ #include "SkReadBuffer.h" #include "SkWriteBuffer.h" #include "SkMask.h" -#include "SkMaskFilter.h" +#include "SkMaskFilterBase.h" #include "SkPaintPriv.h" #include "SkShaderBase.h" #include "SkString.h" @@ -946,7 +946,7 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, SkTCopyOnFirstWrite<SkPaint> paint(origPaint); if (origPaint.getMaskFilter() != nullptr && - origPaint.getMaskFilter()->getFormat() == SkMask::k3D_Format) { + as_MFB(origPaint.getMaskFilter())->getFormat() == SkMask::k3D_Format) { shader3D = sk_make_sp<Sk3DShader>(sk_ref_sp(shader)); // we know we haven't initialized lazyPaint yet, so just do it paint.writable()->setShader(shader3D); diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index 20ce379cd6..3e4722be4d 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -18,7 +18,7 @@ #include "SkDraw.h" #include "SkDrawProcs.h" #include "SkFindAndPlaceGlyph.h" -#include "SkMaskFilter.h" +#include "SkMaskFilterBase.h" #include "SkMatrix.h" #include "SkMatrixUtils.h" #include "SkPaint.h" @@ -842,7 +842,7 @@ void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const { SkMask dstM; if (paint.getMaskFilter() && - paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, nullptr)) { + as_MFB(paint.getMaskFilter())->filterMask(&dstM, srcM, *fMatrix, nullptr)) { mask = &dstM; } SkAutoMaskFreeImage ami(dstM.fImage); @@ -922,7 +922,8 @@ void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const { SkRRect devRRect; if (rrect.transform(*fMatrix, &devRRect)) { SkAutoBlitterChoose blitter(fDst, *fMatrix, paint); - if (paint.getMaskFilter()->filterRRect(devRRect, *fMatrix, *fRC, blitter.get())) { + if (as_MFB(paint.getMaskFilter())->filterRRect(devRRect, *fMatrix, + *fRC, blitter.get())) { return; // filterRRect() called the blitter, so we're done } } @@ -959,7 +960,7 @@ void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawC SkRect pathBounds = devPath.getBounds().makeOutset(1, 1); if (paint.getMaskFilter()) { - paint.getMaskFilter()->computeFastBounds(pathBounds, &pathBounds); + as_MFB(paint.getMaskFilter())->computeFastBounds(pathBounds, &pathBounds); // Need to outset the path to work-around a bug in blurmaskfilter. When that is fixed // we can remove this hack. See skbug.com/5542 @@ -984,7 +985,7 @@ void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawC if (paint.getMaskFilter()) { SkStrokeRec::InitStyle style = doFill ? SkStrokeRec::kFill_InitStyle : SkStrokeRec::kHairline_InitStyle; - if (paint.getMaskFilter()->filterPath(devPath, *fMatrix, *fRC, blitter, style)) { + if (as_MFB(paint.getMaskFilter())->filterPath(devPath, *fMatrix, *fRC, blitter, style)) { return; // filterPath() called the blitter, so we're done } } @@ -1659,7 +1660,7 @@ static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds, srcM.fBounds = *bounds; srcM.fFormat = SkMask::kA8_Format; - if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) { + if (!as_MFB(filter)->filterMask(&dstM, srcM, *filterMatrix, &margin)) { return false; } } diff --git a/src/core/SkMaskFilter.cpp b/src/core/SkMaskFilter.cpp index 75d29e12a8..64767e7efa 100644 --- a/src/core/SkMaskFilter.cpp +++ b/src/core/SkMaskFilter.cpp @@ -5,7 +5,7 @@ * found in the LICENSE file. */ -#include "SkMaskFilter.h" +#include "SkMaskFilterBase.h" #include "SkAutoMalloc.h" #include "SkBlitter.h" @@ -20,7 +20,7 @@ #include "GrFragmentProcessor.h" #endif -SkMaskFilter::NinePatch::~NinePatch() { +SkMaskFilterBase::NinePatch::~NinePatch() { if (fCache) { SkASSERT((const void*)fMask.fImage == fCache->data()); fCache->unref(); @@ -29,12 +29,12 @@ SkMaskFilter::NinePatch::~NinePatch() { } } -bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&, +bool SkMaskFilterBase::filterMask(SkMask*, const SkMask&, const SkMatrix&, SkIPoint*) const { return false; } -bool SkMaskFilter::asABlur(BlurRec*) const { +bool SkMaskFilterBase::asABlur(BlurRec*) const { return false; } @@ -213,8 +213,8 @@ static int countNestedRects(const SkPath& path, SkRect rects[2]) { return path.isRect(&rects[0]); } -bool SkMaskFilter::filterRRect(const SkRRect& devRRect, const SkMatrix& matrix, - const SkRasterClip& clip, SkBlitter* blitter) const { +bool SkMaskFilterBase::filterRRect(const SkRRect& devRRect, const SkMatrix& matrix, + const SkRasterClip& clip, SkBlitter* blitter) const { // Attempt to speed up drawing by creating a nine patch. If a nine patch // cannot be used, return false to allow our caller to recover and perform // the drawing another way. @@ -230,9 +230,9 @@ bool SkMaskFilter::filterRRect(const SkRRect& devRRect, const SkMatrix& matrix, return true; } -bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix, - const SkRasterClip& clip, SkBlitter* blitter, - SkStrokeRec::InitStyle style) const { +bool SkMaskFilterBase::filterPath(const SkPath& devPath, const SkMatrix& matrix, + const SkRasterClip& clip, SkBlitter* blitter, + SkStrokeRec::InitStyle style) const { SkRect rects[2]; int rectCount = 0; if (SkStrokeRec::kFill_InitStyle == style) { @@ -289,20 +289,21 @@ bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix, return true; } -SkMaskFilter::FilterReturn -SkMaskFilter::filterRRectToNine(const SkRRect&, const SkMatrix&, - const SkIRect& clipBounds, NinePatch*) const { +SkMaskFilterBase::FilterReturn +SkMaskFilterBase::filterRRectToNine(const SkRRect&, const SkMatrix&, + const SkIRect& clipBounds, NinePatch*) const { return kUnimplemented_FilterReturn; } -SkMaskFilter::FilterReturn -SkMaskFilter::filterRectsToNine(const SkRect[], int count, const SkMatrix&, - const SkIRect& clipBounds, NinePatch*) const { +SkMaskFilterBase::FilterReturn +SkMaskFilterBase::filterRectsToNine(const SkRect[], int count, const SkMatrix&, + const SkIRect& clipBounds, NinePatch*) const { return kUnimplemented_FilterReturn; } #if SK_SUPPORT_GPU -std::unique_ptr<GrFragmentProcessor> SkMaskFilter::asFragmentProcessor(const GrFPArgs& args) const { +std::unique_ptr<GrFragmentProcessor> +SkMaskFilterBase::asFragmentProcessor(const GrFPArgs& args) const { SkASSERT(args.fLocalMatrix == nullptr); auto fp = this->onAsFragmentProcessor(args); if (fp) { @@ -312,52 +313,53 @@ std::unique_ptr<GrFragmentProcessor> SkMaskFilter::asFragmentProcessor(const GrF } return fp; } -bool SkMaskFilter::hasFragmentProcessor() const { +bool SkMaskFilterBase::hasFragmentProcessor() const { return this->onHasFragmentProcessor(); } -std::unique_ptr<GrFragmentProcessor> SkMaskFilter::onAsFragmentProcessor(const GrFPArgs&) const { +std::unique_ptr<GrFragmentProcessor> +SkMaskFilterBase::onAsFragmentProcessor(const GrFPArgs&) const { return nullptr; } -bool SkMaskFilter::onHasFragmentProcessor() const { return false; } +bool SkMaskFilterBase::onHasFragmentProcessor() const { return false; } -bool SkMaskFilter::canFilterMaskGPU(const SkRRect& devRRect, - const SkIRect& clipBounds, - const SkMatrix& ctm, - SkRect* maskRect) const { +bool SkMaskFilterBase::canFilterMaskGPU(const SkRRect& devRRect, + const SkIRect& clipBounds, + const SkMatrix& ctm, + SkRect* maskRect) const { return false; } -bool SkMaskFilter::directFilterMaskGPU(GrContext*, - GrRenderTargetContext* renderTargetContext, - GrPaint&&, - const GrClip&, - const SkMatrix& viewMatrix, - const SkStrokeRec& strokeRec, - const SkPath& path) const { +bool SkMaskFilterBase::directFilterMaskGPU(GrContext*, + GrRenderTargetContext* renderTargetContext, + GrPaint&&, + const GrClip&, + const SkMatrix& viewMatrix, + const SkStrokeRec& strokeRec, + const SkPath& path) const { return false; } -bool SkMaskFilter::directFilterRRectMaskGPU(GrContext*, - GrRenderTargetContext* renderTargetContext, - GrPaint&&, - const GrClip&, - const SkMatrix& viewMatrix, - const SkStrokeRec& strokeRec, - const SkRRect& rrect, - const SkRRect& devRRect) const { +bool SkMaskFilterBase::directFilterRRectMaskGPU(GrContext*, + GrRenderTargetContext* renderTargetContext, + GrPaint&&, + const GrClip&, + const SkMatrix& viewMatrix, + const SkStrokeRec& strokeRec, + const SkRRect& rrect, + const SkRRect& devRRect) const { return false; } -sk_sp<GrTextureProxy> SkMaskFilter::filterMaskGPU(GrContext*, - sk_sp<GrTextureProxy> srcProxy, - const SkMatrix& ctm, - const SkIRect& maskRect) const { +sk_sp<GrTextureProxy> SkMaskFilterBase::filterMaskGPU(GrContext*, + sk_sp<GrTextureProxy> srcProxy, + const SkMatrix& ctm, + const SkIRect& maskRect) const { return nullptr; } #endif -void SkMaskFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { +void SkMaskFilterBase::computeFastBounds(const SkRect& src, SkRect* dst) const { SkMask srcM, dstM; srcM.fBounds = src.roundOut(); diff --git a/src/core/SkMaskFilterBase.h b/src/core/SkMaskFilterBase.h new file mode 100644 index 0000000000..4b4b4258d6 --- /dev/null +++ b/src/core/SkMaskFilterBase.h @@ -0,0 +1,251 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkMaskFilterBase_DEFINED +#define SkMaskFilterBase_DEFINED + +#include "SkBlurTypes.h" +#include "SkFlattenable.h" +#include "SkMask.h" +#include "SkMaskFilter.h" +#include "SkPaint.h" +#include "SkStrokeRec.h" + +class GrClip; +class GrContext; +struct GrFPArgs; +class GrRenderTargetContext; +class GrPaint; +class GrFragmentProcessor; +class GrRenderTarget; +class GrResourceProvider; +class GrTexture; +class GrTextureProxy; +class SkBitmap; +class SkBlitter; +class SkCachedData; +class SkMatrix; +class SkPath; +class SkRasterClip; +class SkRRect; + +class SkMaskFilterBase : public SkMaskFilter { +public: + /** Returns the format of the resulting mask that this subclass will return + when its filterMask() method is called. + */ + virtual SkMask::Format getFormat() const = 0; + + /** Create a new mask by filter the src mask. + If src.fImage == null, then do not allocate or create the dst image + but do fill out the other fields in dstMask. + If you do allocate a dst image, use SkMask::AllocImage() + If this returns false, dst mask is ignored. + @param dst the result of the filter. If src.fImage == null, dst should not allocate its image + @param src the original image to be filtered. + @param matrix the CTM + @param margin if not null, return the buffer dx/dy need when calculating the effect. Used when + drawing a clipped object to know how much larger to allocate the src before + applying the filter. If returning false, ignore this parameter. + @return true if the dst mask was correctly created. + */ + virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, + SkIPoint* margin) const; + +#if SK_SUPPORT_GPU + /** + * Returns a processor if the filter can be expressed a single-pass GrProcessor without + * requiring an explicit input mask. Per-pixel, the effect receives the incoming mask's + * coverage as the input color and outputs the filtered covereage value. This means that each + * pixel's filtered coverage must only depend on the unfiltered mask value for that pixel and + * not on surrounding values. + */ + std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs& args) const; + + /** + * Returns true iff asFragmentProcessor() will return a processor + */ + bool hasFragmentProcessor() const; + + /** + * If asFragmentProcessor() fails the filter may be implemented on the GPU by a subclass + * overriding filterMaskGPU (declared below). That code path requires constructing a + * src mask as input. Since that is a potentially expensive operation, the subclass must also + * override this function to indicate whether filterTextureMaskGPU would succeeed if the mask + * were to be created. + * + * 'maskRect' returns the device space portion of the mask that the filter needs. The mask + * passed into 'filterMaskGPU' should have the same extent as 'maskRect' but be + * translated to the upper-left corner of the mask (i.e., (maskRect.fLeft, maskRect.fTop) + * appears at (0, 0) in the mask). + * + * Logically, how this works is: + * canFilterMaskGPU is called + * if (it returns true) + * the returned mask rect is used for quick rejecting + * either directFilterMaskGPU or directFilterRRectMaskGPU is then called + * if (neither of them handle the blur) + * the mask rect is used to generate the mask + * filterMaskGPU is called to filter the mask + * + * TODO: this should work as: + * if (canFilterMaskGPU(devShape, ...)) // rect, rrect, drrect, path + * filterMaskGPU(devShape, ...) + * this would hide the RRect special case and the mask generation + */ + virtual bool canFilterMaskGPU(const SkRRect& devRRect, + const SkIRect& clipBounds, + const SkMatrix& ctm, + SkRect* maskRect) const; + + /** + * Try to directly render the mask filter into the target. Returns true if drawing was + * successful. If false is returned then paint is unmodified. + */ + virtual bool directFilterMaskGPU(GrContext*, + GrRenderTargetContext* renderTargetContext, + GrPaint&& paint, + const GrClip&, + const SkMatrix& viewMatrix, + const SkStrokeRec& strokeRec, + const SkPath& path) const; + /** + * Try to directly render a rounded rect mask filter into the target. Returns + * true if drawing was successful. If false is returned then paint is unmodified. + */ + virtual bool directFilterRRectMaskGPU(GrContext*, + GrRenderTargetContext* renderTargetContext, + GrPaint&& paint, + const GrClip&, + const SkMatrix& viewMatrix, + const SkStrokeRec& strokeRec, + const SkRRect& rrect, + const SkRRect& devRRect) const; + + /** + * This function is used to implement filters that require an explicit src mask. It should only + * be called if canFilterMaskGPU returned true and the maskRect param should be the output from + * that call. + * Implementations are free to get the GrContext from the src texture in order to create + * additional textures and perform multiple passes. + */ + virtual sk_sp<GrTextureProxy> filterMaskGPU(GrContext*, + sk_sp<GrTextureProxy> srcProxy, + const SkMatrix& ctm, + const SkIRect& maskRect) const; +#endif + + /** + * The fast bounds function is used to enable the paint to be culled early + * in the drawing pipeline. This function accepts the current bounds of the + * paint as its src param and the filter adjust those bounds using its + * current mask and returns the result using the dest param. Callers are + * allowed to provide the same struct for both src and dest so each + * implementation must accomodate that behavior. + * + * The default impl calls filterMask with the src mask having no image, + * but subclasses may override this if they can compute the rect faster. + */ + virtual void computeFastBounds(const SkRect& src, SkRect* dest) const; + + struct BlurRec { + SkScalar fSigma; + SkBlurStyle fStyle; + SkBlurQuality fQuality; + }; + /** + * If this filter can be represented by a BlurRec, return true and (if not null) fill in the + * provided BlurRec parameter. If this effect cannot be represented as a BlurRec, return false + * and ignore the BlurRec parameter. + */ + virtual bool asABlur(BlurRec*) const; + +protected: + SkMaskFilterBase() {} + +#if SK_SUPPORT_GPU + virtual std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs&) const; + virtual bool onHasFragmentProcessor() const; +#endif + + enum FilterReturn { + kFalse_FilterReturn, + kTrue_FilterReturn, + kUnimplemented_FilterReturn + }; + + class NinePatch : ::SkNoncopyable { + public: + NinePatch() : fCache(nullptr) { } + ~NinePatch(); + + SkMask fMask; // fBounds must have [0,0] in its top-left + SkIRect fOuterRect; // width/height must be >= fMask.fBounds' + SkIPoint fCenter; // identifies center row/col for stretching + SkCachedData* fCache; + }; + + /** + * Override if your subclass can filter a rect, and return the answer as + * a ninepatch mask to be stretched over the returned outerRect. On success + * return kTrue_FilterReturn. On failure (e.g. out of memory) return + * kFalse_FilterReturn. If the normal filterMask() entry-point should be + * called (the default) return kUnimplemented_FilterReturn. + * + * By convention, the caller will take the center rol/col from the returned + * mask as the slice it can replicate horizontally and vertically as we + * stretch the mask to fit inside outerRect. It is an error for outerRect + * to be smaller than the mask's bounds. This would imply that the width + * and height of the mask should be odd. This is not required, just that + * the caller will call mask.fBounds.centerX() and centerY() to find the + * strips that will be replicated. + */ + virtual FilterReturn filterRectsToNine(const SkRect[], int count, + const SkMatrix&, + const SkIRect& clipBounds, + NinePatch*) const; + /** + * Similar to filterRectsToNine, except it performs the work on a round rect. + */ + virtual FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&, + const SkIRect& clipBounds, + NinePatch*) const; + +private: + friend class SkDraw; + + /** Helper method that, given a path in device space, will rasterize it into a kA8_Format mask + and then call filterMask(). If this returns true, the specified blitter will be called + to render that mask. Returns false if filterMask() returned false. + This method is not exported to java. + */ + bool filterPath(const SkPath& devPath, const SkMatrix& ctm, const SkRasterClip&, SkBlitter*, + SkStrokeRec::InitStyle) const; + + /** Helper method that, given a roundRect in device space, will rasterize it into a kA8_Format + mask and then call filterMask(). If this returns true, the specified blitter will be called + to render that mask. Returns false if filterMask() returned false. + */ + bool filterRRect(const SkRRect& devRRect, const SkMatrix& ctm, const SkRasterClip&, + SkBlitter*) const; + + typedef SkFlattenable INHERITED; +}; + +inline SkMaskFilterBase* as_MFB(SkMaskFilter* mf) { + return static_cast<SkMaskFilterBase*>(mf); +} + +inline const SkMaskFilterBase* as_MFB(const SkMaskFilter* mf) { + return static_cast<const SkMaskFilterBase*>(mf); +} + +inline const SkMaskFilterBase* as_MFB(const sk_sp<SkMaskFilter>& mf) { + return static_cast<SkMaskFilterBase*>(mf.get()); +} + +#endif diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 3cfa690b1e..0686c3b017 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -1967,7 +1967,7 @@ const SkRect& SkPaint::doComputeFastBounds(const SkRect& origSrc, *storage = src->makeOutset(radius, radius); if (this->getMaskFilter()) { - this->getMaskFilter()->computeFastBounds(*storage, storage); + as_MFB(this->getMaskFilter())->computeFastBounds(*storage, storage); } if (this->getImageFilter()) { @@ -2034,7 +2034,7 @@ void SkPaint::toString(SkString* str) const { SkMaskFilter* maskFilter = this->getMaskFilter(); if (maskFilter) { str->append("<dt>MaskFilter:</dt><dd>"); - maskFilter->toString(str); + as_MFB(maskFilter)->toString(str); str->append("</dd>"); } diff --git a/src/core/SkReadBuffer.h b/src/core/SkReadBuffer.h index 34c3c50fa3..4e0453a7aa 100644 --- a/src/core/SkReadBuffer.h +++ b/src/core/SkReadBuffer.h @@ -13,7 +13,7 @@ #include "SkSerialProcs.h" #include "SkDrawLooper.h" #include "SkImageFilter.h" -#include "SkMaskFilter.h" +#include "SkMaskFilterBase.h" #include "SkPath.h" #include "SkPathEffect.h" #include "SkPicture.h" @@ -143,7 +143,7 @@ public: sk_sp<SkColorFilter> readColorFilter() { return this->readFlattenable<SkColorFilter>(); } sk_sp<SkDrawLooper> readDrawLooper() { return this->readFlattenable<SkDrawLooper>(); } sk_sp<SkImageFilter> readImageFilter() { return this->readFlattenable<SkImageFilter>(); } - sk_sp<SkMaskFilter> readMaskFilter() { return this->readFlattenable<SkMaskFilter>(); } + sk_sp<SkMaskFilter> readMaskFilter() { return this->readFlattenable<SkMaskFilterBase>(); } sk_sp<SkPathEffect> readPathEffect() { return this->readFlattenable<SkPathEffect>(); } sk_sp<SkShader> readShader() { return this->readFlattenable<SkShaderBase>(); } diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp index fafaf367eb..d082232986 100644 --- a/src/core/SkScalerContext.cpp +++ b/src/core/SkScalerContext.cpp @@ -175,7 +175,7 @@ void SkScalerContext::getMetrics(SkGlyph* glyph) { fRec.getMatrixFrom2x2(&matrix); src.fImage = nullptr; // only want the bounds from the filter - if (fMaskFilter->filterMask(&dst, src, matrix, nullptr)) { + if (as_MFB(fMaskFilter)->filterMask(&dst, src, matrix, nullptr)) { if (dst.fBounds.isEmpty() || !dst.fBounds.is16Bit()) { goto SK_ERROR; } @@ -504,7 +504,7 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) { fRec.getMatrixFrom2x2(&matrix); - if (fMaskFilter->filterMask(&dstM, srcM, matrix, nullptr)) { + if (as_MFB(fMaskFilter)->filterMask(&dstM, srcM, matrix, nullptr)) { int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width()); int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height()); int dstRB = origGlyph.rowBytes(); diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp index 0d67b4a18f..d730d62d14 100644 --- a/src/effects/SkBlurMaskFilter.cpp +++ b/src/effects/SkBlurMaskFilter.cpp @@ -8,6 +8,7 @@ #include "SkBlurMaskFilter.h" #include "SkBlurMask.h" #include "SkGpuBlurUtils.h" +#include "SkMaskFilterBase.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" #include "SkMaskFilter.h" @@ -40,7 +41,7 @@ SkScalar SkBlurMaskFilter::ConvertRadiusToSigma(SkScalar radius) { return SkBlurMask::ConvertRadiusToSigma(radius); } -class SkBlurMaskFilterImpl : public SkMaskFilter { +class SkBlurMaskFilterImpl : public SkMaskFilterBase { public: SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle, const SkRect& occluder, uint32_t flags); @@ -459,7 +460,7 @@ static SkCachedData* add_cached_rects(SkMask* mask, SkScalar sigma, SkBlurStyle static const bool c_analyticBlurRRect{true}; #endif -SkMaskFilter::FilterReturn +SkMaskFilterBase::FilterReturn SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& matrix, const SkIRect& clipBounds, NinePatch* patch) const { @@ -596,7 +597,7 @@ SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma // Use the faster analytic blur approach for ninepatch rects static const bool c_analyticBlurNinepatch{true}; -SkMaskFilter::FilterReturn +SkMaskFilterBase::FilterReturn SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count, const SkMatrix& matrix, const SkIRect& clipBounds, diff --git a/src/effects/SkEmbossMaskFilter.h b/src/effects/SkEmbossMaskFilter.h index 29b70ad1f9..89bb5c8921 100644 --- a/src/effects/SkEmbossMaskFilter.h +++ b/src/effects/SkEmbossMaskFilter.h @@ -8,13 +8,13 @@ #ifndef SkEmbossMaskFilter_DEFINED #define SkEmbossMaskFilter_DEFINED -#include "SkMaskFilter.h" +#include "SkMaskFilterBase.h" /** \class SkEmbossMaskFilter This mask filter creates a 3D emboss look, by specifying a light and blur amount. */ -class SK_API SkEmbossMaskFilter : public SkMaskFilter { +class SK_API SkEmbossMaskFilter : public SkMaskFilterBase { public: struct Light { SkScalar fDirection[3]; // x,y,z diff --git a/src/effects/SkLayerDrawLooper.cpp b/src/effects/SkLayerDrawLooper.cpp index 7dff657c52..17aa7a123d 100644 --- a/src/effects/SkLayerDrawLooper.cpp +++ b/src/effects/SkLayerDrawLooper.cpp @@ -10,6 +10,7 @@ #include "SkCanvas.h" #include "SkColorSpaceXformer.h" #include "SkColor.h" +#include "SkMaskFilterBase.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" #include "SkLayerDrawLooper.h" @@ -181,8 +182,8 @@ bool SkLayerDrawLooper::asABlurShadow(BlurShadowRec* bsRec) const { if (nullptr == mf) { return false; } - SkMaskFilter::BlurRec maskBlur; - if (!mf->asABlur(&maskBlur)) { + SkMaskFilterBase::BlurRec maskBlur; + if (!as_MFB(mf)->asABlur(&maskBlur)) { return false; } diff --git a/src/effects/SkRRectsGaussianEdgeMaskFilter.cpp b/src/effects/SkRRectsGaussianEdgeMaskFilter.cpp index 09739c0813..850e440099 100644 --- a/src/effects/SkRRectsGaussianEdgeMaskFilter.cpp +++ b/src/effects/SkRRectsGaussianEdgeMaskFilter.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "SkMaskFilterBase.h" #include "SkRRectsGaussianEdgeMaskFilter.h" #include "SkReadBuffer.h" #include "SkRRect.h" @@ -19,7 +20,7 @@ * The round rects must have the same radii at each corner and the x&y radii * must also be equal. */ -class SkRRectsGaussianEdgeMaskFilterImpl : public SkMaskFilter { +class SkRRectsGaussianEdgeMaskFilterImpl : public SkMaskFilterBase { public: SkRRectsGaussianEdgeMaskFilterImpl(const SkRRect& first, const SkRRect& second, SkScalar radius) diff --git a/src/effects/SkShaderMaskFilter.cpp b/src/effects/SkShaderMaskFilter.cpp index 8693751899..f2088fce72 100644 --- a/src/effects/SkShaderMaskFilter.cpp +++ b/src/effects/SkShaderMaskFilter.cpp @@ -6,12 +6,13 @@ */ #include "SkCanvas.h" +#include "SkMaskFilterBase.h" #include "SkReadBuffer.h" #include "SkShaderMaskFilter.h" #include "SkShader.h" #include "SkString.h" -class SkShaderMF : public SkMaskFilter { +class SkShaderMF : public SkMaskFilterBase { public: SkShaderMF(sk_sp<SkShader> shader) : fShader(std::move(shader)) {} diff --git a/src/effects/SkTableMaskFilter.cpp b/src/effects/SkTableMaskFilter.cpp index a3b4038a2f..5006f04cb0 100644 --- a/src/effects/SkTableMaskFilter.cpp +++ b/src/effects/SkTableMaskFilter.cpp @@ -5,26 +5,48 @@ * found in the LICENSE file. */ - #include "SkFixed.h" #include "SkReadBuffer.h" #include "SkString.h" #include "SkTableMaskFilter.h" #include "SkWriteBuffer.h" -SkTableMaskFilter::SkTableMaskFilter() { +class SkTableMaskFilterImpl : public SkMaskFilterBase { +public: + explicit SkTableMaskFilterImpl(const uint8_t table[256]); + + SkMask::Format getFormat() const override; + bool filterMask(SkMask*, const SkMask&, const SkMatrix&, SkIPoint*) const override; + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTableMaskFilterImpl) + +protected: + ~SkTableMaskFilterImpl() override; + + void flatten(SkWriteBuffer&) const override; + +private: + SkTableMaskFilterImpl(); + + uint8_t fTable[256]; + + typedef SkMaskFilter INHERITED; +}; + +SkTableMaskFilterImpl::SkTableMaskFilterImpl() { for (int i = 0; i < 256; i++) { fTable[i] = i; } } -SkTableMaskFilter::SkTableMaskFilter(const uint8_t table[256]) { +SkTableMaskFilterImpl::SkTableMaskFilterImpl(const uint8_t table[256]) { memcpy(fTable, table, sizeof(fTable)); } -SkTableMaskFilter::~SkTableMaskFilter() {} +SkTableMaskFilterImpl::~SkTableMaskFilterImpl() {} -bool SkTableMaskFilter::filterMask(SkMask* dst, const SkMask& src, +bool SkTableMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, SkIPoint* margin) const { if (src.fFormat != SkMask::kA8_Format) { return false; @@ -66,24 +88,40 @@ bool SkTableMaskFilter::filterMask(SkMask* dst, const SkMask& src, return true; } -SkMask::Format SkTableMaskFilter::getFormat() const { +SkMask::Format SkTableMaskFilterImpl::getFormat() const { return SkMask::kA8_Format; } -void SkTableMaskFilter::flatten(SkWriteBuffer& wb) const { +void SkTableMaskFilterImpl::flatten(SkWriteBuffer& wb) const { wb.writeByteArray(fTable, 256); } -sk_sp<SkFlattenable> SkTableMaskFilter::CreateProc(SkReadBuffer& buffer) { +sk_sp<SkFlattenable> SkTableMaskFilterImpl::CreateProc(SkReadBuffer& buffer) { uint8_t table[256]; if (!buffer.readByteArray(table, 256)) { return nullptr; } - return sk_sp<SkFlattenable>(Create(table)); + return sk_sp<SkFlattenable>(SkTableMaskFilter::Create(table)); } /////////////////////////////////////////////////////////////////////////////// +SkMaskFilter* SkTableMaskFilter::Create(const uint8_t table[256]) { + return new SkTableMaskFilterImpl(table); +} + +SkMaskFilter* SkTableMaskFilter::CreateGamma(SkScalar gamma) { + uint8_t table[256]; + MakeGammaTable(table, gamma); + return new SkTableMaskFilterImpl(table); +} + +SkMaskFilter* SkTableMaskFilter::CreateClip(uint8_t min, uint8_t max) { + uint8_t table[256]; + MakeClipTable(table, min, max); + return new SkTableMaskFilterImpl(table); +} + void SkTableMaskFilter::MakeGammaTable(uint8_t table[256], SkScalar gamma) { const float dx = 1 / 255.0f; const float g = SkScalarToFloat(gamma); @@ -131,7 +169,7 @@ void SkTableMaskFilter::MakeClipTable(uint8_t table[256], uint8_t min, } #ifndef SK_IGNORE_TO_STRING -void SkTableMaskFilter::toString(SkString* str) const { +void SkTableMaskFilterImpl::toString(SkString* str) const { str->append("SkTableMaskFilter: ("); str->append("table: "); diff --git a/src/gpu/GrBlurUtils.cpp b/src/gpu/GrBlurUtils.cpp index aff3647f6c..b79a38a884 100644 --- a/src/gpu/GrBlurUtils.cpp +++ b/src/gpu/GrBlurUtils.cpp @@ -17,7 +17,7 @@ #include "GrTextureProxy.h" #include "SkDraw.h" #include "SkGr.h" -#include "SkMaskFilter.h" +#include "SkMaskFilterBase.h" #include "SkPaint.h" #include "SkTLazy.h" @@ -65,7 +65,7 @@ static bool sw_draw_with_mask_filter(GrContext* context, } SkAutoMaskFreeImage autoSrc(srcM.fImage); - if (!filter->filterMask(&dstM, srcM, viewMatrix, nullptr)) { + if (!as_MFB(filter)->filterMask(&dstM, srcM, viewMatrix, nullptr)) { return false; } // this will free-up dstM when we're done (allocated in filterMask()) @@ -144,7 +144,7 @@ static void draw_path_with_mask_filter(GrContext* context, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, - const SkMaskFilter* maskFilter, + const SkMaskFilterBase* maskFilter, const GrStyle& style, const SkPath* path, bool pathIsMutable) { @@ -252,7 +252,7 @@ void GrBlurUtils::drawPathWithMaskFilter(GrContext* context, const GrStyle& style, bool pathIsMutable) { draw_path_with_mask_filter(context, renderTargetContext, clip, std::move(paint), aa, viewMatrix, - mf, style, &path, pathIsMutable); + as_MFB(mf), style, &path, pathIsMutable); } void GrBlurUtils::drawPathWithMaskFilter(GrContext* context, @@ -297,7 +297,7 @@ void GrBlurUtils::drawPathWithMaskFilter(GrContext* context, return; } GrAA aa = GrAA(paint.isAntiAlias()); - SkMaskFilter* mf = paint.getMaskFilter(); + SkMaskFilterBase* mf = as_MFB(paint.getMaskFilter()); if (mf && !mf->hasFragmentProcessor()) { // The MaskFilter wasn't already handled in SkPaintToGrPaint draw_path_with_mask_filter(context, renderTargetContext, clip, std::move(grPaint), aa, diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 3f7dcb41e0..080d993c68 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -28,7 +28,7 @@ #include "SkImageInfoPriv.h" #include "SkImage_Base.h" #include "SkLatticeIter.h" -#include "SkMaskFilter.h" +#include "SkMaskFilterBase.h" #include "SkPathEffect.h" #include "SkPicture.h" #include "SkPictureData.h" @@ -402,7 +402,7 @@ void SkGpuDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) { return; } - SkMaskFilter* mf = paint.getMaskFilter(); + SkMaskFilterBase* mf = as_MFB(paint.getMaskFilter()); if (mf) { if (mf->hasFragmentProcessor()) { mf = nullptr; // already handled in SkPaintToGrPaint diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp index 9e980cddb5..0798f1e012 100644 --- a/src/gpu/SkGpuDevice_drawTexture.cpp +++ b/src/gpu/SkGpuDevice_drawTexture.cpp @@ -15,7 +15,7 @@ #include "GrTextureMaker.h" #include "SkDraw.h" #include "SkGr.h" -#include "SkMaskFilter.h" +#include "SkMaskFilterBase.h" #include "effects/GrBicubicEffect.h" #include "effects/GrSimpleTextureEffect.h" #include "effects/GrTextureDomain.h" @@ -323,14 +323,14 @@ void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer, viewMatrix.mapRectScaleTranslate(&devClippedDstRect, clippedDstRect); SkStrokeRec rec(SkStrokeRec::kFill_InitStyle); - if (mf->directFilterRRectMaskGPU(fContext.get(), - fRenderTargetContext.get(), - std::move(grPaint), - this->clip(), - viewMatrix, - rec, - SkRRect::MakeRect(clippedDstRect), - SkRRect::MakeRect(devClippedDstRect))) { + if (as_MFB(mf)->directFilterRRectMaskGPU(fContext.get(), + fRenderTargetContext.get(), + std::move(grPaint), + this->clip(), + viewMatrix, + rec, + SkRRect::MakeRect(clippedDstRect), + SkRRect::MakeRect(devClippedDstRect))) { return; } } diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp index 6b1c779ff8..4d3ce4752a 100644 --- a/src/gpu/SkGr.cpp +++ b/src/gpu/SkGr.cpp @@ -24,7 +24,7 @@ #include "SkConvertPixels.h" #include "SkData.h" #include "SkImageInfoPriv.h" -#include "SkMaskFilter.h" +#include "SkMaskFilterBase.h" #include "SkMessageBus.h" #include "SkMipMap.h" #include "SkPM4fPriv.h" @@ -477,7 +477,7 @@ static inline bool skpaint_to_grpaint_impl(GrContext* context, } } - SkMaskFilter* maskFilter = skPaint.getMaskFilter(); + SkMaskFilterBase* maskFilter = as_MFB(skPaint.getMaskFilter()); if (maskFilter) { if (auto mfFP = maskFilter->asFragmentProcessor(fpArgs)) { grPaint->addCoverageFragmentProcessor(std::move(mfFP)); diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp index 69e5e775be..7fce4ba856 100644 --- a/src/gpu/text/GrAtlasTextBlob.cpp +++ b/src/gpu/text/GrAtlasTextBlob.cpp @@ -13,6 +13,7 @@ #include "SkColorFilter.h" #include "SkDrawFilter.h" #include "SkGlyphCache.h" +#include "SkMaskFilterBase.h" #include "SkTextBlobRunIterator.h" #include "ops/GrAtlasTextOp.h" @@ -152,7 +153,7 @@ void GrAtlasTextBlob::appendBigGlyph(GrGlyph* glyph, SkGlyphCache* cache, const } bool GrAtlasTextBlob::mustRegenerate(const GrTextUtils::Paint& paint, - const SkMaskFilter::BlurRec& blurRec, + const SkMaskFilterBase::BlurRec& blurRec, const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { // If we have LCD text then our canonical color will be set to transparent, in this case we have // to regenerate the blob on any color change diff --git a/src/gpu/text/GrAtlasTextBlob.h b/src/gpu/text/GrAtlasTextBlob.h index 94ec54a775..12a80c49d3 100644 --- a/src/gpu/text/GrAtlasTextBlob.h +++ b/src/gpu/text/GrAtlasTextBlob.h @@ -14,7 +14,7 @@ #include "GrMemoryPool.h" #include "GrTextUtils.h" #include "SkDescriptor.h" -#include "SkMaskFilter.h" +#include "SkMaskFilterBase.h" #include "SkOpts.h" #include "SkPathEffect.h" #include "SkPoint3.h" @@ -81,7 +81,7 @@ public: }; void setupKey(const GrAtlasTextBlob::Key& key, - const SkMaskFilter::BlurRec& blurRec, + const SkMaskFilterBase::BlurRec& blurRec, const SkPaint& paint) { fKey = key; if (key.fHasBlur) { @@ -190,7 +190,7 @@ public: } } - bool mustRegenerate(const GrTextUtils::Paint&, const SkMaskFilter::BlurRec& blurRec, + bool mustRegenerate(const GrTextUtils::Paint&, const SkMaskFilterBase::BlurRec& blurRec, const SkMatrix& viewMatrix, SkScalar x, SkScalar y); // flush a GrAtlasTextBlob associated with a SkTextBlob @@ -536,7 +536,7 @@ private: GrGlyph** fGlyphs; Run* fRuns; GrMemoryPool* fPool; - SkMaskFilter::BlurRec fBlurRec; + SkMaskFilterBase::BlurRec fBlurRec; StrokeInfo fStrokeInfo; SkTArray<BigGlyph> fBigGlyphs; Key fKey; diff --git a/src/gpu/text/GrAtlasTextContext.cpp b/src/gpu/text/GrAtlasTextContext.cpp index 4193c7d32c..41c46466ac 100644 --- a/src/gpu/text/GrAtlasTextContext.cpp +++ b/src/gpu/text/GrAtlasTextContext.cpp @@ -15,6 +15,7 @@ #include "SkGr.h" #include "SkGraphics.h" #include "SkMakeUnique.h" +#include "SkMaskFilterBase.h" #include "ops/GrMeshDrawOp.h" // DF sizes and thresholds for usage of the small and medium sizes. For example, above @@ -113,13 +114,13 @@ void GrAtlasTextContext::drawTextBlob(GrContext* context, GrTextUtils::Target* t } sk_sp<GrAtlasTextBlob> cacheBlob; - SkMaskFilter::BlurRec blurRec; + SkMaskFilterBase::BlurRec blurRec; GrAtlasTextBlob::Key key; // It might be worth caching these things, but its not clear at this time // TODO for animated mask filters, this will fill up our cache. We need a safeguard here const SkMaskFilter* mf = skPaint.getMaskFilter(); bool canCache = !(skPaint.getPathEffect() || - (mf && !mf->asABlur(&blurRec)) || + (mf && !as_MFB(mf)->asABlur(&blurRec)) || drawFilter); SkScalerContextFlags scalerContextFlags = ComputeScalerContextFlags(target->colorSpaceInfo()); diff --git a/src/gpu/text/GrTextBlobCache.h b/src/gpu/text/GrTextBlobCache.h index ac15124937..7a5c3a8c28 100644 --- a/src/gpu/text/GrTextBlobCache.h +++ b/src/gpu/text/GrTextBlobCache.h @@ -48,7 +48,7 @@ public: sk_sp<GrAtlasTextBlob> makeCachedBlob(const SkTextBlob* blob, const GrAtlasTextBlob::Key& key, - const SkMaskFilter::BlurRec& blurRec, + const SkMaskFilterBase::BlurRec& blurRec, const SkPaint& paint) { sk_sp<GrAtlasTextBlob> cacheBlob(this->makeBlob(blob)); cacheBlob->setupKey(key, blurRec, paint); diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index 0628b8f905..91f170d194 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -21,7 +21,7 @@ #include "SkImageFilterCache.h" #include "SkJpegEncoder.h" #include "SkMakeUnique.h" -#include "SkMaskFilter.h" +#include "SkMaskFilterBase.h" #include "SkPDFBitmap.h" #include "SkPDFCanon.h" #include "SkPDFDocument.h" @@ -841,7 +841,7 @@ void SkPDFDevice::internalDrawPathWithFilter(const SkClipStack& clipStack, SkAutoMaskFreeImage srcAutoMaskFreeImage(sourceMask.fImage); SkMask dstMask; SkIPoint margin; - if (!paint->getMaskFilter()->filterMask(&dstMask, sourceMask, ctm, &margin)) { + if (!as_MFB(paint->getMaskFilter())->filterMask(&dstMask, sourceMask, ctm, &margin)) { return; } SkIRect dstMaskBounds = dstMask.fBounds; diff --git a/src/xps/SkXPSDevice.cpp b/src/xps/SkXPSDevice.cpp index dcf88aac00..94c6b79c32 100644 --- a/src/xps/SkXPSDevice.cpp +++ b/src/xps/SkXPSDevice.cpp @@ -34,7 +34,7 @@ #include "SkImage.h" #include "SkImageEncoder.h" #include "SkImagePriv.h" -#include "SkMaskFilter.h" +#include "SkMaskFilterBase.h" #include "SkPaint.h" #include "SkPathEffect.h" #include "SkPathOps.h" @@ -1615,7 +1615,7 @@ void SkXPSDevice::drawPath(const SkPath& platonicPath, //[Mask -> Mask] SkMask filteredMask; - if (filter->filterMask(&filteredMask, rasteredMask, matrix, nullptr)) { + if (as_MFB(filter)->filterMask(&filteredMask, rasteredMask, matrix, nullptr)) { mask = &filteredMask; } SkAutoMaskFreeImage filteredAmi(filteredMask.fImage); diff --git a/tests/BlurTest.cpp b/tests/BlurTest.cpp index 6c5ef269d7..d8d917fe8f 100644 --- a/tests/BlurTest.cpp +++ b/tests/BlurTest.cpp @@ -12,6 +12,7 @@ #include "SkColorFilter.h" #include "SkEmbossMaskFilter.h" #include "SkLayerDrawLooper.h" +#include "SkMaskFilterBase.h" #include "SkMath.h" #include "SkPaint.h" #include "SkPath.h" @@ -456,8 +457,8 @@ DEF_TEST(BlurAsABlur, reporter) { REPORTER_ASSERT(reporter, sigma <= 0); } else { REPORTER_ASSERT(reporter, sigma > 0); - SkMaskFilter::BlurRec rec; - bool success = mf->asABlur(&rec); + SkMaskFilterBase::BlurRec rec; + bool success = as_MFB(mf)->asABlur(&rec); if (flags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) { REPORTER_ASSERT(reporter, !success); } else { @@ -483,8 +484,8 @@ DEF_TEST(BlurAsABlur, reporter) { const SkScalar sigma = sigmas[j]; auto mf(SkEmbossMaskFilter::Make(sigma, light)); if (mf) { - SkMaskFilter::BlurRec rec; - bool success = mf->asABlur(&rec); + SkMaskFilterBase::BlurRec rec; + bool success = as_MFB(mf)->asABlur(&rec); REPORTER_ASSERT(reporter, !success); } } diff --git a/tests/FlattenDrawableTest.cpp b/tests/FlattenDrawableTest.cpp index 9df8ba0b5b..411b082dba 100644 --- a/tests/FlattenDrawableTest.cpp +++ b/tests/FlattenDrawableTest.cpp @@ -284,3 +284,18 @@ DEF_TEST(FlattenRecordedDrawable, r) { REPORTER_ASSERT(r, out); REPORTER_ASSERT(r, !strcmp("SkRecordedDrawable", out->getTypeName())); } + +// be sure these constructs compile, don't assert, and return null +DEF_TEST(Flattenable_EmptyDeserialze, reporter) { + auto data = SkData::MakeEmpty(); + + #define test(name) REPORTER_ASSERT(reporter, !name::Deserialize(data->data(), data->size())) + test(SkPathEffect); + test(SkMaskFilter); + test(SkShaderBase); // todo: make this just be shader! + test(SkColorFilter); + test(SkImageFilter); + test(SkDrawLooper); + #undef test +} + diff --git a/tools/debugger/SkDrawCommand.cpp b/tools/debugger/SkDrawCommand.cpp index 34189fa6a4..c1f06773d3 100644 --- a/tools/debugger/SkDrawCommand.cpp +++ b/tools/debugger/SkDrawCommand.cpp @@ -15,7 +15,7 @@ #include "SkDashPathEffect.h" #include "SkImageFilter.h" #include "SkJsonWriteBuffer.h" -#include "SkMaskFilter.h" +#include "SkMaskFilterBase.h" #include "SkObjectParser.h" #include "SkPaintDefaults.h" #include "SkPathEffect.h" @@ -1071,8 +1071,8 @@ static void apply_paint_maskfilter(const SkPaint& paint, Json::Value* target, UrlDataManager& urlDataManager) { SkMaskFilter* maskFilter = paint.getMaskFilter(); if (maskFilter != nullptr) { - SkMaskFilter::BlurRec blurRec; - if (maskFilter->asABlur(&blurRec)) { + SkMaskFilterBase::BlurRec blurRec; + if (as_MFB(maskFilter)->asABlur(&blurRec)) { Json::Value blur(Json::objectValue); blur[SKDEBUGCANVAS_ATTRIBUTE_SIGMA] = Json::Value(blurRec.fSigma); switch (blurRec.fStyle) { |