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 /src/core/SkMaskFilterBase.h | |
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>
Diffstat (limited to 'src/core/SkMaskFilterBase.h')
-rw-r--r-- | src/core/SkMaskFilterBase.h | 251 |
1 files changed, 251 insertions, 0 deletions
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 |