1 | // Copyright 2013 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #ifndef FLUTTER_DISPLAY_LIST_EFFECTS_DL_IMAGE_FILTER_H_ |
6 | #define FLUTTER_DISPLAY_LIST_EFFECTS_DL_IMAGE_FILTER_H_ |
7 | |
8 | #include "flutter/display_list/dl_attributes.h" |
9 | #include "flutter/display_list/dl_sampling_options.h" |
10 | #include "flutter/display_list/dl_tile_mode.h" |
11 | #include "flutter/display_list/effects/dl_color_filter.h" |
12 | #include "flutter/display_list/utils/dl_comparable.h" |
13 | #include "flutter/fml/logging.h" |
14 | |
15 | #include "third_party/skia/include/core/SkMatrix.h" |
16 | |
17 | namespace flutter { |
18 | |
19 | // The DisplayList ImageFilter class. This class implements all of the |
20 | // facilities and adheres to the design goals of the |DlAttribute| base |
21 | // class. |
22 | // |
23 | // The objects here define operations that can take a location and one or |
24 | // more input pixels and produce a color for that output pixel |
25 | |
26 | // An enumerated type for the supported ImageFilter operations. |
27 | enum class DlImageFilterType { |
28 | kBlur, |
29 | kDilate, |
30 | kErode, |
31 | kMatrix, |
32 | kCompose, |
33 | kColorFilter, |
34 | kLocalMatrix, |
35 | }; |
36 | |
37 | class DlBlurImageFilter; |
38 | class DlDilateImageFilter; |
39 | class DlErodeImageFilter; |
40 | class DlMatrixImageFilter; |
41 | class DlLocalMatrixImageFilter; |
42 | class DlComposeImageFilter; |
43 | class DlColorFilterImageFilter; |
44 | |
45 | class DlImageFilter : public DlAttribute<DlImageFilter, DlImageFilterType> { |
46 | public: |
47 | enum class MatrixCapability { |
48 | kTranslate, |
49 | kScaleTranslate, |
50 | kComplex, |
51 | }; |
52 | |
53 | // Return a DlBlurImageFilter pointer to this object iff it is a Blur |
54 | // type of ImageFilter, otherwise return nullptr. |
55 | virtual const DlBlurImageFilter* asBlur() const { return nullptr; } |
56 | |
57 | // Return a DlDilateImageFilter pointer to this object iff it is a Dilate |
58 | // type of ImageFilter, otherwise return nullptr. |
59 | virtual const DlDilateImageFilter* asDilate() const { return nullptr; } |
60 | |
61 | // Return a DlErodeImageFilter pointer to this object iff it is an Erode |
62 | // type of ImageFilter, otherwise return nullptr. |
63 | virtual const DlErodeImageFilter* asErode() const { return nullptr; } |
64 | |
65 | // Return a DlMatrixImageFilter pointer to this object iff it is a Matrix |
66 | // type of ImageFilter, otherwise return nullptr. |
67 | virtual const DlMatrixImageFilter* asMatrix() const { return nullptr; } |
68 | |
69 | virtual const DlLocalMatrixImageFilter* asLocalMatrix() const { |
70 | return nullptr; |
71 | } |
72 | |
73 | virtual std::shared_ptr<DlImageFilter> makeWithLocalMatrix( |
74 | const SkMatrix& matrix) const; |
75 | |
76 | // Return a DlComposeImageFilter pointer to this object iff it is a Compose |
77 | // type of ImageFilter, otherwise return nullptr. |
78 | virtual const DlComposeImageFilter* asCompose() const { return nullptr; } |
79 | |
80 | // Return a DlColorFilterImageFilter pointer to this object iff it is a |
81 | // ColorFilter type of ImageFilter, otherwise return nullptr. |
82 | virtual const DlColorFilterImageFilter* asColorFilter() const { |
83 | return nullptr; |
84 | } |
85 | |
86 | // Return a boolean indicating whether the image filtering operation will |
87 | // modify transparent black. This is typically used to determine if applying |
88 | // the ImageFilter to a temporary saveLayer buffer will turn the surrounding |
89 | // pixels non-transparent and therefore expand the bounds. |
90 | virtual bool modifies_transparent_black() const = 0; |
91 | |
92 | // Return the bounds of the output for this image filtering operation |
93 | // based on the supplied input bounds where both are measured in the local |
94 | // (untransformed) coordinate space. |
95 | // |
96 | // The method will return a pointer to the output_bounds parameter if it |
97 | // can successfully compute the output bounds of the filter, otherwise the |
98 | // method will return a nullptr and the output_bounds will be filled with |
99 | // a best guess for the answer, even if just a copy of the input_bounds. |
100 | virtual SkRect* map_local_bounds(const SkRect& input_bounds, |
101 | SkRect& output_bounds) const = 0; |
102 | |
103 | // Return the device bounds of the output for this image filtering operation |
104 | // based on the supplied input device bounds where both are measured in the |
105 | // pixel coordinate space and relative to the given rendering ctm. The |
106 | // transform matrix is used to adjust the filter parameters for when it |
107 | // is used in a rendering operation (for example, the blur radius of a |
108 | // Blur filter will expand based on the ctm). |
109 | // |
110 | // The method will return a pointer to the output_bounds parameter if it |
111 | // can successfully compute the output bounds of the filter, otherwise the |
112 | // method will return a nullptr and the output_bounds will be filled with |
113 | // a best guess for the answer, even if just a copy of the input_bounds. |
114 | virtual SkIRect* map_device_bounds(const SkIRect& input_bounds, |
115 | const SkMatrix& ctm, |
116 | SkIRect& output_bounds) const = 0; |
117 | |
118 | // Return the input bounds that will be needed in order for the filter to |
119 | // properly fill the indicated output_bounds under the specified |
120 | // transformation matrix. Both output_bounds and input_bounds are taken to |
121 | // be relative to the transformed coordinate space of the provided |ctm|. |
122 | // |
123 | // The method will return a pointer to the input_bounds parameter if it |
124 | // can successfully compute the required input bounds, otherwise the |
125 | // method will return a nullptr and the input_bounds will be filled with |
126 | // a best guess for the answer, even if just a copy of the output_bounds. |
127 | virtual SkIRect* get_input_device_bounds(const SkIRect& output_bounds, |
128 | const SkMatrix& ctm, |
129 | SkIRect& input_bounds) const = 0; |
130 | |
131 | virtual MatrixCapability matrix_capability() const { |
132 | return MatrixCapability::kScaleTranslate; |
133 | } |
134 | |
135 | protected: |
136 | static SkVector map_vectors_affine(const SkMatrix& ctm, |
137 | SkScalar x, |
138 | SkScalar y) { |
139 | FML_DCHECK(SkScalarIsFinite(x) && x >= 0); |
140 | FML_DCHECK(SkScalarIsFinite(y) && y >= 0); |
141 | FML_DCHECK(ctm.isFinite() && !ctm.hasPerspective()); |
142 | |
143 | // The x and y scalars would have been used to expand a local space |
144 | // rectangle which is then transformed by ctm. In order to do the |
145 | // expansion correctly, we should look at the relevant math. The |
146 | // 4 corners will be moved outward by the following vectors: |
147 | // (UL,UR,LR,LL) = ((-x, -y), (+x, -y), (+x, +y), (-x, +y)) |
148 | // After applying the transform, each of these vectors could be |
149 | // pointing in any direction so we need to examine each transformed |
150 | // delta vector and how it affected the bounds. |
151 | // Looking at just the affine 2x3 entries of the CTM we can delta |
152 | // transform these corner offsets and get the following: |
153 | // UL = dCTM(-x, -y) = (- x*m00 - y*m01, - x*m10 - y*m11) |
154 | // UR = dCTM(+x, -y) = ( x*m00 - y*m01, x*m10 - y*m11) |
155 | // LR = dCTM(+x, +y) = ( x*m00 + y*m01, x*m10 + y*m11) |
156 | // LL = dCTM(-x, +y) = (- x*m00 + y*m01, - x*m10 + y*m11) |
157 | // The X vectors are all some variation of adding or subtracting |
158 | // the sum of x*m00 and y*m01 or their difference. Similarly the Y |
159 | // vectors are +/- the associated sum/difference of x*m10 and y*m11. |
160 | // The largest displacements, both left/right or up/down, will |
161 | // happen when the signs of the m00/m01/m10/m11 matrix entries |
162 | // coincide with the signs of the scalars, i.e. are all positive. |
163 | return {.fX: x * abs(lcpp_x: ctm[0]) + y * abs(lcpp_x: ctm[1]), |
164 | .fY: x * abs(lcpp_x: ctm[3]) + y * abs(lcpp_x: ctm[4])}; |
165 | } |
166 | |
167 | static SkIRect* inset_device_bounds(const SkIRect& input_bounds, |
168 | SkScalar radius_x, |
169 | SkScalar radius_y, |
170 | const SkMatrix& ctm, |
171 | SkIRect& output_bounds) { |
172 | if (ctm.isFinite()) { |
173 | if (ctm.hasPerspective()) { |
174 | SkMatrix inverse; |
175 | if (ctm.invert(inverse: &inverse)) { |
176 | SkRect local_bounds = inverse.mapRect(src: SkRect::Make(irect: input_bounds)); |
177 | local_bounds.inset(dx: radius_x, dy: radius_y); |
178 | output_bounds = ctm.mapRect(src: local_bounds).roundOut(); |
179 | return &output_bounds; |
180 | } |
181 | } else { |
182 | SkVector device_radius = map_vectors_affine(ctm, x: radius_x, y: radius_y); |
183 | output_bounds = input_bounds.makeInset(dx: floor(lcpp_x: device_radius.fX), // |
184 | dy: floor(lcpp_x: device_radius.fY)); |
185 | return &output_bounds; |
186 | } |
187 | } |
188 | output_bounds = input_bounds; |
189 | return nullptr; |
190 | } |
191 | |
192 | static SkIRect* outset_device_bounds(const SkIRect& input_bounds, |
193 | SkScalar radius_x, |
194 | SkScalar radius_y, |
195 | const SkMatrix& ctm, |
196 | SkIRect& output_bounds) { |
197 | if (ctm.isFinite()) { |
198 | if (ctm.hasPerspective()) { |
199 | SkMatrix inverse; |
200 | if (ctm.invert(inverse: &inverse)) { |
201 | SkRect local_bounds = inverse.mapRect(src: SkRect::Make(irect: input_bounds)); |
202 | local_bounds.outset(dx: radius_x, dy: radius_y); |
203 | output_bounds = ctm.mapRect(src: local_bounds).roundOut(); |
204 | return &output_bounds; |
205 | } |
206 | } else { |
207 | SkVector device_radius = map_vectors_affine(ctm, x: radius_x, y: radius_y); |
208 | output_bounds = input_bounds.makeOutset(dx: ceil(lcpp_x: device_radius.fX), // |
209 | dy: ceil(lcpp_x: device_radius.fY)); |
210 | return &output_bounds; |
211 | } |
212 | } |
213 | output_bounds = input_bounds; |
214 | return nullptr; |
215 | } |
216 | }; |
217 | |
218 | class DlBlurImageFilter final : public DlImageFilter { |
219 | public: |
220 | DlBlurImageFilter(SkScalar sigma_x, SkScalar sigma_y, DlTileMode tile_mode) |
221 | : sigma_x_(sigma_x), sigma_y_(sigma_y), tile_mode_(tile_mode) {} |
222 | explicit DlBlurImageFilter(const DlBlurImageFilter* filter) |
223 | : DlBlurImageFilter(filter->sigma_x_, |
224 | filter->sigma_y_, |
225 | filter->tile_mode_) {} |
226 | explicit DlBlurImageFilter(const DlBlurImageFilter& filter) |
227 | : DlBlurImageFilter(&filter) {} |
228 | |
229 | static std::shared_ptr<DlImageFilter> Make(SkScalar sigma_x, |
230 | SkScalar sigma_y, |
231 | DlTileMode tile_mode) { |
232 | if (!SkScalarIsFinite(x: sigma_x) || !SkScalarIsFinite(x: sigma_y)) { |
233 | return nullptr; |
234 | } |
235 | if (sigma_x < SK_ScalarNearlyZero && sigma_y < SK_ScalarNearlyZero) { |
236 | return nullptr; |
237 | } |
238 | sigma_x = (sigma_x < SK_ScalarNearlyZero) ? 0 : sigma_x; |
239 | sigma_y = (sigma_y < SK_ScalarNearlyZero) ? 0 : sigma_y; |
240 | return std::make_shared<DlBlurImageFilter>(args&: sigma_x, args&: sigma_y, args&: tile_mode); |
241 | } |
242 | |
243 | std::shared_ptr<DlImageFilter> shared() const override { |
244 | return std::make_shared<DlBlurImageFilter>(args: this); |
245 | } |
246 | |
247 | DlImageFilterType type() const override { return DlImageFilterType::kBlur; } |
248 | size_t size() const override { return sizeof(*this); } |
249 | |
250 | const DlBlurImageFilter* asBlur() const override { return this; } |
251 | |
252 | bool modifies_transparent_black() const override { return false; } |
253 | |
254 | SkRect* map_local_bounds(const SkRect& input_bounds, |
255 | SkRect& output_bounds) const override { |
256 | output_bounds = input_bounds.makeOutset(dx: sigma_x_ * 3.0f, dy: sigma_y_ * 3.0f); |
257 | return &output_bounds; |
258 | } |
259 | |
260 | SkIRect* map_device_bounds(const SkIRect& input_bounds, |
261 | const SkMatrix& ctm, |
262 | SkIRect& output_bounds) const override { |
263 | return outset_device_bounds(input_bounds, radius_x: sigma_x_ * 3.0f, radius_y: sigma_y_ * 3.0f, |
264 | ctm, output_bounds); |
265 | } |
266 | |
267 | SkIRect* get_input_device_bounds(const SkIRect& output_bounds, |
268 | const SkMatrix& ctm, |
269 | SkIRect& input_bounds) const override { |
270 | // Blurs are symmetric in terms of output-for-input and input-for-output |
271 | return map_device_bounds(input_bounds: output_bounds, ctm, output_bounds&: input_bounds); |
272 | } |
273 | |
274 | SkScalar sigma_x() const { return sigma_x_; } |
275 | SkScalar sigma_y() const { return sigma_y_; } |
276 | DlTileMode tile_mode() const { return tile_mode_; } |
277 | |
278 | protected: |
279 | bool equals_(const DlImageFilter& other) const override { |
280 | FML_DCHECK(other.type() == DlImageFilterType::kBlur); |
281 | auto that = static_cast<const DlBlurImageFilter*>(&other); |
282 | return (sigma_x_ == that->sigma_x_ && sigma_y_ == that->sigma_y_ && |
283 | tile_mode_ == that->tile_mode_); |
284 | } |
285 | |
286 | private: |
287 | SkScalar sigma_x_; |
288 | SkScalar sigma_y_; |
289 | DlTileMode tile_mode_; |
290 | }; |
291 | |
292 | class DlDilateImageFilter final : public DlImageFilter { |
293 | public: |
294 | DlDilateImageFilter(SkScalar radius_x, SkScalar radius_y) |
295 | : radius_x_(radius_x), radius_y_(radius_y) {} |
296 | explicit DlDilateImageFilter(const DlDilateImageFilter* filter) |
297 | : DlDilateImageFilter(filter->radius_x_, filter->radius_y_) {} |
298 | explicit DlDilateImageFilter(const DlDilateImageFilter& filter) |
299 | : DlDilateImageFilter(&filter) {} |
300 | |
301 | static std::shared_ptr<DlImageFilter> Make(SkScalar radius_x, |
302 | SkScalar radius_y) { |
303 | if (SkScalarIsFinite(x: radius_x) && radius_x > SK_ScalarNearlyZero && |
304 | SkScalarIsFinite(x: radius_y) && radius_y > SK_ScalarNearlyZero) { |
305 | return std::make_shared<DlDilateImageFilter>(args&: radius_x, args&: radius_y); |
306 | } |
307 | return nullptr; |
308 | } |
309 | |
310 | std::shared_ptr<DlImageFilter> shared() const override { |
311 | return std::make_shared<DlDilateImageFilter>(args: this); |
312 | } |
313 | |
314 | DlImageFilterType type() const override { return DlImageFilterType::kDilate; } |
315 | size_t size() const override { return sizeof(*this); } |
316 | |
317 | const DlDilateImageFilter* asDilate() const override { return this; } |
318 | |
319 | bool modifies_transparent_black() const override { return false; } |
320 | |
321 | SkRect* map_local_bounds(const SkRect& input_bounds, |
322 | SkRect& output_bounds) const override { |
323 | output_bounds = input_bounds.makeOutset(dx: radius_x_, dy: radius_y_); |
324 | return &output_bounds; |
325 | } |
326 | |
327 | SkIRect* map_device_bounds(const SkIRect& input_bounds, |
328 | const SkMatrix& ctm, |
329 | SkIRect& output_bounds) const override { |
330 | return outset_device_bounds(input_bounds, radius_x: radius_x_, radius_y: radius_y_, ctm, |
331 | output_bounds); |
332 | } |
333 | |
334 | SkIRect* get_input_device_bounds(const SkIRect& output_bounds, |
335 | const SkMatrix& ctm, |
336 | SkIRect& input_bounds) const override { |
337 | return inset_device_bounds(input_bounds: output_bounds, radius_x: radius_x_, radius_y: radius_y_, ctm, |
338 | output_bounds&: input_bounds); |
339 | } |
340 | |
341 | SkScalar radius_x() const { return radius_x_; } |
342 | SkScalar radius_y() const { return radius_y_; } |
343 | |
344 | protected: |
345 | bool equals_(const DlImageFilter& other) const override { |
346 | FML_DCHECK(other.type() == DlImageFilterType::kDilate); |
347 | auto that = static_cast<const DlDilateImageFilter*>(&other); |
348 | return (radius_x_ == that->radius_x_ && radius_y_ == that->radius_y_); |
349 | } |
350 | |
351 | private: |
352 | SkScalar radius_x_; |
353 | SkScalar radius_y_; |
354 | }; |
355 | |
356 | class DlErodeImageFilter final : public DlImageFilter { |
357 | public: |
358 | DlErodeImageFilter(SkScalar radius_x, SkScalar radius_y) |
359 | : radius_x_(radius_x), radius_y_(radius_y) {} |
360 | explicit DlErodeImageFilter(const DlErodeImageFilter* filter) |
361 | : DlErodeImageFilter(filter->radius_x_, filter->radius_y_) {} |
362 | explicit DlErodeImageFilter(const DlErodeImageFilter& filter) |
363 | : DlErodeImageFilter(&filter) {} |
364 | |
365 | static std::shared_ptr<DlImageFilter> Make(SkScalar radius_x, |
366 | SkScalar radius_y) { |
367 | if (SkScalarIsFinite(x: radius_x) && radius_x > SK_ScalarNearlyZero && |
368 | SkScalarIsFinite(x: radius_y) && radius_y > SK_ScalarNearlyZero) { |
369 | return std::make_shared<DlErodeImageFilter>(args&: radius_x, args&: radius_y); |
370 | } |
371 | return nullptr; |
372 | } |
373 | |
374 | std::shared_ptr<DlImageFilter> shared() const override { |
375 | return std::make_shared<DlErodeImageFilter>(args: this); |
376 | } |
377 | |
378 | DlImageFilterType type() const override { return DlImageFilterType::kErode; } |
379 | size_t size() const override { return sizeof(*this); } |
380 | |
381 | const DlErodeImageFilter* asErode() const override { return this; } |
382 | |
383 | bool modifies_transparent_black() const override { return false; } |
384 | |
385 | SkRect* map_local_bounds(const SkRect& input_bounds, |
386 | SkRect& output_bounds) const override { |
387 | output_bounds = input_bounds.makeInset(dx: radius_x_, dy: radius_y_); |
388 | return &output_bounds; |
389 | } |
390 | |
391 | SkIRect* map_device_bounds(const SkIRect& input_bounds, |
392 | const SkMatrix& ctm, |
393 | SkIRect& output_bounds) const override { |
394 | return inset_device_bounds(input_bounds, radius_x: radius_x_, radius_y: radius_y_, ctm, |
395 | output_bounds); |
396 | } |
397 | |
398 | SkIRect* get_input_device_bounds(const SkIRect& output_bounds, |
399 | const SkMatrix& ctm, |
400 | SkIRect& input_bounds) const override { |
401 | return outset_device_bounds(input_bounds: output_bounds, radius_x: radius_x_, radius_y: radius_y_, ctm, |
402 | output_bounds&: input_bounds); |
403 | } |
404 | |
405 | SkScalar radius_x() const { return radius_x_; } |
406 | SkScalar radius_y() const { return radius_y_; } |
407 | |
408 | protected: |
409 | bool equals_(const DlImageFilter& other) const override { |
410 | FML_DCHECK(other.type() == DlImageFilterType::kErode); |
411 | auto that = static_cast<const DlErodeImageFilter*>(&other); |
412 | return (radius_x_ == that->radius_x_ && radius_y_ == that->radius_y_); |
413 | } |
414 | |
415 | private: |
416 | SkScalar radius_x_; |
417 | SkScalar radius_y_; |
418 | }; |
419 | |
420 | class DlMatrixImageFilter final : public DlImageFilter { |
421 | public: |
422 | DlMatrixImageFilter(const SkMatrix& matrix, DlImageSampling sampling) |
423 | : matrix_(matrix), sampling_(sampling) {} |
424 | explicit DlMatrixImageFilter(const DlMatrixImageFilter* filter) |
425 | : DlMatrixImageFilter(filter->matrix_, filter->sampling_) {} |
426 | explicit DlMatrixImageFilter(const DlMatrixImageFilter& filter) |
427 | : DlMatrixImageFilter(&filter) {} |
428 | |
429 | static std::shared_ptr<DlImageFilter> Make(const SkMatrix& matrix, |
430 | DlImageSampling sampling) { |
431 | if (matrix.isFinite() && !matrix.isIdentity()) { |
432 | return std::make_shared<DlMatrixImageFilter>(args: matrix, args&: sampling); |
433 | } |
434 | return nullptr; |
435 | } |
436 | |
437 | std::shared_ptr<DlImageFilter> shared() const override { |
438 | return std::make_shared<DlMatrixImageFilter>(args: this); |
439 | } |
440 | |
441 | DlImageFilterType type() const override { return DlImageFilterType::kMatrix; } |
442 | size_t size() const override { return sizeof(*this); } |
443 | |
444 | const SkMatrix& matrix() const { return matrix_; } |
445 | DlImageSampling sampling() const { return sampling_; } |
446 | |
447 | const DlMatrixImageFilter* asMatrix() const override { return this; } |
448 | |
449 | bool modifies_transparent_black() const override { return false; } |
450 | |
451 | SkRect* map_local_bounds(const SkRect& input_bounds, |
452 | SkRect& output_bounds) const override { |
453 | output_bounds = matrix_.mapRect(src: input_bounds); |
454 | return &output_bounds; |
455 | } |
456 | |
457 | SkIRect* map_device_bounds(const SkIRect& input_bounds, |
458 | const SkMatrix& ctm, |
459 | SkIRect& output_bounds) const override { |
460 | SkMatrix matrix; |
461 | if (!ctm.invert(inverse: &matrix)) { |
462 | output_bounds = input_bounds; |
463 | return nullptr; |
464 | } |
465 | matrix.postConcat(other: matrix_); |
466 | matrix.postConcat(other: ctm); |
467 | SkRect device_rect; |
468 | matrix.mapRect(dst: &device_rect, src: SkRect::Make(irect: input_bounds)); |
469 | output_bounds = device_rect.roundOut(); |
470 | return &output_bounds; |
471 | } |
472 | |
473 | SkIRect* get_input_device_bounds(const SkIRect& output_bounds, |
474 | const SkMatrix& ctm, |
475 | SkIRect& input_bounds) const override { |
476 | SkMatrix matrix = SkMatrix::Concat(a: ctm, b: matrix_); |
477 | SkMatrix inverse; |
478 | if (!matrix.invert(inverse: &inverse)) { |
479 | input_bounds = output_bounds; |
480 | return nullptr; |
481 | } |
482 | inverse.postConcat(other: ctm); |
483 | SkRect bounds; |
484 | bounds.set(output_bounds); |
485 | inverse.mapRect(rect: &bounds); |
486 | input_bounds = bounds.roundOut(); |
487 | return &input_bounds; |
488 | } |
489 | |
490 | protected: |
491 | bool equals_(const DlImageFilter& other) const override { |
492 | FML_DCHECK(other.type() == DlImageFilterType::kMatrix); |
493 | auto that = static_cast<const DlMatrixImageFilter*>(&other); |
494 | return (matrix_ == that->matrix_ && sampling_ == that->sampling_); |
495 | } |
496 | |
497 | private: |
498 | SkMatrix matrix_; |
499 | DlImageSampling sampling_; |
500 | }; |
501 | |
502 | class DlComposeImageFilter final : public DlImageFilter { |
503 | public: |
504 | DlComposeImageFilter(std::shared_ptr<const DlImageFilter> outer, |
505 | std::shared_ptr<const DlImageFilter> inner) |
506 | : outer_(std::move(outer)), inner_(std::move(inner)) {} |
507 | DlComposeImageFilter(const DlImageFilter* outer, const DlImageFilter* inner) |
508 | : outer_(outer->shared()), inner_(inner->shared()) {} |
509 | DlComposeImageFilter(const DlImageFilter& outer, const DlImageFilter& inner) |
510 | : DlComposeImageFilter(&outer, &inner) {} |
511 | explicit DlComposeImageFilter(const DlComposeImageFilter* filter) |
512 | : DlComposeImageFilter(filter->outer_, filter->inner_) {} |
513 | explicit DlComposeImageFilter(const DlComposeImageFilter& filter) |
514 | : DlComposeImageFilter(&filter) {} |
515 | |
516 | static std::shared_ptr<const DlImageFilter> Make( |
517 | std::shared_ptr<const DlImageFilter> outer, |
518 | std::shared_ptr<const DlImageFilter> inner) { |
519 | if (!outer) { |
520 | return inner; |
521 | } |
522 | if (!inner) { |
523 | return outer; |
524 | } |
525 | return std::make_shared<DlComposeImageFilter>(args&: outer, args&: inner); |
526 | } |
527 | |
528 | std::shared_ptr<DlImageFilter> shared() const override { |
529 | return std::make_shared<DlComposeImageFilter>(args: this); |
530 | } |
531 | |
532 | DlImageFilterType type() const override { |
533 | return DlImageFilterType::kCompose; |
534 | } |
535 | size_t size() const override { return sizeof(*this); } |
536 | |
537 | std::shared_ptr<const DlImageFilter> outer() const { return outer_; } |
538 | std::shared_ptr<const DlImageFilter> inner() const { return inner_; } |
539 | |
540 | const DlComposeImageFilter* asCompose() const override { return this; } |
541 | |
542 | bool modifies_transparent_black() const override { |
543 | if (inner_ && inner_->modifies_transparent_black()) { |
544 | return true; |
545 | } |
546 | if (outer_ && outer_->modifies_transparent_black()) { |
547 | return true; |
548 | } |
549 | return false; |
550 | } |
551 | |
552 | SkRect* map_local_bounds(const SkRect& input_bounds, |
553 | SkRect& output_bounds) const override; |
554 | |
555 | SkIRect* map_device_bounds(const SkIRect& input_bounds, |
556 | const SkMatrix& ctm, |
557 | SkIRect& output_bounds) const override; |
558 | |
559 | SkIRect* get_input_device_bounds(const SkIRect& output_bounds, |
560 | const SkMatrix& ctm, |
561 | SkIRect& input_bounds) const override; |
562 | |
563 | MatrixCapability matrix_capability() const override { |
564 | return std::min(a: outer_->matrix_capability(), b: inner_->matrix_capability()); |
565 | } |
566 | |
567 | protected: |
568 | bool equals_(const DlImageFilter& other) const override { |
569 | FML_DCHECK(other.type() == DlImageFilterType::kCompose); |
570 | auto that = static_cast<const DlComposeImageFilter*>(&other); |
571 | return (Equals(a: outer_, b: that->outer_) && Equals(a: inner_, b: that->inner_)); |
572 | } |
573 | |
574 | private: |
575 | std::shared_ptr<const DlImageFilter> outer_; |
576 | std::shared_ptr<const DlImageFilter> inner_; |
577 | }; |
578 | |
579 | class DlColorFilterImageFilter final : public DlImageFilter { |
580 | public: |
581 | explicit DlColorFilterImageFilter(std::shared_ptr<const DlColorFilter> filter) |
582 | : color_filter_(std::move(filter)) {} |
583 | explicit DlColorFilterImageFilter(const DlColorFilter* filter) |
584 | : color_filter_(filter->shared()) {} |
585 | explicit DlColorFilterImageFilter(const DlColorFilter& filter) |
586 | : color_filter_(filter.shared()) {} |
587 | explicit DlColorFilterImageFilter(const DlColorFilterImageFilter* filter) |
588 | : DlColorFilterImageFilter(filter->color_filter_) {} |
589 | explicit DlColorFilterImageFilter(const DlColorFilterImageFilter& filter) |
590 | : DlColorFilterImageFilter(&filter) {} |
591 | |
592 | static std::shared_ptr<DlImageFilter> Make( |
593 | std::shared_ptr<const DlColorFilter> filter) { |
594 | if (filter) { |
595 | return std::make_shared<DlColorFilterImageFilter>(args&: filter); |
596 | } |
597 | return nullptr; |
598 | } |
599 | |
600 | std::shared_ptr<DlImageFilter> shared() const override { |
601 | return std::make_shared<DlColorFilterImageFilter>(args: color_filter_); |
602 | } |
603 | |
604 | DlImageFilterType type() const override { |
605 | return DlImageFilterType::kColorFilter; |
606 | } |
607 | size_t size() const override { return sizeof(*this); } |
608 | |
609 | const std::shared_ptr<const DlColorFilter> color_filter() const { |
610 | return color_filter_; |
611 | } |
612 | |
613 | const DlColorFilterImageFilter* asColorFilter() const override { |
614 | return this; |
615 | } |
616 | |
617 | bool modifies_transparent_black() const override { |
618 | if (color_filter_) { |
619 | return color_filter_->modifies_transparent_black(); |
620 | } |
621 | return false; |
622 | } |
623 | |
624 | SkRect* map_local_bounds(const SkRect& input_bounds, |
625 | SkRect& output_bounds) const override { |
626 | output_bounds = input_bounds; |
627 | return modifies_transparent_black() ? nullptr : &output_bounds; |
628 | } |
629 | |
630 | SkIRect* map_device_bounds(const SkIRect& input_bounds, |
631 | const SkMatrix& ctm, |
632 | SkIRect& output_bounds) const override { |
633 | output_bounds = input_bounds; |
634 | return modifies_transparent_black() ? nullptr : &output_bounds; |
635 | } |
636 | |
637 | SkIRect* get_input_device_bounds(const SkIRect& output_bounds, |
638 | const SkMatrix& ctm, |
639 | SkIRect& input_bounds) const override { |
640 | return map_device_bounds(input_bounds: output_bounds, ctm, output_bounds&: input_bounds); |
641 | } |
642 | |
643 | MatrixCapability matrix_capability() const override { |
644 | return MatrixCapability::kComplex; |
645 | } |
646 | |
647 | std::shared_ptr<DlImageFilter> makeWithLocalMatrix( |
648 | const SkMatrix& matrix) const override { |
649 | return shared(); |
650 | } |
651 | |
652 | protected: |
653 | bool equals_(const DlImageFilter& other) const override { |
654 | FML_DCHECK(other.type() == DlImageFilterType::kColorFilter); |
655 | auto that = static_cast<const DlColorFilterImageFilter*>(&other); |
656 | return Equals(a: color_filter_, b: that->color_filter_); |
657 | } |
658 | |
659 | private: |
660 | std::shared_ptr<const DlColorFilter> color_filter_; |
661 | }; |
662 | |
663 | class DlLocalMatrixImageFilter final : public DlImageFilter { |
664 | public: |
665 | explicit DlLocalMatrixImageFilter(const SkMatrix& matrix, |
666 | std::shared_ptr<DlImageFilter> filter) |
667 | : matrix_(matrix), image_filter_(filter) {} |
668 | explicit DlLocalMatrixImageFilter(const DlLocalMatrixImageFilter* filter) |
669 | : DlLocalMatrixImageFilter(filter->matrix_, filter->image_filter_) {} |
670 | DlLocalMatrixImageFilter(const DlLocalMatrixImageFilter& filter) |
671 | : DlLocalMatrixImageFilter(&filter) {} |
672 | std::shared_ptr<DlImageFilter> shared() const override { |
673 | return std::make_shared<DlLocalMatrixImageFilter>(args: this); |
674 | } |
675 | |
676 | DlImageFilterType type() const override { |
677 | return DlImageFilterType::kLocalMatrix; |
678 | } |
679 | size_t size() const override { return sizeof(*this); } |
680 | |
681 | const SkMatrix& matrix() const { return matrix_; } |
682 | |
683 | const std::shared_ptr<DlImageFilter> image_filter() const { |
684 | return image_filter_; |
685 | } |
686 | |
687 | const DlLocalMatrixImageFilter* asLocalMatrix() const override { |
688 | return this; |
689 | } |
690 | |
691 | bool modifies_transparent_black() const override { |
692 | if (!image_filter_) { |
693 | return false; |
694 | } |
695 | return image_filter_->modifies_transparent_black(); |
696 | } |
697 | |
698 | SkRect* map_local_bounds(const SkRect& input_bounds, |
699 | SkRect& output_bounds) const override { |
700 | if (!image_filter_) { |
701 | return nullptr; |
702 | } |
703 | return image_filter_->map_local_bounds(input_bounds, output_bounds); |
704 | } |
705 | |
706 | SkIRect* map_device_bounds(const SkIRect& input_bounds, |
707 | const SkMatrix& ctm, |
708 | SkIRect& output_bounds) const override { |
709 | if (!image_filter_) { |
710 | return nullptr; |
711 | } |
712 | return image_filter_->map_device_bounds( |
713 | input_bounds, ctm: SkMatrix::Concat(a: ctm, b: matrix_), output_bounds); |
714 | } |
715 | |
716 | SkIRect* get_input_device_bounds(const SkIRect& output_bounds, |
717 | const SkMatrix& ctm, |
718 | SkIRect& input_bounds) const override { |
719 | if (!image_filter_) { |
720 | return nullptr; |
721 | } |
722 | return image_filter_->get_input_device_bounds( |
723 | output_bounds, ctm: SkMatrix::Concat(a: ctm, b: matrix_), input_bounds); |
724 | } |
725 | |
726 | protected: |
727 | bool equals_(const DlImageFilter& other) const override { |
728 | FML_DCHECK(other.type() == DlImageFilterType::kLocalMatrix); |
729 | auto that = static_cast<const DlLocalMatrixImageFilter*>(&other); |
730 | return (matrix_ == that->matrix_ && |
731 | Equals(a: image_filter_, b: that->image_filter_)); |
732 | } |
733 | |
734 | private: |
735 | SkMatrix matrix_; |
736 | std::shared_ptr<DlImageFilter> image_filter_; |
737 | }; |
738 | |
739 | } // namespace flutter |
740 | |
741 | #endif // FLUTTER_DISPLAY_LIST_EFFECTS_DL_IMAGE_FILTER_H_ |
742 | |