xref: /aosp_15_r20/external/skia/src/core/SkImageFilter_Base.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2019 Google LLC
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 SkImageFilter_Base_DEFINED
9 #define SkImageFilter_Base_DEFINED
10 
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkImageFilter.h"
13 #include "include/core/SkImageInfo.h"
14 #include "include/private/base/SkTArray.h"
15 #include "include/private/base/SkTemplates.h"
16 
17 #include "src/core/SkImageFilterTypes.h"
18 
19 #include <optional>
20 
21 // True base class that all SkImageFilter implementations need to extend from. This provides the
22 // actual API surface that Skia will use to compute the filtered images.
23 class SkImageFilter_Base : public SkImageFilter {
24 public:
25     /**
26      *  Request a new filtered image to be created from the src image. The returned skif::Image
27      *  provides both the pixel data and the origin point that it should be drawn at, relative to
28      *  the layer space defined by the provided context.
29      *
30      *  If the result image cannot be created, or the result would be transparent black, returns
31      *  a skif::Image that has a null special image, in which its origin should be ignored.
32      *
33      *  TODO: Right now the imagefilters sometimes return empty result bitmaps/
34      *        specialimages. That doesn't seem quite right.
35      */
36     skif::FilterResult filterImage(const skif::Context& context) const;
37 
38     /**
39      * Create a filtered version of the 'src' image using this filter. This is basically a wrapper
40      * around filterImage that prepares the skif::Context to filter the 'src' image directly,
41      * for implementing the SkImages::MakeWithFilter API calls.
42      */
43     sk_sp<SkImage> makeImageWithFilter(sk_sp<skif::Backend> backend,
44                                        sk_sp<SkImage> src,
45                                        const SkIRect& subset,
46                                        const SkIRect& clipBounds,
47                                        SkIRect* outSubset,
48                                        SkIPoint* offset) const;
49 
50     /**
51      *  Calculate the smallest-possible required layer bounds that would provide sufficient
52      *  information to correctly compute the image filter for every pixel in the desired output
53      *  bounds. The 'desiredOutput' is intended to represent either the root render target bounds,
54      *  or the device-space bounds of the current clip. If the bounds of the content that will be
55      *  drawn into the layer is known, 'knownContentBounds' should be provided, since it can be
56      *  used to restrict the size of the layer if the image filter DAG does not affect transparent
57      *  black.
58      *
59      *  The returned rect is in the layer space defined by 'mapping', so it directly represents
60      *  the size and location of the SkDevice created to rasterize the content prior to invoking the
61      *  image filter (assuming its CTM and basis matrix are configured to match 'mapping').
62      *
63      *  While this operation transforms an device-space output bounds to a layer-space input bounds,
64      *  it is not necessarily the inverse of getOutputBounds(). For instance, a blur needs to have
65      *  an outset margin when reading pixels at the edge (to satisfy its kernel), thus it expands
66      *  its required input rect to include every pixel that contributes to the desired output rect.
67 
68      *  @param mapping       The coordinate space mapping that defines both the transformation
69      *                       between local and layer, and layer to root device space, that will be
70      *                       used when the filter is later invoked.
71      *  @param desiredOutput The desired output boundary that needs to be covered by the filter's
72      *                       output (assuming that the filter is then invoked with a suitable input)
73      *  @param knownContentBounds
74      *                       Optional, the known layer-space bounds of the non-transparent content
75      *                       that would be rasterized in the source input image. Assumes unbounded
76      *                       content when not provided.
77      *
78      * @return The layer-space bounding box to use for an SkDevice when drawing the source image.
79      */
80     skif::LayerSpace<SkIRect> getInputBounds(
81             const skif::Mapping& mapping,
82             const skif::DeviceSpace<SkIRect>& desiredOutput,
83             std::optional<skif::ParameterSpace<SkRect>> knownContentBounds) const;
84 
85     /**
86      *  Calculate the device-space bounds of the output of this filter DAG, if it were to process
87      *  an image layer covering the 'contentBounds'. The 'mapping' defines how the content will be
88      *  transformed to layer space when it is drawn, and how the output filter image is then
89      *  transformed to the final device space (i.e. it specifies the mapping between the root device
90      *  space and the parameter space of the initially provided content).
91      *
92      *  While this operation transforms a parameter-space input bounds to an device-space output
93      *  bounds, it is not necessarily the inverse of getInputBounds(). For instance, a blur needs to
94      *  have an outset margin when reading pixels at the edge (to satisfy its kernel), so it will
95      *  generate a result larger than its input (so that the blur is visible) and, thus, expands its
96      *  output to include every pixel that it will touch.
97      *
98      *  If the returned optional does not have a value, the caller should interpret this to mean
99      *  that the output of the image filter will fill the entirety of whatever clipped device it's
100      *  drawn into.
101      *
102      *  @param mapping       The coordinate space mapping that defines both the transformation
103      *                       between local and layer, and layer to root device space, that will be
104      *                       used when the filter is later invoked.
105      *  @param contentBounds The local-space bounds of the non-transparent content that would be
106      *                       drawn into the source image prior to filtering with this DAG,  i.e.
107      *                       the same as 'knownContentBounds' in getInputBounds().
108      *
109      *  @return The root device-space bounding box of the filtered image, were it applied to
110      *          content contained by 'contentBounds' and then drawn with 'mapping' to the root
111      *          device (w/o any additional clipping).
112      */
113     std::optional<skif::DeviceSpace<SkIRect>> getOutputBounds(
114             const skif::Mapping& mapping,
115             const skif::ParameterSpace<SkRect>& contentBounds) const;
116 
117     // Returns true if this image filter graph transforms a source transparent black pixel to a
118     // color other than transparent black.
119     bool affectsTransparentBlack() const;
120 
121     // Returns true if this image filter graph references the Context's source image.
usesSource()122     bool usesSource() const { return fUsesSrcInput; }
123 
124     /**
125      *  This call returns the maximum "kind" of CTM for a filter and all of its (non-null) inputs.
126      */
127     using MatrixCapability = skif::MatrixCapability;
128     MatrixCapability getCTMCapability() const;
129 
uniqueID()130     uint32_t uniqueID() const { return fUniqueID; }
131 
GetFlattenableType()132     static SkFlattenable::Type GetFlattenableType() {
133         return kSkImageFilter_Type;
134     }
135 
getFlattenableType()136     SkFlattenable::Type getFlattenableType() const override {
137         return kSkImageFilter_Type;
138     }
139 
140     // TODO: CreateProcs for now-removed image filter subclasses need to hook into
141     // SK_IMAGEFILTER_UNFLATTEN_COMMON, so this temporarily exposes it for the case where there's a
142     // single input filter, and can be removed when the legacy CreateProcs are deleted.
143     static std::pair<sk_sp<SkImageFilter>, std::optional<SkRect>>
144     Unflatten(SkReadBuffer& buffer);
145 
146 protected:
147     class Common {
148     public:
149         /**
150          *  Attempt to unflatten the expected number of input filters.
151          *  If any number of input filters is valid, pass -1.
152          *  If this fails (i.e. corrupt buffer or contents) then return false and common will
153          *  be left uninitialized.
154          *  If this returns true, then inputCount() is the number of found input filters, each
155          *  of which may be NULL or a valid imagefilter.
156          */
157         bool unflatten(SkReadBuffer&, int expectedInputs);
158 
cropRect()159         std::optional<SkRect> cropRect() const { return fCropRect; }
160 
inputCount()161         int inputCount() const { return fInputs.size(); }
inputs()162         sk_sp<SkImageFilter>* inputs() { return fInputs.begin(); }
163 
getInput(int index)164         sk_sp<SkImageFilter> getInput(int index) { return fInputs[index]; }
165 
166     private:
167         // Old SKPs (version less than kRemoveDeprecatedCropRect may have this set).
168         std::optional<SkRect> fCropRect;
169 
170         // most filters accept at most 2 input-filters
171         skia_private::STArray<2, sk_sp<SkImageFilter>, true> fInputs;
172     };
173 
174     SkImageFilter_Base(sk_sp<SkImageFilter> const* inputs, int inputCount,
175                        std::optional<bool> usesSrc = {});
176 
177     ~SkImageFilter_Base() override;
178 
179     void flatten(SkWriteBuffer&) const override;
180 
181     // Helper function to calculate the required input/output of a specific child filter,
182     // automatically handling if the child filter is null.
183     skif::LayerSpace<SkIRect> getChildInputLayerBounds(
184             int index,
185             const skif::Mapping& mapping,
186             const skif::LayerSpace<SkIRect>& desiredOutput,
187             std::optional<skif::LayerSpace<SkIRect>> contentBounds) const;
188     std::optional<skif::LayerSpace<SkIRect>> getChildOutputLayerBounds(
189             int index,
190             const skif::Mapping& mapping,
191             std::optional<skif::LayerSpace<SkIRect>> contentBounds) const;
192 
193     // Helper function for recursing through the filter DAG. It automatically evaluates the input
194     // image filter at 'index' using the given context. If the input image filter is null, it
195     // returns the context's dynamic source image.
196     //
197     // When an image filter requires a different output than what is requested in it's own Context
198     // passed to onFilterImage(), it should explicitly pass in an updated Context via
199     // `withNewDesiredOutput`.
200     skif::FilterResult getChildOutput(int index, const skif::Context& ctx) const;
201 
202 private:
203     friend class SkImageFilter;
204     // For PurgeCache()
205     friend class SkGraphics;
206 
207     static void PurgeCache();
208 
209     // Configuration points for the filter implementation, marked private since they should not
210     // need to be invoked by the subclasses. These refer to the node's specific behavior and are
211     // not responsible for aggregating the behavior of the entire filter DAG.
212 
213     /**
214      *  Return true (and returns a ref'd colorfilter) if this node in the DAG is just a colorfilter
215      *  w/o cropping constraints.
216      */
onIsColorFilterNode(SkColorFilter **)217     virtual bool onIsColorFilterNode(SkColorFilter** /*filterPtr*/) const { return false; }
218 
219     /**
220      *  Return the most complex matrix type this filter can support (mapping from its parameter
221      *  space to a layer space). If this returns anything less than kComplex, the filter only needs
222      *  to worry about mapping from parameter to layer using a matrix that is constrained in that
223      *  way (eg, scale+translate).
224      */
onGetCTMCapability()225     virtual MatrixCapability onGetCTMCapability() const {
226         return MatrixCapability::kScaleTranslate;
227     }
228 
229     /**
230      *  Return true if this filter would transform transparent black pixels to a color other than
231      *  transparent black. When false, optimizations can be taken to discard regions known to be
232      *  transparent black and thus process fewer pixels.
233      */
onAffectsTransparentBlack()234     virtual bool onAffectsTransparentBlack() const { return false; }
235 
236     /**
237      * Return true if `affectsTransparentBlack()` should only be based on
238      * `onAffectsTransparentBlack()` and ignore the transparency behavior of child input filters.
239      */
ignoreInputsAffectsTransparentBlack()240     virtual bool ignoreInputsAffectsTransparentBlack() const { return false; }
241 
242     /**
243      *  This is the virtual which should be overridden by the derived class to perform image
244      *  filtering. Subclasses are responsible for recursing to their input filters, although the
245      *  filterInput() function is provided to handle all necessary details of this.
246      *
247      *  If the image cannot be created (either because of an error or if the result would be empty
248      *  because it was clipped out), this should return a filtered Image with a null SkSpecialImage.
249      *  In these situations, callers that do not affect transparent black can end early, since the
250      *  "transparent" implicit image would be unchanged. Callers that affect transparent black need
251      *  to safely handle these null and empty images and return an image filling the context's clip
252      *  bounds as if its input filtered image were transparent black.
253      */
254     virtual skif::FilterResult onFilterImage(const skif::Context& context) const = 0;
255 
256     /**
257      *  Calculates the necessary input layer size in order for the final output of the filter to
258      *  cover the desired output bounds. The provided 'desiredOutput' represents the requested
259      *  input bounds for this node's parent filter node, i.e. this function answers "what does this
260      *  node require for input in order to satisfy (as its own output), the input needs of its
261      *  parent?".
262      *
263      *  'contentBounds' represents the bounds of the non-transparent content that will form the
264      *  source image when the filter graph is invoked. If it's not instantiated, implementations
265      *  should treat the content as extending infinitely. However, since the output is known and
266      *  bounded, implementations should still be able to determine a finite input bounds under these
267      *  circumstances.
268      *
269      *  Unlike the public getInputBounds(), all internal bounds calculations are done in the shared
270      *  layer space defined by 'mapping'.
271      */
272     virtual skif::LayerSpace<SkIRect> onGetInputLayerBounds(
273             const skif::Mapping& mapping,
274             const skif::LayerSpace<SkIRect>& desiredOutput,
275             std::optional<skif::LayerSpace<SkIRect>> contentBounds) const = 0;
276 
277     /**
278      *  Calculates the output bounds that this filter node would touch when processing an input
279      *  sized to 'contentBounds'. This function is responsible for recursing to its child image
280      *  filters and accounting for what they output. It is up to the filter to determine how to
281      *  aggregate the outputs of its children.
282      *
283      *  'contentBounds' represents the bounds of the non-transparent content that will form the
284      *  source image when the filter graph is invoked. If it's not instantiated, implementations
285      *  should treat the content as extending infinitely. However, since the output is known and
286      *  bounded, implementations should still be able to determine a finite input bounds under these
287      *  circumstances.
288      *
289      *  If the non-transparent output extends infinitely, subclasses should return an uninstantiated
290      *  optional. Implementations must also be able to handle when their children return such
291      *  unbounded "outputs" and react accordingly.
292      *
293      *  Unlike the public getOutputBounds(), all internal bounds calculations are done in the
294      *  shared layer space defined by 'mapping'.
295      */
296     // TODO (michaelludwig) - When layerMatrix = I, this function could be used to implement
297     // onComputeFastBounds() instead of making filters implement the essentially the same calcs x2
298     virtual std::optional<skif::LayerSpace<SkIRect>> onGetOutputLayerBounds(
299             const skif::Mapping& mapping,
300             std::optional<skif::LayerSpace<SkIRect>> contentBounds) const = 0;
301 
302     skia_private::AutoSTArray<2, sk_sp<SkImageFilter>> fInputs;
303 
304     bool fUsesSrcInput;
305     uint32_t fUniqueID; // Globally unique
306 
307     using INHERITED = SkImageFilter;
308 };
309 
as_IFB(SkImageFilter * filter)310 static inline SkImageFilter_Base* as_IFB(SkImageFilter* filter) {
311     return static_cast<SkImageFilter_Base*>(filter);
312 }
313 
as_IFB(const sk_sp<SkImageFilter> & filter)314 static inline SkImageFilter_Base* as_IFB(const sk_sp<SkImageFilter>& filter) {
315     return static_cast<SkImageFilter_Base*>(filter.get());
316 }
317 
as_IFB(const SkImageFilter * filter)318 static inline const SkImageFilter_Base* as_IFB(const SkImageFilter* filter) {
319     return static_cast<const SkImageFilter_Base*>(filter);
320 }
321 
322 /**
323  *  Helper to unflatten the common data, and return nullptr if we fail.
324  */
325 #define SK_IMAGEFILTER_UNFLATTEN_COMMON(localVar, expectedCount)    \
326     Common localVar;                                                \
327     do {                                                            \
328         if (!localVar.unflatten(buffer, expectedCount)) {           \
329             return nullptr;                                         \
330         }                                                           \
331     } while (0)
332 
333 
334 /**
335  * All image filter implementations defined for the include/effects/SkImageFilters.h factories
336  * are entirely encapsulated within their own CPP files. SkFlattenable deserialization needs a hook
337  * into these types, so their registration functions are exposed here.
338  */
339 void SkRegisterBlendImageFilterFlattenable();
340 void SkRegisterBlurImageFilterFlattenable();
341 void SkRegisterColorFilterImageFilterFlattenable();
342 void SkRegisterComposeImageFilterFlattenable();
343 void SkRegisterCropImageFilterFlattenable();
344 void SkRegisterDisplacementMapImageFilterFlattenable();
345 void SkRegisterImageImageFilterFlattenable();
346 void SkRegisterLightingImageFilterFlattenables();
347 void SkRegisterMagnifierImageFilterFlattenable();
348 void SkRegisterMatrixConvolutionImageFilterFlattenable();
349 void SkRegisterMatrixTransformImageFilterFlattenable();
350 void SkRegisterMergeImageFilterFlattenable();
351 void SkRegisterMorphologyImageFilterFlattenables();
352 void SkRegisterPictureImageFilterFlattenable();
353 void SkRegisterRuntimeImageFilterFlattenable();
354 void SkRegisterShaderImageFilterFlattenable();
355 
356 // TODO(michaelludwig): These filters no longer have dedicated implementations, so their
357 // SkFlattenable create procs only need to remain to support old SkPictures.
358 void SkRegisterLegacyDropShadowImageFilterFlattenable();
359 
360 #endif // SkImageFilter_Base_DEFINED
361