blob: 53d5ec959c013a9c04c85ff4a61a528695809ae2 [file] [log] [blame]
Mike Reed80747ef2018-01-23 15:29:32 -05001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkMaskFilterBase_DEFINED
9#define SkMaskFilterBase_DEFINED
10
11#include "SkBlurTypes.h"
12#include "SkFlattenable.h"
13#include "SkMask.h"
14#include "SkMaskFilter.h"
Ben Wagnerd5148e32018-07-16 17:44:06 -040015#include "SkNoncopyable.h"
Mike Reed80747ef2018-01-23 15:29:32 -050016#include "SkPaint.h"
17#include "SkStrokeRec.h"
18
19class GrClip;
20class GrContext;
21struct GrFPArgs;
Mike Reed80747ef2018-01-23 15:29:32 -050022class GrFragmentProcessor;
Robert Phillips20390c32018-08-17 11:01:03 -040023class GrPaint;
Mike Reed80747ef2018-01-23 15:29:32 -050024class GrRenderTarget;
Robert Phillips20390c32018-08-17 11:01:03 -040025class GrRenderTargetContext;
Mike Reed80747ef2018-01-23 15:29:32 -050026class GrResourceProvider;
27class GrTexture;
28class GrTextureProxy;
Robert Phillips20390c32018-08-17 11:01:03 -040029
Mike Reed80747ef2018-01-23 15:29:32 -050030class SkBitmap;
31class SkBlitter;
32class SkCachedData;
33class SkMatrix;
34class SkPath;
35class SkRasterClip;
36class SkRRect;
37
38class SkMaskFilterBase : public SkMaskFilter {
39public:
40 /** Returns the format of the resulting mask that this subclass will return
41 when its filterMask() method is called.
42 */
43 virtual SkMask::Format getFormat() const = 0;
44
45 /** Create a new mask by filter the src mask.
46 If src.fImage == null, then do not allocate or create the dst image
47 but do fill out the other fields in dstMask.
48 If you do allocate a dst image, use SkMask::AllocImage()
49 If this returns false, dst mask is ignored.
50 @param dst the result of the filter. If src.fImage == null, dst should not allocate its image
51 @param src the original image to be filtered.
52 @param matrix the CTM
53 @param margin if not null, return the buffer dx/dy need when calculating the effect. Used when
54 drawing a clipped object to know how much larger to allocate the src before
55 applying the filter. If returning false, ignore this parameter.
56 @return true if the dst mask was correctly created.
57 */
58 virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
Ben Wagner275df2e2018-04-25 15:27:40 -040059 SkIPoint* margin) const = 0;
Mike Reed80747ef2018-01-23 15:29:32 -050060
61#if SK_SUPPORT_GPU
62 /**
63 * Returns a processor if the filter can be expressed a single-pass GrProcessor without
64 * requiring an explicit input mask. Per-pixel, the effect receives the incoming mask's
65 * coverage as the input color and outputs the filtered covereage value. This means that each
66 * pixel's filtered coverage must only depend on the unfiltered mask value for that pixel and
67 * not on surrounding values.
68 */
69 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs& args) const;
70
71 /**
72 * Returns true iff asFragmentProcessor() will return a processor
73 */
74 bool hasFragmentProcessor() const;
75
76 /**
77 * If asFragmentProcessor() fails the filter may be implemented on the GPU by a subclass
78 * overriding filterMaskGPU (declared below). That code path requires constructing a
79 * src mask as input. Since that is a potentially expensive operation, the subclass must also
80 * override this function to indicate whether filterTextureMaskGPU would succeeed if the mask
81 * were to be created.
82 *
83 * 'maskRect' returns the device space portion of the mask that the filter needs. The mask
84 * passed into 'filterMaskGPU' should have the same extent as 'maskRect' but be
85 * translated to the upper-left corner of the mask (i.e., (maskRect.fLeft, maskRect.fTop)
86 * appears at (0, 0) in the mask).
87 *
88 * Logically, how this works is:
89 * canFilterMaskGPU is called
90 * if (it returns true)
91 * the returned mask rect is used for quick rejecting
92 * either directFilterMaskGPU or directFilterRRectMaskGPU is then called
93 * if (neither of them handle the blur)
94 * the mask rect is used to generate the mask
95 * filterMaskGPU is called to filter the mask
96 *
97 * TODO: this should work as:
98 * if (canFilterMaskGPU(devShape, ...)) // rect, rrect, drrect, path
99 * filterMaskGPU(devShape, ...)
100 * this would hide the RRect special case and the mask generation
101 */
102 virtual bool canFilterMaskGPU(const SkRRect& devRRect,
103 const SkIRect& clipBounds,
104 const SkMatrix& ctm,
105 SkRect* maskRect) const;
106
107 /**
108 * Try to directly render the mask filter into the target. Returns true if drawing was
109 * successful. If false is returned then paint is unmodified.
110 */
111 virtual bool directFilterMaskGPU(GrContext*,
Robert Phillips20390c32018-08-17 11:01:03 -0400112 GrRenderTargetContext*,
Mike Reed80747ef2018-01-23 15:29:32 -0500113 GrPaint&& paint,
114 const GrClip&,
115 const SkMatrix& viewMatrix,
116 const SkStrokeRec& strokeRec,
117 const SkPath& path) const;
118 /**
119 * Try to directly render a rounded rect mask filter into the target. Returns
120 * true if drawing was successful. If false is returned then paint is unmodified.
121 */
122 virtual bool directFilterRRectMaskGPU(GrContext*,
Robert Phillips20390c32018-08-17 11:01:03 -0400123 GrRenderTargetContext*,
124 GrPaint&&,
Mike Reed80747ef2018-01-23 15:29:32 -0500125 const GrClip&,
126 const SkMatrix& viewMatrix,
Robert Phillips20390c32018-08-17 11:01:03 -0400127 const SkStrokeRec&,
Mike Reed80747ef2018-01-23 15:29:32 -0500128 const SkRRect& rrect,
129 const SkRRect& devRRect) const;
130
131 /**
132 * This function is used to implement filters that require an explicit src mask. It should only
133 * be called if canFilterMaskGPU returned true and the maskRect param should be the output from
134 * that call.
135 * Implementations are free to get the GrContext from the src texture in order to create
136 * additional textures and perform multiple passes.
137 */
138 virtual sk_sp<GrTextureProxy> filterMaskGPU(GrContext*,
139 sk_sp<GrTextureProxy> srcProxy,
140 const SkMatrix& ctm,
141 const SkIRect& maskRect) const;
142#endif
143
144 /**
145 * The fast bounds function is used to enable the paint to be culled early
146 * in the drawing pipeline. This function accepts the current bounds of the
147 * paint as its src param and the filter adjust those bounds using its
148 * current mask and returns the result using the dest param. Callers are
149 * allowed to provide the same struct for both src and dest so each
150 * implementation must accomodate that behavior.
151 *
152 * The default impl calls filterMask with the src mask having no image,
153 * but subclasses may override this if they can compute the rect faster.
154 */
155 virtual void computeFastBounds(const SkRect& src, SkRect* dest) const;
156
157 struct BlurRec {
158 SkScalar fSigma;
159 SkBlurStyle fStyle;
Mike Reed80747ef2018-01-23 15:29:32 -0500160 };
161 /**
162 * If this filter can be represented by a BlurRec, return true and (if not null) fill in the
163 * provided BlurRec parameter. If this effect cannot be represented as a BlurRec, return false
164 * and ignore the BlurRec parameter.
165 */
166 virtual bool asABlur(BlurRec*) const;
167
168protected:
169 SkMaskFilterBase() {}
170
171#if SK_SUPPORT_GPU
172 virtual std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs&) const;
173 virtual bool onHasFragmentProcessor() const;
174#endif
175
176 enum FilterReturn {
177 kFalse_FilterReturn,
178 kTrue_FilterReturn,
179 kUnimplemented_FilterReturn
180 };
181
182 class NinePatch : ::SkNoncopyable {
183 public:
184 NinePatch() : fCache(nullptr) { }
185 ~NinePatch();
186
187 SkMask fMask; // fBounds must have [0,0] in its top-left
188 SkIRect fOuterRect; // width/height must be >= fMask.fBounds'
189 SkIPoint fCenter; // identifies center row/col for stretching
190 SkCachedData* fCache;
191 };
192
193 /**
194 * Override if your subclass can filter a rect, and return the answer as
195 * a ninepatch mask to be stretched over the returned outerRect. On success
196 * return kTrue_FilterReturn. On failure (e.g. out of memory) return
197 * kFalse_FilterReturn. If the normal filterMask() entry-point should be
198 * called (the default) return kUnimplemented_FilterReturn.
199 *
200 * By convention, the caller will take the center rol/col from the returned
201 * mask as the slice it can replicate horizontally and vertically as we
202 * stretch the mask to fit inside outerRect. It is an error for outerRect
203 * to be smaller than the mask's bounds. This would imply that the width
204 * and height of the mask should be odd. This is not required, just that
205 * the caller will call mask.fBounds.centerX() and centerY() to find the
206 * strips that will be replicated.
207 */
208 virtual FilterReturn filterRectsToNine(const SkRect[], int count,
209 const SkMatrix&,
210 const SkIRect& clipBounds,
211 NinePatch*) const;
212 /**
213 * Similar to filterRectsToNine, except it performs the work on a round rect.
214 */
215 virtual FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&,
216 const SkIRect& clipBounds,
217 NinePatch*) const;
218
219private:
220 friend class SkDraw;
221
222 /** Helper method that, given a path in device space, will rasterize it into a kA8_Format mask
223 and then call filterMask(). If this returns true, the specified blitter will be called
224 to render that mask. Returns false if filterMask() returned false.
225 This method is not exported to java.
226 */
227 bool filterPath(const SkPath& devPath, const SkMatrix& ctm, const SkRasterClip&, SkBlitter*,
228 SkStrokeRec::InitStyle) const;
229
230 /** Helper method that, given a roundRect in device space, will rasterize it into a kA8_Format
231 mask and then call filterMask(). If this returns true, the specified blitter will be called
232 to render that mask. Returns false if filterMask() returned false.
233 */
234 bool filterRRect(const SkRRect& devRRect, const SkMatrix& ctm, const SkRasterClip&,
235 SkBlitter*) const;
236
237 typedef SkFlattenable INHERITED;
238};
239
240inline SkMaskFilterBase* as_MFB(SkMaskFilter* mf) {
241 return static_cast<SkMaskFilterBase*>(mf);
242}
243
244inline const SkMaskFilterBase* as_MFB(const SkMaskFilter* mf) {
245 return static_cast<const SkMaskFilterBase*>(mf);
246}
247
248inline const SkMaskFilterBase* as_MFB(const sk_sp<SkMaskFilter>& mf) {
249 return static_cast<SkMaskFilterBase*>(mf.get());
250}
251
252#endif