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/SkTArray.h"
15
16#include "src/core/SkImageFilterTypes.h"
17
18class GrFragmentProcessor;
19class GrRecordingContext;
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.
23class SkImageFilter_Base : public SkImageFilter {
24public:
25 SK_USE_FLUENT_IMAGE_FILTER_TYPES_IN_CLASS
26
27 // DEPRECATED - Use skif::Context directly.
28 using Context = skif::Context;
29
30 /**
31 * Request a new filtered image to be created from the src image. The returned skif::Image
32 * provides both the pixel data and the origin point that it should be drawn at, relative to
33 * the layer space defined by the provided context.
34 *
35 * If the result image cannot be created, or the result would be transparent black, returns
36 * a skif::Image that has a null special image, in which its origin should be ignored.
37 *
38 * TODO: Right now the imagefilters sometimes return empty result bitmaps/
39 * specialimages. That doesn't seem quite right.
40 */
41 skif::FilterResult<For::kOutput> filterImage(const skif::Context& context) const;
42
43 /**
44 * Calculate the smallest-possible required layer bounds that would provide sufficient
45 * information to correctly compute the image filter for every pixel in the desired output
46 * bounds. The 'desiredOutput' is intended to represent either the root render target bounds,
47 * or the device-space bounds of the current clip. If the bounds of the content that will be
48 * drawn into the layer is known, 'knownContentBounds' should be provided, since it can be
49 * used to restrict the size of the layer if the image filter DAG does not affect transparent
50 * black.
51 *
52 * The returned rect is in the layer space defined by 'mapping', so it directly represents
53 * the size and location of the SkDevice created to rasterize the content prior to invoking the
54 * image filter (assuming its CTM and basis matrix are configured to match 'mapping').
55 *
56 * While this operation transforms an device-space output bounds to a layer-space input bounds,
57 * it is not necessarily the inverse of getOutputBounds(). For instance, a blur needs to have
58 * an outset margin when reading pixels at the edge (to satisfy its kernel), thus it expands
59 * its required input rect to include every pixel that contributes to the desired output rect.
60
61 * @param mapping The coordinate space mapping that defines both the transformation
62 * between local and layer, and layer to root device space, that will be
63 * used when the filter is later invoked.
64 * @param desiredOutput The desired output boundary that needs to be covered by the filter's
65 * output (assuming that the filter is then invoked with a suitable input)
66 * @param knownContentBounds
67 * Optional, the known layer-space bounds of the non-transparent content
68 * that would be rasterized in the source input image.
69 *
70 * @return The layer-space bounding box to use for an SkDevice when drawing the source image.
71 */
72 skif::LayerSpace<SkIRect> getInputBounds(
73 const skif::Mapping& mapping, const skif::DeviceSpace<SkRect>& desiredOutput,
74 const skif::ParameterSpace<SkRect>* knownContentBounds) const;
75
76 /**
77 * Calculate the device-space bounds of the output of this filter DAG, if it were to process
78 * an image layer covering the 'contentBounds'. The 'mapping' defines how the content will be
79 * transformed to layer space when it is drawn, and how the output filter image is then
80 * transformed to the final device space (i.e. it specifies the mapping between the root device
81 * space and the parameter space of the initially provided content).
82 *
83 * While this operation transforms a parameter-space input bounds to an device-space output
84 * bounds, it is not necessarily the inverse of getInputBounds(). For instance, a blur needs to
85 * have an outset margin when reading pixels at the edge (to satisfy its kernel), so it will
86 * generate a result larger than its input (so that the blur is visible) and, thus, expands its
87 * output to include every pixel that it will touch.
88 *
89 * @param mapping The coordinate space mapping that defines both the transformation
90 * between local and layer, and layer to root device space, that will be
91 * used when the filter is later invoked.
92 * @param contentBounds The local-space bounds of the non-transparent content that would be
93 * drawn into the source image prior to filtering with this DAG, i.e.
94 * the same as 'knownContentBounds' in getInputBounds().
95 *
96 * @return The root device-space bounding box of the filtered image, were it applied to
97 * content contained by 'contentBounds' and then drawn with 'mapping' to the root
98 * device (w/o any additional clipping).
99 */
100 skif::DeviceSpace<SkIRect> getOutputBounds(
101 const skif::Mapping& mapping, const skif::ParameterSpace<SkRect>& contentBounds) const;
102
103 /**
104 * Returns whether any edges of the crop rect have been set. The crop
105 * rect is set at construction time, and determines which pixels from the
106 * input image will be processed, and which pixels in the output image will be allowed.
107 * The size of the crop rect should be
108 * used as the size of the destination image. The origin of this rect
109 * should be used to offset access to the input images, and should also
110 * be added to the "offset" parameter in onFilterImage.
111 *
112 * DEPRECATED - Remove once cropping is handled by a separate filter
113 */
114 bool cropRectIsSet() const { return fCropRect.flags() != 0x0; }
115
116 // DEPRECATED - Remove once cropping is handled by a separate filter
117 CropRect getCropRect() const { return fCropRect; }
118
119 // Expose isolated node bounds behavior for SampleImageFilterDAG and debugging
120 SkIRect filterNodeBounds(const SkIRect& srcRect, const SkMatrix& ctm,
121 MapDirection dir, const SkIRect* inputRect) const {
122 return this->onFilterNodeBounds(srcRect, ctm, dir, inputRect);
123 }
124
125 /**
126 * ImageFilters can natively handle scaling and translate components in the CTM. Only some of
127 * them can handle affine (or more complex) matrices. This call returns true iff the filter
128 * and all of its (non-null) inputs can handle these more complex matrices.
129 */
130 bool canHandleComplexCTM() const;
131
132 /**
133 * Return an image filter representing this filter applied with the given ctm. This will modify
134 * the DAG as needed if this filter does not support complex CTMs and 'ctm' is not simple. The
135 * ctm matrix will be decomposed such that ctm = A*B; B will be incorporated directly into the
136 * DAG and A must be the ctm set on the context passed to filterImage(). 'remainder' will be set
137 * to A.
138 *
139 * If this filter supports complex ctms, or 'ctm' is not complex, then A = ctm and B = I. When
140 * the filter does not support complex ctms, and the ctm is complex, then A represents the
141 * extracted simple portion of the ctm, and the complex portion is baked into a new DAG using a
142 * matrix filter.
143 *
144 * This will never return null.
145 *
146 * DEPRECATED - Should draw the results of filterImage() directly with the remainder matrix.
147 */
148 sk_sp<SkImageFilter> applyCTM(const SkMatrix& ctm, SkMatrix* remainder) const;
149
150 uint32_t uniqueID() const { return fUniqueID; }
151
152protected:
153 class Common {
154 public:
155 /**
156 * Attempt to unflatten the cropRect and the expected number of input filters.
157 * If any number of input filters is valid, pass -1.
158 * If this fails (i.e. corrupt buffer or contents) then return false and common will
159 * be left uninitialized.
160 * If this returns true, then inputCount() is the number of found input filters, each
161 * of which may be NULL or a valid imagefilter.
162 */
163 bool unflatten(SkReadBuffer&, int expectedInputs);
164
165 const CropRect& cropRect() const { return fCropRect; }
166 int inputCount() const { return fInputs.count(); }
167 sk_sp<SkImageFilter>* inputs() { return fInputs.begin(); }
168
169 sk_sp<SkImageFilter> getInput(int index) { return fInputs[index]; }
170
171 private:
172 CropRect fCropRect;
173 // most filters accept at most 2 input-filters
174 SkSTArray<2, sk_sp<SkImageFilter>, true> fInputs;
175 };
176
177 // Whether or not to recurse to child input filters for certain operations that walk the DAG.
178 enum class VisitChildren : bool {
179 kNo = false,
180 kYes = true
181 };
182
183 SkImageFilter_Base(sk_sp<SkImageFilter> const* inputs, int inputCount,
184 const CropRect* cropRect);
185
186 ~SkImageFilter_Base() override;
187
188 void flatten(SkWriteBuffer&) const override;
189
190 // DEPRECATED - Use the private context-only variant
191 virtual sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const = 0;
192
193 // DEPRECATED - Override onGetOutputLayerBounds and onGetInputLayerBounds instead. The
194 // node-specific and aggregation functions are no longer separated in the current API. A helper
195 // function is provided to do the default recursion for the common filter case.
196 virtual SkIRect onFilterBounds(const SkIRect&, const SkMatrix& ctm,
197 MapDirection, const SkIRect* inputRect) const;
198 virtual SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix& ctm,
199 MapDirection, const SkIRect* inputRect) const;
200
201 // DEPRECRATED - Call the Context-only getInputFilteredImage()
202 sk_sp<SkSpecialImage> filterInput(int index, const Context& ctx, SkIPoint* offset) const {
203 return this->getInputFilteredImage(index, ctx).imageAndOffset(offset);
204 }
205
206 // Helper function to visit each of this filter's child filters and call their
207 // onGetInputLayerBounds with the provided 'desiredOutput' and 'contentBounds'. Automatically
208 // handles null input filters. Returns the union of all of the children's input bounds.
209 skif::LayerSpace<SkIRect> visitInputLayerBounds(
210 const skif::Mapping& mapping, const skif::LayerSpace<SkIRect>& desiredOutput,
211 const skif::LayerSpace<SkIRect>& contentBounds) const;
212 // Helper function to visit each of this filter's child filters and call their
213 // onGetOutputLayerBounds with the provided 'contentBounds'. Automatically handles null input
214 // filters.
215 skif::LayerSpace<SkIRect> visitOutputLayerBounds(
216 const skif::Mapping& mapping, const skif::LayerSpace<SkIRect>& contentBounds) const;
217
218 // Helper function to help with recursing through the filter DAG. It invokes filter processing
219 // set to null, it returns the dynamic source image on the Context instead.
220 //
221 // Implementations must handle cases when the input filter was unable to compute an image and
222 // the returned skif::Image has a null SkSpecialImage. If the filter affect transparent black
223 // should explicitly handle nullptr results and press on. In the error case this behavior will
224 // produce a better result than nothing and is necessary for the clipped out case.
225 skif::FilterResult<For::kInput> getInputFilteredImage(int index,
226 const skif::Context& context) const {
227 return this->filterInput<For::kInput>(index, context);
228 }
229 // Convenience that calls filterInput with index = 0 and the most specific usage.
230 skif::FilterResult<For::kInput0> getInputFilteredImage0(const skif::Context& context) const {
231 return this->filterInput<For::kInput0>(0, context);
232 }
233 // Convenience that calls filterInput with index = 1 and the most specific usage.
234 skif::FilterResult<For::kInput1> getInputFilteredImage1(const skif::Context& context) const {
235 return this->filterInput<For::kInput1>(1, context);
236 }
237
238 // DEPRECATED - Remove once cropping is handled by a separate filter
239 const CropRect* getCropRectIfSet() const {
240 return this->cropRectIsSet() ? &fCropRect : nullptr;
241 }
242
243 /** Given a "srcBounds" rect, computes destination bounds for this filter.
244 * "dstBounds" are computed by transforming the crop rect by the context's
245 * CTM, applying it to the initial bounds, and intersecting the result with
246 * the context's clip bounds. "srcBounds" (if non-null) are computed by
247 * intersecting the initial bounds with "dstBounds", to ensure that we never
248 * sample outside of the crop rect (this restriction may be relaxed in the
249 * future).
250 *
251 * DEPRECATED - Remove once cropping is handled by a separate filter, although it may be
252 * necessary to provide a similar convenience function to compute the output bounds given the
253 * images returned by filterInput().
254 */
255 bool applyCropRect(const Context&, const SkIRect& srcBounds, SkIRect* dstBounds) const;
256
257 /** A variant of the above call which takes the original source bitmap and
258 * source offset. If the resulting crop rect is not entirely contained by
259 * the source bitmap's bounds, it creates a new bitmap in "result" and
260 * pads the edges with transparent black. In that case, the srcOffset is
261 * modified to be the same as the bounds, since no further adjustment is
262 * needed by the caller. This version should only be used by filters
263 * which are not capable of processing a smaller source bitmap into a
264 * larger destination.
265 *
266 * DEPRECATED - Remove once cropping is handled by a separate filter.
267 */
268 sk_sp<SkSpecialImage> applyCropRectAndPad(const Context&, SkSpecialImage* src,
269 SkIPoint* srcOffset, SkIRect* bounds) const;
270
271 /**
272 * Creates a modified Context for use when recursing up the image filter DAG.
273 * The clip bounds are adjusted to accommodate any margins that this
274 * filter requires by calling this node's
275 * onFilterNodeBounds(..., kReverse_MapDirection).
276 */
277 // TODO (michaelludwig) - I don't think this is necessary to keep as protected. Other than the
278 // real use case in recursing through the DAG for filterInput(), it feels wrong for blur and
279 // other filters to need to call it.
280 Context mapContext(const Context& ctx) const;
281
282#if SK_SUPPORT_GPU
283 static sk_sp<SkSpecialImage> DrawWithFP(GrRecordingContext* context,
284 std::unique_ptr<GrFragmentProcessor> fp,
285 const SkIRect& bounds,
286 SkColorType colorType,
287 const SkColorSpace* colorSpace,
288 GrProtected isProtected = GrProtected::kNo);
289
290 /**
291 * Returns a version of the passed-in image (possibly the original), that is in a colorspace
292 * with the same gamut as the one from the OutputProperties. This allows filters that do many
293 * texture samples to guarantee that any color space conversion has happened before running.
294 */
295 static sk_sp<SkSpecialImage> ImageToColorSpace(SkSpecialImage* src,
296 SkColorType colorType,
297 SkColorSpace* colorSpace);
298#endif
299
300 // If 'srcBounds' will sample outside the border of 'originalSrcBounds' (i.e., the sample
301 // will wrap around to the other side) we must preserve the far side of the src along that
302 // axis (e.g., if we will sample beyond the left edge of the src, the right side must be
303 // preserved for the repeat sampling to work).
304 // DEPRECATED - Remove once cropping is handled by a separate filter, that can also handle all
305 // tile modes (including repeat) properly
306 static SkIRect DetermineRepeatedSrcBound(const SkIRect& srcBounds,
307 const SkIVector& filterOffset,
308 const SkISize& filterSize,
309 const SkIRect& originalSrcBounds);
310
311private:
312 friend class SkImageFilter;
313 // For PurgeCache()
314 friend class SkGraphics;
315
316 static void PurgeCache();
317
318 void init(sk_sp<SkImageFilter> const* inputs, int inputCount, const CropRect* cropRect);
319
320 // Configuration points for the filter implementation, marked private since they should not
321 // need to be invoked by the subclasses. These refer to the node's specific behavior and are
322 // not responsible for aggregating the behavior of the entire filter DAG.
323
324 /**
325 * Return true (and returns a ref'd colorfilter) if this node in the DAG is just a colorfilter
326 * w/o CropRect constraints.
327 */
328 virtual bool onIsColorFilterNode(SkColorFilter** /*filterPtr*/) const { return false; }
329
330 /**
331 * Return true if this filter can map from its parameter space to a layer space described by an
332 * arbitrary transformation matrix. If this returns false, the filter only needs to worry about
333 * mapping from parameter to layer using a scale+translate matrix.
334 */
335 virtual bool onCanHandleComplexCTM() const { return false; }
336
337 /**
338 * Return true if this filter would transform transparent black pixels to a color other than
339 * transparent black. When false, optimizations can be taken to discard regions known to be
340 * transparent black and thus process fewer pixels.
341 */
342 virtual bool affectsTransparentBlack() const { return false; }
343
344 /**
345 * This is the virtual which should be overridden by the derived class to perform image
346 * filtering. Subclasses are responsible for recursing to their input filters, although the
347 * getFilteredInputX() functions are provided to handle all necessary details of this. If the
348 * filter has a fixed number of inputs, the getFilterInput0() and getFilteredInput1() functions
349 * ensure the returned filtered Images have the most specific input usage.
350 *
351 * If the image cannot be created (either because of an error or if the result would be empty
352 * because it was clipped out), this should return a filtered Image with a null SkSpecialImage.
353 * In these situations, callers that do not affect transparent black can end early, since the
354 * "transparent" implicit image would be unchanged. Callers that affect transparent black need
355 * to safely handle these null and empty images and return an image filling the context's clip
356 * bounds as if its input filtered image were transparent black.
357 */
358 virtual skif::FilterResult<For::kOutput> onFilterImage(const skif::Context& context) const;
359
360 /**
361 * Calculates the necessary input layer size in order for the final output of the filter to
362 * cover the desired output bounds. The provided 'desiredOutput' represents the requested
363 * input bounds for this node's parent filter node, i.e. this function answers "what does this
364 * node require for input in order to satisfy (as its own output), the input needs of its
365 * parent?".
366 *
367 * If 'recurse' is true, this function is responsible for recursing to its child image filters
368 * and accounting for what they require to meet this filter's input requirements. It is up to
369 * the filter to determine how to aggregate these inputs, but a helper function is provided for
370 * the common case where the final required layer size is the union of the child filters'
371 * required inputs, evaluated on what this filter requires for itself. 'recurse' is kNo
372 * when mapping Contexts while actually filtering images, since the child recursion is
373 * happening at a higher level.
374 *
375 * Unlike the public getInputBounds(), all internal bounds calculations are done in the shared
376 * layer space defined by 'mapping'.
377 *
378 * The default implementation assumes that current filter requires an input equal to
379 * 'desiredOutputBounds', and passes this down to its child filters, and returns the union of
380 * their required inputs.
381 */
382 virtual skif::LayerSpace<SkIRect> onGetInputLayerBounds(
383 const skif::Mapping& mapping, const skif::LayerSpace<SkIRect>& desiredOutput,
384 const skif::LayerSpace<SkIRect>& contentBounds,
385 VisitChildren recurse = VisitChildren::kYes) const;
386
387 /**
388 * Calculates the output bounds that this filter node would touch when processing an input
389 * sized to 'contentBounds'. This function is responsible for recursing to its child image
390 * filters and accounting for what they output. It is up to the filter to determine how to
391 * aggregate the outputs of its children, but a helper function is provided for the common
392 * case where the filter output is the union of its child outputs.
393 *
394 * Unlike the public getOutputBounds(), all internal bounds calculations are done in the
395 * shared layer space defined by 'mapping'.
396 *
397 * The default implementation assumes that the output of this filter is equal to the union of
398 * the outputs of its child filters evaluated with 'contentBounds'.
399 */
400 // TODO (michaelludwig) - When layerMatrix = I, this function could be used to implement
401 // onComputeFastBounds() instead of making filters implement the essentially the same calcs x2
402 virtual skif::LayerSpace<SkIRect> onGetOutputLayerBounds(
403 const skif::Mapping& mapping, const skif::LayerSpace<SkIRect>& contentBounds) const;
404
405 // The actual implementation of the protected getFilterInputX() functions, but don't expose the
406 // flexible templating to subclasses so it can't be abused.
407 template<skif::Usage kU>
408 skif::FilterResult<kU> filterInput(int index, const skif::Context& ctx) const;
409
410 SkAutoSTArray<2, sk_sp<SkImageFilter>> fInputs;
411
412 bool fUsesSrcInput;
413 CropRect fCropRect;
414 uint32_t fUniqueID; // Globally unique
415
416 typedef SkImageFilter INHERITED;
417};
418
419static inline SkImageFilter_Base* as_IFB(SkImageFilter* filter) {
420 return static_cast<SkImageFilter_Base*>(filter);
421}
422
423static inline SkImageFilter_Base* as_IFB(const sk_sp<SkImageFilter>& filter) {
424 return static_cast<SkImageFilter_Base*>(filter.get());
425}
426
427static inline const SkImageFilter_Base* as_IFB(const SkImageFilter* filter) {
428 return static_cast<const SkImageFilter_Base*>(filter);
429}
430
431/**
432 * Helper to unflatten the common data, and return nullptr if we fail.
433 */
434#define SK_IMAGEFILTER_UNFLATTEN_COMMON(localVar, expectedCount) \
435 Common localVar; \
436 do { \
437 if (!localVar.unflatten(buffer, expectedCount)) { \
438 return nullptr; \
439 } \
440 } while (0)
441
442#endif // SkImageFilter_Base_DEFINED
443