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
17namespace 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.
27enum class DlImageFilterType {
28 kBlur,
29 kDilate,
30 kErode,
31 kMatrix,
32 kCompose,
33 kColorFilter,
34 kLocalMatrix,
35};
36
37class DlBlurImageFilter;
38class DlDilateImageFilter;
39class DlErodeImageFilter;
40class DlMatrixImageFilter;
41class DlLocalMatrixImageFilter;
42class DlComposeImageFilter;
43class DlColorFilterImageFilter;
44
45class 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
218class 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
292class 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
356class 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
420class 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
502class 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
579class 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
663class 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

source code of flutter_engine/flutter/display_list/effects/dl_image_filter.h