/*
|
* 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 "SkNoncopyable.h"
|
#include "SkPaint.h"
|
#include "SkStrokeRec.h"
|
|
class GrClip;
|
struct GrFPArgs;
|
class GrFragmentProcessor;
|
class GrPaint;
|
class GrRecordingContext;
|
class GrRenderTarget;
|
class GrRenderTargetContext;
|
class GrResourceProvider;
|
class GrShape;
|
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 = 0;
|
|
#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
|
* 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 GrShape&,
|
const SkIRect& devSpaceShapeBounds,
|
const SkIRect& clipBounds,
|
const SkMatrix& ctm,
|
SkIRect* 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(GrRecordingContext*,
|
GrRenderTargetContext*,
|
GrPaint&& paint,
|
const GrClip&,
|
const SkMatrix& viewMatrix,
|
const GrShape& shape) 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(GrRecordingContext*,
|
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;
|
};
|
/**
|
* 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
|