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