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 | |
18 | class GrFragmentProcessor; |
19 | class 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. |
23 | class SkImageFilter_Base : public SkImageFilter { |
24 | public: |
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 | |
152 | protected: |
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 | |
311 | private: |
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 | |
419 | static inline SkImageFilter_Base* as_IFB(SkImageFilter* filter) { |
420 | return static_cast<SkImageFilter_Base*>(filter); |
421 | } |
422 | |
423 | static inline SkImageFilter_Base* as_IFB(const sk_sp<SkImageFilter>& filter) { |
424 | return static_cast<SkImageFilter_Base*>(filter.get()); |
425 | } |
426 | |
427 | static 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 | |