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