Flutter Engine
 
Loading...
Searching...
No Matches
dl_image_filter_unittests.cc
Go to the documentation of this file.
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
16#include "gtest/gtest.h"
17
18#include "include/core/SkMatrix.h"
19#include "third_party/skia/include/core/SkBlendMode.h"
20#include "third_party/skia/include/core/SkColorFilter.h"
21#include "third_party/skia/include/core/SkSamplingOptions.h"
22#include "third_party/skia/include/effects/SkImageFilters.h"
23
24namespace flutter {
25namespace testing {
26
27// DlRect::Contains treats the rect as a half-open interval which is
28// appropriate for so many operations. Unfortunately, we are using
29// it here to test containment of the corners of a transformed quad
30// so the corners of the quad that are measured against the right
31// and bottom edges are contained even if they are on the right or
32// bottom edge. This method does the "all sides inclusive" version
33// of DlRect::Contains.
34static bool containsInclusive(const DlRect rect, const DlPoint p) {
35 // Test with a slight offset of 1E-9 to "forgive" IEEE bit-rounding
36 // Ending up with bounds that are off by 1E-9 (these numbers are all
37 // being tested in device space with this method) will be off by a
38 // negligible amount of a pixel that wouldn't contribute to changing
39 // the color of a pixel.
40 return (p.x >= rect.GetLeft() - 1E-9 && //
41 p.x <= rect.GetRight() + 1E-9 && //
42 p.y >= rect.GetTop() - 1E-9 && //
43 p.y <= rect.GetBottom() + 1E-9);
44}
45
46static bool containsInclusive(const DlRect rect, const DlQuad quad) {
47 return (containsInclusive(rect, quad[0]) && //
48 containsInclusive(rect, quad[1]) && //
49 containsInclusive(rect, quad[2]) && //
50 containsInclusive(rect, quad[3]));
51}
52
53static bool containsInclusive(const DlIRect rect, const DlQuad quad) {
54 return containsInclusive(DlRect::Make(rect), quad);
55}
56
57static bool containsInclusive(const DlIRect rect, const DlRect bounds) {
58 return (bounds.GetLeft() >= rect.GetLeft() - 1E-9 &&
59 bounds.GetTop() >= rect.GetTop() - 1E-9 &&
60 bounds.GetRight() <= rect.GetRight() + 1E-9 &&
61 bounds.GetBottom() <= rect.GetBottom() + 1E-9);
62}
63
64// Used to verify that the expected output bounds and reverse-engineered
65// "input bounds for output bounds" rectangles are included in the rectangle
66// returned from the various bounds computation methods under the specified
67// matrix.
68static void TestBoundsWithMatrix(const DlImageFilter& filter,
69 const DlMatrix& matrix,
70 const DlRect& sourceBounds,
71 const DlQuad& expectedLocalOutputQuad) {
72 DlRect device_input_bounds = sourceBounds.TransformAndClipBounds(matrix);
73 DlQuad expected_output_quad = matrix.Transform(expectedLocalOutputQuad);
74
75 DlIRect device_filter_ibounds;
76 ASSERT_EQ(filter.map_device_bounds(DlIRect::RoundOut(device_input_bounds),
77 matrix, device_filter_ibounds),
78 &device_filter_ibounds);
79 EXPECT_TRUE(containsInclusive(device_filter_ibounds, expected_output_quad))
80 << filter << std::endl
81 << sourceBounds << ", {" << std::endl
82 << " " << expectedLocalOutputQuad[0] << ", " << std::endl
83 << " " << expectedLocalOutputQuad[1] << ", " << std::endl
84 << " " << expectedLocalOutputQuad[2] << ", " << std::endl
85 << " " << expectedLocalOutputQuad[3] << std::endl
86 << "}, " << matrix << ", " << std::endl
87 << device_filter_ibounds << std::endl
88 << device_input_bounds << ", {" << std::endl
89 << " " << expected_output_quad[0] << ", " << std::endl
90 << " " << expected_output_quad[1] << ", " << std::endl
91 << " " << expected_output_quad[2] << ", " << std::endl
92 << " " << expected_output_quad[3] << std::endl
93 << "}";
94
95 DlIRect reverse_input_ibounds;
96 ASSERT_EQ(filter.get_input_device_bounds(device_filter_ibounds, matrix,
97 reverse_input_ibounds),
98 &reverse_input_ibounds);
99 EXPECT_TRUE(containsInclusive(reverse_input_ibounds, device_input_bounds))
100 << filter << std::endl
101 << matrix << ", " << std::endl
102 << reverse_input_ibounds << ", " << std::endl
103 << device_input_bounds;
104}
105
106static void TestInvalidBounds(const DlImageFilter& filter,
107 const DlMatrix& matrix,
108 const DlRect& localInputBounds) {
109 DlIRect device_input_bounds =
110 DlIRect::RoundOut(localInputBounds.TransformBounds(matrix));
111
112 DlRect local_filter_bounds;
113 ASSERT_EQ(filter.map_local_bounds(localInputBounds, local_filter_bounds),
114 nullptr);
115 ASSERT_EQ(local_filter_bounds, localInputBounds);
116
117 DlIRect device_filter_ibounds;
118 ASSERT_EQ(filter.map_device_bounds(device_input_bounds, matrix,
119 device_filter_ibounds),
120 nullptr);
121 ASSERT_EQ(device_filter_ibounds, device_input_bounds);
122
123 DlIRect reverse_input_ibounds;
124 ASSERT_EQ(filter.get_input_device_bounds(device_input_bounds, matrix,
125 reverse_input_ibounds),
126 nullptr);
127 ASSERT_EQ(reverse_input_ibounds, device_input_bounds);
128}
129
130// localInputBounds is a sample bounds for testing as input to the filter.
131// localExpectOutputBounds is the theoretical output bounds for applying
132// the filter to the localInputBounds.
133// localExpectInputBounds is the theoretical input bounds required for the
134// filter to cover the localExpectOutputBounds
135// If either of the expected bounds are nullptr then the bounds methods will
136// be assumed to be unable to perform their computations for the given
137// image filter and will be returning null.
138static void TestBounds(const DlImageFilter& filter,
139 const DlRect& sourceBounds,
140 const DlQuad& expectedLocalOutputQuad) {
141 DlRect local_filter_bounds;
142 ASSERT_EQ(filter.map_local_bounds(sourceBounds, local_filter_bounds),
143 &local_filter_bounds);
144 ASSERT_TRUE(containsInclusive(local_filter_bounds, expectedLocalOutputQuad));
145
146 for (int i_scale = 1; i_scale <= 4; i_scale++) {
147 DlScalar scale = i_scale;
148 for (int skew_eighths = 0; skew_eighths < 7; skew_eighths++) {
149 DlScalar skew = skew_eighths / 8.0f;
150 for (int degrees = 0; degrees <= 360; degrees += 15) {
151 DlMatrix matrix;
152 matrix = matrix.Scale({scale, scale, 1});
153 matrix = DlMatrix::MakeSkew(skew, skew) * matrix;
154 matrix = DlMatrix::MakeRotationZ(DlDegrees(degrees)) * matrix;
155 ASSERT_TRUE(matrix.IsInvertible()) << matrix;
156 ASSERT_FALSE(matrix.HasPerspective2D()) << matrix;
157 TestBoundsWithMatrix(filter, matrix, sourceBounds,
158 expectedLocalOutputQuad);
159 matrix.m[3] = 0.001f;
160 matrix.m[7] = 0.001f;
161 ASSERT_TRUE(matrix.IsInvertible()) << matrix;
162 ASSERT_TRUE(matrix.HasPerspective2D()) << matrix;
163 TestBoundsWithMatrix(filter, matrix, sourceBounds,
164 expectedLocalOutputQuad);
165 }
166 }
167 }
168}
169
170static void TestBounds(const DlImageFilter& filter,
171 const DlRect& sourceBounds,
172 const DlRect& expectedLocalOutputBounds) {
173 DlQuad expected_local_output_quad = expectedLocalOutputBounds.GetPoints();
174 ASSERT_EQ(expected_local_output_quad.size(), 4u); // Only 0u when empty
175 TestBounds(filter, sourceBounds, expected_local_output_quad);
176}
177
178TEST(DisplayListImageFilter, BlurConstructor) {
179 DlBlurImageFilter filter(5.0, 6.0, DlTileMode::kMirror);
180}
181
182TEST(DisplayListImageFilter, BlurShared) {
183 DlBlurImageFilter filter(5.0, 6.0, DlTileMode::kMirror);
184
185 ASSERT_NE(filter.shared().get(), &filter);
186 ASSERT_EQ(*filter.shared(), filter);
187}
188
189TEST(DisplayListImageFilter, BlurAsBlur) {
190 DlBlurImageFilter filter(5.0, 6.0, DlTileMode::kMirror);
191
192 ASSERT_NE(filter.asBlur(), nullptr);
193 ASSERT_EQ(filter.asBlur(), &filter);
194}
195
196TEST(DisplayListImageFilter, BlurContents) {
197 DlBlurImageFilter filter(5.0, 6.0, DlTileMode::kMirror);
198
199 ASSERT_EQ(filter.sigma_x(), 5.0);
200 ASSERT_EQ(filter.sigma_y(), 6.0);
201 ASSERT_EQ(filter.tile_mode(), DlTileMode::kMirror);
202}
203
204TEST(DisplayListImageFilter, BlurEquals) {
205 DlBlurImageFilter filter1(5.0, 6.0, DlTileMode::kMirror);
206 DlBlurImageFilter filter2(5.0, 6.0, DlTileMode::kMirror);
207
208 TestEquals(filter1, filter2);
209}
210
211TEST(DisplayListImageFilter, BlurWithLocalMatrixEquals) {
212 DlBlurImageFilter filter1(5.0, 6.0, DlTileMode::kMirror);
213 DlBlurImageFilter filter2(5.0, 6.0, DlTileMode::kMirror);
214
215 DlMatrix local_matrix = DlMatrix::MakeTranslation({10, 10});
216 TestEquals(*filter1.makeWithLocalMatrix(local_matrix),
217 *filter2.makeWithLocalMatrix(local_matrix));
218}
219
220TEST(DisplayListImageFilter, BlurNotEquals) {
221 DlBlurImageFilter filter1(5.0, 6.0, DlTileMode::kMirror);
222 DlBlurImageFilter filter2(7.0, 6.0, DlTileMode::kMirror);
223 DlBlurImageFilter filter3(5.0, 8.0, DlTileMode::kMirror);
224 DlBlurImageFilter filter4(5.0, 6.0, DlTileMode::kRepeat);
225
226 TestNotEquals(filter1, filter2, "Sigma X differs");
227 TestNotEquals(filter1, filter3, "Sigma Y differs");
228 TestNotEquals(filter1, filter4, "Tile Mode differs");
229}
230
231TEST(DisplayListImageFilter, BlurBounds) {
233 DlRect input_bounds = DlRect::MakeLTRB(20, 20, 80, 80);
234 DlRect expected_output_bounds = input_bounds.Expand(15, 30);
235 TestBounds(filter, input_bounds, expected_output_bounds);
236}
237
238TEST(DisplayListImageFilter, BlurZeroSigma) {
239 std::shared_ptr<DlImageFilter> filter =
241 ASSERT_EQ(filter, nullptr);
242 filter = DlImageFilter::MakeBlur(3, SK_ScalarNaN, DlTileMode::kMirror);
243 ASSERT_EQ(filter, nullptr);
244 filter = DlImageFilter::MakeBlur(SK_ScalarNaN, 3, DlTileMode::kMirror);
245 ASSERT_EQ(filter, nullptr);
246 filter =
247 DlImageFilter::MakeBlur(SK_ScalarNaN, SK_ScalarNaN, DlTileMode::kMirror);
248 ASSERT_EQ(filter, nullptr);
250 ASSERT_NE(filter, nullptr);
252 ASSERT_NE(filter, nullptr);
253}
254
255TEST(DisplayListImageFilter, DilateConstructor) {
256 DlDilateImageFilter filter(5.0, 6.0);
257}
258
259TEST(DisplayListImageFilter, DilateShared) {
260 DlDilateImageFilter filter(5.0, 6.0);
261
262 ASSERT_NE(filter.shared().get(), &filter);
263 ASSERT_EQ(*filter.shared(), filter);
264}
265
266TEST(DisplayListImageFilter, DilateAsDilate) {
267 DlDilateImageFilter filter(5.0, 6.0);
268
269 ASSERT_NE(filter.asDilate(), nullptr);
270 ASSERT_EQ(filter.asDilate(), &filter);
271}
272
273TEST(DisplayListImageFilter, DilateContents) {
274 DlDilateImageFilter filter(5.0, 6.0);
275
276 ASSERT_EQ(filter.radius_x(), 5.0);
277 ASSERT_EQ(filter.radius_y(), 6.0);
278}
279
280TEST(DisplayListImageFilter, DilateEquals) {
281 DlDilateImageFilter filter1(5.0, 6.0);
282 DlDilateImageFilter filter2(5.0, 6.0);
283
284 TestEquals(filter1, filter2);
285}
286
287TEST(DisplayListImageFilter, DilateWithLocalMatrixEquals) {
288 DlDilateImageFilter filter1(5.0, 6.0);
289 DlDilateImageFilter filter2(5.0, 6.0);
290
291 DlMatrix local_matrix = DlMatrix::MakeTranslation({10, 10});
292 TestEquals(*filter1.makeWithLocalMatrix(local_matrix),
293 *filter2.makeWithLocalMatrix(local_matrix));
294}
295
296TEST(DisplayListImageFilter, DilateNotEquals) {
297 DlDilateImageFilter filter1(5.0, 6.0);
298 DlDilateImageFilter filter2(7.0, 6.0);
299 DlDilateImageFilter filter3(5.0, 8.0);
300
301 TestNotEquals(filter1, filter2, "Radius X differs");
302 TestNotEquals(filter1, filter3, "Radius Y differs");
303}
304
305TEST(DisplayListImageFilter, DilateBounds) {
307 DlRect input_bounds = DlRect::MakeLTRB(20, 20, 80, 80);
308 DlRect expected_output_bounds = input_bounds.Expand(5, 10);
309 TestBounds(filter, input_bounds, expected_output_bounds);
310}
311
312TEST(DisplayListImageFilter, ErodeConstructor) {
313 DlErodeImageFilter filter(5.0, 6.0);
314}
315
316TEST(DisplayListImageFilter, ErodeShared) {
317 DlErodeImageFilter filter(5.0, 6.0);
318
319 ASSERT_NE(filter.shared().get(), &filter);
320 ASSERT_EQ(*filter.shared(), filter);
321}
322
323TEST(DisplayListImageFilter, ErodeAsErode) {
324 DlErodeImageFilter filter(5.0, 6.0);
325
326 ASSERT_NE(filter.asErode(), nullptr);
327 ASSERT_EQ(filter.asErode(), &filter);
328}
329
330TEST(DisplayListImageFilter, ErodeContents) {
331 DlErodeImageFilter filter(5.0, 6.0);
332
333 ASSERT_EQ(filter.radius_x(), 5.0);
334 ASSERT_EQ(filter.radius_y(), 6.0);
335}
336
337TEST(DisplayListImageFilter, ErodeEquals) {
338 DlErodeImageFilter filter1(5.0, 6.0);
339 DlErodeImageFilter filter2(5.0, 6.0);
340
341 TestEquals(filter1, filter2);
342}
343
344TEST(DisplayListImageFilter, ErodeWithLocalMatrixEquals) {
345 DlErodeImageFilter filter1(5.0, 6.0);
346 DlErodeImageFilter filter2(5.0, 6.0);
347
348 DlMatrix local_matrix = DlMatrix::MakeTranslation({10, 10});
349 TestEquals(*filter1.makeWithLocalMatrix(local_matrix),
350 *filter2.makeWithLocalMatrix(local_matrix));
351}
352
353TEST(DisplayListImageFilter, ErodeNotEquals) {
354 DlErodeImageFilter filter1(5.0, 6.0);
355 DlErodeImageFilter filter2(7.0, 6.0);
356 DlErodeImageFilter filter3(5.0, 8.0);
357
358 TestNotEquals(filter1, filter2, "Radius X differs");
359 TestNotEquals(filter1, filter3, "Radius Y differs");
360}
361
362TEST(DisplayListImageFilter, ErodeBounds) {
364 DlRect input_bounds = DlRect::MakeLTRB(20, 20, 80, 80);
365 DlRect expected_output_bounds = input_bounds.Expand(-5, -10);
366 TestBounds(filter, input_bounds, expected_output_bounds);
367}
368
369TEST(DisplayListImageFilter, MatrixConstructor) {
370 DlMatrixImageFilter filter(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
371 0.5, 3.0, 0.0, 15, //
372 0.0, 0.0, 1.0, 0.0, //
373 0.0, 0.0, 0.0, 1.0),
375}
376
377TEST(DisplayListImageFilter, MatrixShared) {
378 DlMatrixImageFilter filter(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
379 0.5, 3.0, 0.0, 15, //
380 0.0, 0.0, 1.0, 0.0, //
381 0.0, 0.0, 0.0, 1.0),
383
384 ASSERT_NE(filter.shared().get(), &filter);
385 ASSERT_EQ(*filter.shared(), filter);
386}
387
388TEST(DisplayListImageFilter, MatrixAsMatrix) {
389 DlMatrixImageFilter filter(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
390 0.5, 3.0, 0.0, 15, //
391 0.0, 0.0, 1.0, 0.0, //
392 0.0, 0.0, 0.0, 1.0),
394
395 ASSERT_NE(filter.asMatrix(), nullptr);
396 ASSERT_EQ(filter.asMatrix(), &filter);
397}
398
399TEST(DisplayListImageFilter, MatrixContents) {
400 DlMatrix matrix = DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
401 0.5, 3.0, 0.0, 15, //
402 0.0, 0.0, 1.0, 0.0, //
403 0.0, 0.0, 0.0, 1.0);
405
406 ASSERT_EQ(filter.matrix(), matrix);
407 ASSERT_EQ(filter.sampling(), DlImageSampling::kLinear);
408}
409
410TEST(DisplayListImageFilter, MatrixEquals) {
411 DlMatrix matrix = DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
412 0.5, 3.0, 0.0, 15, //
413 0.0, 0.0, 1.0, 0.0, //
414 0.0, 0.0, 0.0, 1.0);
417
418 TestEquals(filter1, filter2);
419}
420
421TEST(DisplayListImageFilter, MatrixWithLocalMatrixEquals) {
422 DlMatrix matrix = DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
423 0.5, 3.0, 0.0, 15, //
424 0.0, 0.0, 1.0, 0.0, //
425 0.0, 0.0, 0.0, 1.0);
428
429 DlMatrix local_matrix = DlMatrix::MakeTranslation({10, 10});
430 TestEquals(*filter1.makeWithLocalMatrix(local_matrix),
431 *filter2.makeWithLocalMatrix(local_matrix));
432}
433
434TEST(DisplayListImageFilter, MatrixNotEquals) {
435 DlMatrix matrix1 = DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
436 0.5, 3.0, 0.0, 15, //
437 0.0, 0.0, 1.0, 0.0, //
438 0.0, 0.0, 0.0, 1.0);
439 DlMatrix matrix2 = DlMatrix::MakeRow(5.0, 0.0, 0.0, 10, //
440 0.5, 3.0, 0.0, 15, //
441 0.0, 0.0, 1.0, 0.0, //
442 0.0, 0.0, 0.0, 1.0);
446
447 TestNotEquals(filter1, filter2, "Matrix differs");
448 TestNotEquals(filter1, filter3, "Sampling differs");
449}
450
451TEST(DisplayListImageFilter, MatrixBounds) {
452 DlMatrix matrix = DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
453 0.5, 3.0, 0.0, 7, //
454 0.0, 0.0, 1.0, 0.0, //
455 0.0, 0.0, 0.0, 1.0);
456 EXPECT_TRUE(matrix.IsInvertible());
458 DlRect input_bounds = DlRect::MakeLTRB(20, 20, 80, 80);
459 DlQuad expectedOutputQuad = {
460 DlPoint(50, 77), // == (20,20) => (20*2 + 10, 20/2 + 20*3 + 7)
461 DlPoint(50, 257), // == (20,80) => (20*2 + 10, 20/2 + 80*3 + 7)
462 DlPoint(170, 287), // == (80,80) => (80*2 + 10, 80/2 + 80*3 + 7)
463 DlPoint(170, 107), // == (80,20) => (80*2 + 10, 80/2 + 20*3 + 7)
464 };
465 TestBounds(filter, input_bounds, expectedOutputQuad);
466}
467
468TEST(DisplayListImageFilter, ComposeConstructor) {
469 DlMatrixImageFilter outer(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
470 0.5, 3.0, 0.0, 15, //
471 0.0, 0.0, 1.0, 0.0, //
472 0.0, 0.0, 0.0, 1.0),
474 DlBlurImageFilter inner(5.0, 6.0, DlTileMode::kMirror);
475 DlComposeImageFilter filter(outer, inner);
476}
477
478TEST(DisplayListImageFilter, ComposeShared) {
479 DlMatrixImageFilter outer(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
480 0.5, 3.0, 0.0, 15, //
481 0.0, 0.0, 1.0, 0.0, //
482 0.0, 0.0, 0.0, 1.0),
484 DlBlurImageFilter inner(5.0, 6.0, DlTileMode::kMirror);
485 DlComposeImageFilter filter(outer, inner);
486
487 ASSERT_NE(filter.shared().get(), &filter);
488 ASSERT_EQ(*filter.shared(), filter);
489}
490
491TEST(DisplayListImageFilter, ComposeAsCompose) {
492 DlMatrixImageFilter outer(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
493 0.5, 3.0, 0.0, 15, //
494 0.0, 0.0, 1.0, 0.0, //
495 0.0, 0.0, 0.0, 1.0),
497 DlBlurImageFilter inner(5.0, 6.0, DlTileMode::kMirror);
498 DlComposeImageFilter filter(outer, inner);
499
500 ASSERT_NE(filter.asCompose(), nullptr);
501 ASSERT_EQ(filter.asCompose(), &filter);
502}
503
504TEST(DisplayListImageFilter, ComposeContents) {
505 DlMatrixImageFilter outer(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
506 0.5, 3.0, 0.0, 15, //
507 0.0, 0.0, 1.0, 0.0, //
508 0.0, 0.0, 0.0, 1.0),
510 DlBlurImageFilter inner(5.0, 6.0, DlTileMode::kMirror);
511 DlComposeImageFilter filter(outer, inner);
512
513 ASSERT_EQ(*filter.outer().get(), outer);
514 ASSERT_EQ(*filter.inner().get(), inner);
515}
516
517TEST(DisplayListImageFilter, ComposeEquals) {
518 DlMatrixImageFilter outer1(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
519 0.5, 3.0, 0.0, 15, //
520 0.0, 0.0, 1.0, 0.0, //
521 0.0, 0.0, 0.0, 1.0),
523 DlBlurImageFilter inner1(5.0, 6.0, DlTileMode::kMirror);
524 DlComposeImageFilter filter1(outer1, inner1);
525
526 DlMatrixImageFilter outer2(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
527 0.5, 3.0, 0.0, 15, //
528 0.0, 0.0, 1.0, 0.0, //
529 0.0, 0.0, 0.0, 1.0),
531 DlBlurImageFilter inner2(5.0, 6.0, DlTileMode::kMirror);
532 DlComposeImageFilter filter2(outer1, inner1);
533
534 TestEquals(filter1, filter2);
535}
536
537TEST(DisplayListImageFilter, ComposeWithLocalMatrixEquals) {
538 DlMatrixImageFilter outer1(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
539 0.5, 3.0, 0.0, 15, //
540 0.0, 0.0, 1.0, 0.0, //
541 0.0, 0.0, 0.0, 1.0),
543 DlBlurImageFilter inner1(5.0, 6.0, DlTileMode::kMirror);
544 DlComposeImageFilter filter1(outer1, inner1);
545
546 DlMatrixImageFilter outer2(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
547 0.5, 3.0, 0.0, 15, //
548 0.0, 0.0, 1.0, 0.0, //
549 0.0, 0.0, 0.0, 1.0),
551 DlBlurImageFilter inner2(5.0, 6.0, DlTileMode::kMirror);
552 DlComposeImageFilter filter2(outer1, inner1);
553
554 DlMatrix local_matrix = DlMatrix::MakeTranslation({10, 10});
555 TestEquals(*filter1.makeWithLocalMatrix(local_matrix),
556 *filter2.makeWithLocalMatrix(local_matrix));
557}
558
559TEST(DisplayListImageFilter, ComposeNotEquals) {
560 DlMatrixImageFilter outer1(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
561 0.5, 3.0, 0.0, 15, //
562 0.0, 0.0, 1.0, 0.0, //
563 0.0, 0.0, 0.0, 1.0),
565 DlBlurImageFilter inner1(5.0, 6.0, DlTileMode::kMirror);
566
567 DlMatrixImageFilter outer2(DlMatrix::MakeRow(5.0, 0.0, 0.0, 10, //
568 0.5, 3.0, 0.0, 15, //
569 0.0, 0.0, 1.0, 0.0, //
570 0.0, 0.0, 0.0, 1.0),
572 DlBlurImageFilter inner2(7.0, 6.0, DlTileMode::kMirror);
573
574 DlComposeImageFilter filter1(outer1, inner1);
575 DlComposeImageFilter filter2(outer2, inner1);
576 DlComposeImageFilter filter3(outer1, inner2);
577
578 TestNotEquals(filter1, filter2, "Outer differs");
579 TestNotEquals(filter1, filter3, "Inner differs");
580}
581
582TEST(DisplayListImageFilter, ComposeBounds) {
585 DlComposeImageFilter filter = DlComposeImageFilter(outer, inner);
586 DlRect input_bounds = DlRect::MakeLTRB(20, 20, 80, 80);
587 DlRect expected_output_bounds = input_bounds.Expand(36, 15).Expand(5, 10);
588 TestBounds(filter, input_bounds, expected_output_bounds);
589}
590
592 const DlRect& sourceBounds,
593 const DlRect& expectedOutputBounds,
594 const DlRect& expectedInputBounds) {
595 DlRect bounds;
596 EXPECT_EQ(filter.map_local_bounds(sourceBounds, bounds), nullptr);
597 EXPECT_EQ(bounds, expectedOutputBounds);
598
599 DlIRect ibounds;
600 EXPECT_EQ(filter.map_device_bounds(DlIRect::RoundOut(sourceBounds),
601 DlMatrix(), ibounds),
602 nullptr);
603 EXPECT_EQ(ibounds, DlIRect::RoundOut(expectedOutputBounds));
604
605 EXPECT_EQ(filter.get_input_device_bounds(DlIRect::RoundOut(sourceBounds),
606 DlMatrix(), ibounds),
607 nullptr);
608 EXPECT_EQ(ibounds, DlIRect::RoundOut(expectedInputBounds));
609}
610
611TEST(DisplayListImageFilter, ComposeBoundsWithUnboundedInner) {
612 auto input_bounds = DlRect::MakeLTRB(20, 20, 80, 80);
613 auto expected_bounds = DlRect::MakeLTRB(5, 2, 95, 98);
614
615 DlBlendColorFilter color_filter(DlColor::kRed(), DlBlendMode::kSrcOver);
616 auto outer = DlBlurImageFilter(5.0, 6.0, DlTileMode::kRepeat);
617 auto inner = DlColorFilterImageFilter(color_filter.shared());
618 auto composed = DlComposeImageFilter(outer.shared(), inner.shared());
619
620 TestUnboundedBounds(composed, input_bounds, expected_bounds, expected_bounds);
621}
622
623TEST(DisplayListImageFilter, ComposeBoundsWithUnboundedOuter) {
624 auto input_bounds = DlRect::MakeLTRB(20, 20, 80, 80);
625 auto expected_bounds = DlRect::MakeLTRB(5, 2, 95, 98);
626
627 DlBlendColorFilter color_filter(DlColor::kRed(), DlBlendMode::kSrcOver);
628 auto outer = DlColorFilterImageFilter(color_filter.shared());
629 auto inner = DlBlurImageFilter(5.0, 6.0, DlTileMode::kRepeat);
630 auto composed = DlComposeImageFilter(outer.shared(), inner.shared());
631
632 TestUnboundedBounds(composed, input_bounds, expected_bounds, expected_bounds);
633}
634
635TEST(DisplayListImageFilter, ComposeBoundsWithUnboundedInnerAndOuter) {
636 auto input_bounds = DlRect::MakeLTRB(20, 20, 80, 80);
637 auto expected_bounds = input_bounds;
638
639 DlBlendColorFilter color_filter1(DlColor::kRed(), DlBlendMode::kSrcOver);
640 DlBlendColorFilter color_filter2(DlColor::kBlue(), DlBlendMode::kSrcOver);
641 auto outer = DlColorFilterImageFilter(color_filter1.shared());
642 auto inner = DlColorFilterImageFilter(color_filter2.shared());
643 auto composed = DlComposeImageFilter(outer.shared(), inner.shared());
644
645 TestUnboundedBounds(composed, input_bounds, expected_bounds, expected_bounds);
646}
647
648// See https://github.com/flutter/flutter/issues/108433
649TEST(DisplayListImageFilter, Issue108433) {
650 auto input_bounds = DlIRect::MakeLTRB(20, 20, 80, 80);
651 auto expected_bounds = DlIRect::MakeLTRB(5, 2, 95, 98);
652
653 DlBlendColorFilter dl_color_filter(DlColor::kRed(), DlBlendMode::kSrcOver);
654 auto dl_outer = DlBlurImageFilter(5.0, 6.0, DlTileMode::kRepeat);
655 auto dl_inner = DlColorFilterImageFilter(dl_color_filter.shared());
656 auto dl_compose = DlComposeImageFilter(dl_outer, dl_inner);
657
658 DlIRect dl_bounds;
659 ASSERT_EQ(dl_compose.map_device_bounds(input_bounds, DlMatrix(), dl_bounds),
660 nullptr);
661 ASSERT_EQ(dl_bounds, expected_bounds);
662}
663
664TEST(DisplayListImageFilter, ColorFilterConstructor) {
665 DlBlendColorFilter dl_color_filter(DlColor::kRed(), DlBlendMode::kLighten);
666 DlColorFilterImageFilter filter(dl_color_filter);
667}
668
669TEST(DisplayListImageFilter, ColorFilterShared) {
670 DlBlendColorFilter dl_color_filter(DlColor::kRed(), DlBlendMode::kLighten);
671 DlColorFilterImageFilter filter(dl_color_filter);
672
673 ASSERT_EQ(*filter.shared(), filter);
674}
675
676TEST(DisplayListImageFilter, ColorFilterAsColorFilter) {
677 DlBlendColorFilter dl_color_filter(DlColor::kRed(), DlBlendMode::kLighten);
678 DlColorFilterImageFilter filter(dl_color_filter);
679
680 ASSERT_NE(filter.asColorFilter(), nullptr);
681 ASSERT_EQ(filter.asColorFilter(), &filter);
682}
683
684TEST(DisplayListImageFilter, ColorFilterContents) {
685 DlBlendColorFilter dl_color_filter(DlColor::kRed(), DlBlendMode::kLighten);
686 DlColorFilterImageFilter filter(dl_color_filter);
687
688 ASSERT_EQ(*filter.color_filter().get(), dl_color_filter);
689}
690
691TEST(DisplayListImageFilter, ColorFilterEquals) {
692 DlBlendColorFilter dl_color_filter1(DlColor::kRed(), DlBlendMode::kLighten);
693 DlColorFilterImageFilter filter1(dl_color_filter1);
694
695 DlBlendColorFilter dl_color_filter2(DlColor::kRed(), DlBlendMode::kLighten);
696 DlColorFilterImageFilter filter2(dl_color_filter2);
697
698 TestEquals(filter1, filter2);
699}
700
701TEST(DisplayListImageFilter, ColorFilterWithLocalMatrixEquals) {
702 DlBlendColorFilter dl_color_filter1(DlColor::kRed(), DlBlendMode::kLighten);
703 DlColorFilterImageFilter filter1(dl_color_filter1);
704
705 DlBlendColorFilter dl_color_filter2(DlColor::kRed(), DlBlendMode::kLighten);
706 DlColorFilterImageFilter filter2(dl_color_filter2);
707
708 DlMatrix local_matrix = DlMatrix::MakeTranslation({10, 10});
709 TestEquals(*filter1.makeWithLocalMatrix(local_matrix),
710 *filter2.makeWithLocalMatrix(local_matrix));
711}
712
713TEST(DisplayListImageFilter, ColorFilterNotEquals) {
714 DlBlendColorFilter dl_color_filter1(DlColor::kRed(), DlBlendMode::kLighten);
715 DlColorFilterImageFilter filter1(dl_color_filter1);
716
717 DlBlendColorFilter dl_color_filter2(DlColor::kBlue(), DlBlendMode::kLighten);
718 DlColorFilterImageFilter filter2(dl_color_filter2);
719
720 DlBlendColorFilter dl_color_filter3(DlColor::kRed(), DlBlendMode::kDarken);
721 DlColorFilterImageFilter filter3(dl_color_filter3);
722
723 TestNotEquals(filter1, filter2, "Color differs");
724 TestNotEquals(filter1, filter3, "Blend Mode differs");
725}
726
727TEST(DisplayListImageFilter, ColorFilterBounds) {
728 DlBlendColorFilter dl_color_filter(DlColor::kRed(), DlBlendMode::kSrcIn);
729 DlColorFilterImageFilter filter(dl_color_filter);
730 DlRect input_bounds = DlRect::MakeLTRB(20, 20, 80, 80);
731 TestBounds(filter, input_bounds, input_bounds);
732}
733
734TEST(DisplayListImageFilter, ColorFilterModifiesTransparencyBounds) {
735 DlBlendColorFilter dl_color_filter(DlColor::kRed(), DlBlendMode::kSrcOver);
736 DlColorFilterImageFilter filter(dl_color_filter);
737 DlRect input_bounds = DlRect::MakeLTRB(20, 20, 80, 80);
738 TestInvalidBounds(filter, DlMatrix(), input_bounds);
739}
740
741TEST(DisplayListImageFilter, LocalImageFilterBounds) {
742 auto filter_matrix = DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, //
743 0.5, 3.0, 0.0, 15, //
744 0.0, 0.0, 1.0, 0.0, //
745 0.0, 0.0, 0.0, 1.0);
746 std::vector<sk_sp<SkImageFilter>> sk_filters{
747 SkImageFilters::Blur(5.0, 6.0, SkTileMode::kRepeat, nullptr),
748 SkImageFilters::ColorFilter(
749 SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcOver), nullptr),
750 SkImageFilters::Dilate(5.0, 10.0, nullptr),
751 SkImageFilters::MatrixTransform(ToSkMatrix(filter_matrix),
752 SkSamplingOptions(SkFilterMode::kLinear),
753 nullptr),
754 SkImageFilters::Compose(
755 SkImageFilters::Blur(5.0, 6.0, SkTileMode::kRepeat, nullptr),
756 SkImageFilters::ColorFilter(
757 SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcOver),
758 nullptr))};
759
760 DlBlendColorFilter dl_color_filter(DlColor::kRed(), DlBlendMode::kSrcOver);
761 std::vector<std::shared_ptr<DlImageFilter>> dl_filters{
763 DlImageFilter::MakeColorFilter(dl_color_filter.shared()),
768 DlImageFilter::MakeColorFilter(dl_color_filter.shared())),
769 };
770
771 auto persp = SkMatrix::I();
772 persp.setPerspY(0.001);
773 std::vector<SkMatrix> sk_matrices = {
774 SkMatrix::Translate(10.0, 10.0),
775 SkMatrix::Scale(2.0, 2.0).preTranslate(10.0, 10.0),
776 SkMatrix::RotateDeg(45).preTranslate(5.0, 5.0), //
777 persp};
778 std::vector<DlMatrix> dl_matrices = {
779 DlMatrix::MakeTranslation({10.0, 10.0}),
780 DlMatrix::MakeScale({2.0, 2.0, 1.0}).Translate({10.0, 10.0}),
782 ToDlMatrix(persp)};
783 std::vector<SkMatrix> sk_bounds_matrices{
784 SkMatrix::Translate(5.0, 10.0),
785 SkMatrix::Scale(2.0, 2.0),
786 };
787 std::vector<DlMatrix> dl_bounds_matrices{
788 DlMatrix::MakeTranslation({5.0, 10.0}),
789 DlMatrix::MakeScale({2.0, 2.0, 1.0}),
790 };
791
792 for (unsigned j = 0; j < dl_matrices.size(); j++) {
793 DlLocalMatrixImageFilter filter(dl_matrices[j], nullptr);
794 {
795 const auto input_bounds = DlRect::MakeLTRB(20, 20, 80, 80);
796 DlRect output_bounds;
797 EXPECT_EQ(filter.map_local_bounds(input_bounds, output_bounds),
798 &output_bounds);
799 EXPECT_EQ(input_bounds, output_bounds);
800 }
801 for (unsigned k = 0; k < dl_bounds_matrices.size(); k++) {
802 auto& bounds_matrix = dl_bounds_matrices[k];
803 {
804 const auto input_bounds = DlIRect::MakeLTRB(20, 20, 80, 80);
805 DlIRect output_bounds;
806 EXPECT_EQ(filter.map_device_bounds(input_bounds, bounds_matrix,
807 output_bounds),
808 &output_bounds);
809 EXPECT_EQ(input_bounds, output_bounds);
810 }
811 {
812 const auto output_bounds = DlIRect::MakeLTRB(20, 20, 80, 80);
813 DlIRect input_bounds;
814 EXPECT_EQ(filter.get_input_device_bounds(output_bounds, bounds_matrix,
815 input_bounds),
816 &input_bounds);
817 EXPECT_EQ(input_bounds, output_bounds);
818 }
819 }
820 }
821
822 for (unsigned i = 0; i < sk_filters.size(); i++) {
823 for (unsigned j = 0; j < dl_matrices.size(); j++) {
824 for (unsigned k = 0; k < dl_bounds_matrices.size(); k++) {
825 auto desc = "filter " + std::to_string(i + 1) //
826 + ", filter matrix " + std::to_string(j + 1) //
827 + ", bounds matrix " + std::to_string(k + 1);
828 auto sk_local_filter =
829 sk_filters[i]->makeWithLocalMatrix(sk_matrices[j]);
830 auto dl_local_filter =
831 dl_filters[i]->makeWithLocalMatrix(dl_matrices[j]);
832 if (!sk_local_filter || !dl_local_filter) {
833 // Temporarily relax the equivalence testing to allow Skia to expand
834 // their behavior. Once the Skia fixes are rolled in, the
835 // DlImageFilter should adapt to the new rules.
836 // See https://github.com/flutter/flutter/issues/114723
837 ASSERT_TRUE(sk_local_filter || !dl_local_filter) << desc;
838 continue;
839 }
840 {
841 auto input_bounds = SkIRect::MakeLTRB(20, 20, 80, 80);
842 SkIRect sk_rect;
843 DlIRect dl_rect;
844 sk_rect = sk_local_filter->filterBounds(
845 input_bounds, sk_bounds_matrices[k],
846 SkImageFilter::MapDirection::kForward_MapDirection);
847 if (dl_local_filter->map_device_bounds(
848 ToDlIRect(input_bounds), dl_bounds_matrices[k], dl_rect)) {
849 ASSERT_EQ(sk_rect, ToSkIRect(dl_rect)) << desc;
850 } else {
851 ASSERT_TRUE(dl_local_filter->modifies_transparent_black()) << desc;
852 ASSERT_FALSE(sk_local_filter->canComputeFastBounds()) << desc;
853 }
854 }
855 {
856 // Test for: Know the outset bounds to get the inset bounds
857 // Skia have some bounds calculate error of DilateFilter and
858 // MatrixFilter
859 // Skia issue: https://bugs.chromium.org/p/skia/issues/detail?id=13444
860 // flutter issue: https://github.com/flutter/flutter/issues/108693
861 if (i == 2 || i == 3) {
862 continue;
863 }
864 auto outset_bounds = SkIRect::MakeLTRB(20, 20, 80, 80);
865 SkIRect sk_rect;
866 DlIRect dl_rect;
867 sk_rect = sk_local_filter->filterBounds(
868 outset_bounds, sk_bounds_matrices[k],
869 SkImageFilter::MapDirection::kReverse_MapDirection);
870 if (dl_local_filter->get_input_device_bounds(
871 ToDlIRect(outset_bounds), dl_bounds_matrices[k], dl_rect)) {
872 ASSERT_EQ(sk_rect, ToSkIRect(dl_rect)) << desc;
873 } else {
874 ASSERT_TRUE(dl_local_filter->modifies_transparent_black());
875 ASSERT_FALSE(sk_local_filter->canComputeFastBounds());
876 }
877 }
878 }
879 }
880 }
881}
882
883TEST(DisplayListImageFilter, RuntimeEffectEquality) {
884 DlRuntimeEffectImageFilter filter_a(nullptr, {nullptr},
885 std::make_shared<std::vector<uint8_t>>());
886 DlRuntimeEffectImageFilter filter_b(nullptr, {nullptr},
887 std::make_shared<std::vector<uint8_t>>());
888
889 EXPECT_EQ(filter_a, filter_b);
890
892 nullptr, {nullptr}, std::make_shared<std::vector<uint8_t>>(1));
893
894 EXPECT_NE(filter_a, filter_c);
895}
896
897TEST(DisplayListImageFilter, RuntimeEffectEqualityWithSamplers) {
898 auto image_a =
900 auto image_b =
902
903 DlRuntimeEffectImageFilter filter_a(nullptr, {nullptr, image_a},
904 std::make_shared<std::vector<uint8_t>>());
905 DlRuntimeEffectImageFilter filter_b(nullptr, {nullptr, image_a},
906 std::make_shared<std::vector<uint8_t>>());
907
908 EXPECT_EQ(filter_a, filter_b);
909
910 DlRuntimeEffectImageFilter filter_c(nullptr, {nullptr, image_b},
911 std::make_shared<std::vector<uint8_t>>());
912
913 EXPECT_NE(filter_a, filter_c);
914}
915
916TEST(DisplayListImageFilter, RuntimeEffectMapDeviceBounds) {
917 DlRuntimeEffectImageFilter filter_a(nullptr, {nullptr},
918 std::make_shared<std::vector<uint8_t>>());
919
920 auto input_bounds = DlIRect::MakeLTRB(0, 0, 100, 100);
921 DlMatrix identity;
922 DlIRect output_bounds;
923 DlIRect* result =
924 filter_a.map_device_bounds(input_bounds, identity, output_bounds);
925
926 EXPECT_NE(result, nullptr);
927 EXPECT_EQ(result, &output_bounds);
928 EXPECT_EQ(output_bounds, input_bounds);
929}
930
931TEST(DisplayListImageFilter, RuntimeEffectMapInputBounds) {
932 DlRuntimeEffectImageFilter filter_a(nullptr, {nullptr},
933 std::make_shared<std::vector<uint8_t>>());
934
935 auto input_bounds = DlRect::MakeLTRB(0, 0, 100, 100);
936
937 DlRect output_bounds;
938 DlRect* result = filter_a.map_local_bounds(input_bounds, output_bounds);
939
940 EXPECT_NE(result, nullptr);
941 EXPECT_EQ(result, &output_bounds);
942 EXPECT_EQ(output_bounds, input_bounds);
943}
944
945TEST(DisplayListImageFilter, RuntimeEffectGetInputDeviceBounds) {
946 DlRuntimeEffectImageFilter filter_a(nullptr, {nullptr},
947 std::make_shared<std::vector<uint8_t>>());
948
949 auto output_bounds = DlIRect::MakeLTRB(0, 0, 100, 100);
950
951 DlMatrix identity;
952 DlIRect input_bounds;
953 DlIRect* result =
954 filter_a.get_input_device_bounds(output_bounds, identity, input_bounds);
955
956 EXPECT_NE(result, nullptr);
957 EXPECT_EQ(result, &input_bounds);
958 EXPECT_EQ(output_bounds, input_bounds);
959}
960
961TEST(DisplayListImageFilter, RuntimeEffectModifiesTransparentBlack) {
962 DlRuntimeEffectImageFilter filter_a(nullptr, {nullptr},
963 std::make_shared<std::vector<uint8_t>>());
964
965 EXPECT_FALSE(filter_a.modifies_transparent_black());
966}
967
968} // namespace testing
969} // namespace flutter
std::shared_ptr< DlColorFilter > shared() const override
std::shared_ptr< DlImageFilter > shared() const override
const DlBlurImageFilter * asBlur() const override
const std::shared_ptr< const DlColorFilter > color_filter() const
const DlColorFilterImageFilter * asColorFilter() const override
std::shared_ptr< DlImageFilter > shared() const override
static std::shared_ptr< DlColorSource > MakeImage(const sk_sp< const DlImage > &image, DlTileMode horizontal_tile_mode, DlTileMode vertical_tile_mode, DlImageSampling sampling=DlImageSampling::kLinear, const DlMatrix *matrix=nullptr)
std::shared_ptr< DlImageFilter > shared() const override
std::shared_ptr< DlImageFilter > inner() const
std::shared_ptr< DlImageFilter > outer() const
const DlComposeImageFilter * asCompose() const override
const DlDilateImageFilter * asDilate() const override
std::shared_ptr< DlImageFilter > shared() const override
const DlErodeImageFilter * asErode() const override
std::shared_ptr< DlImageFilter > shared() const override
static std::shared_ptr< DlImageFilter > MakeDilate(DlScalar radius_x, DlScalar radius_y)
virtual std::shared_ptr< DlImageFilter > makeWithLocalMatrix(const DlMatrix &matrix) const
virtual DlIRect * map_device_bounds(const DlIRect &input_bounds, const DlMatrix &ctm, DlIRect &output_bounds) const =0
static std::shared_ptr< DlImageFilter > MakeBlur(DlScalar sigma_x, DlScalar sigma_y, DlTileMode tile_mode)
static std::shared_ptr< DlImageFilter > MakeColorFilter(const std::shared_ptr< const DlColorFilter > &filter)
virtual DlRect * map_local_bounds(const DlRect &input_bounds, DlRect &output_bounds) const =0
static std::shared_ptr< DlImageFilter > MakeMatrix(const DlMatrix &matrix, DlImageSampling sampling)
static std::shared_ptr< DlImageFilter > MakeCompose(const std::shared_ptr< DlImageFilter > &outer, const std::shared_ptr< DlImageFilter > &inner)
virtual DlIRect * get_input_device_bounds(const DlIRect &output_bounds, const DlMatrix &ctm, DlIRect &input_bounds) const =0
DlIRect * map_device_bounds(const DlIRect &input_bounds, const DlMatrix &ctm, DlIRect &output_bounds) const override
DlIRect * get_input_device_bounds(const DlIRect &output_bounds, const DlMatrix &ctm, DlIRect &input_bounds) const override
DlRect * map_local_bounds(const DlRect &input_bounds, DlRect &output_bounds) const override
const DlMatrixImageFilter * asMatrix() const override
std::shared_ptr< DlImageFilter > shared() const override
const DlMatrix & matrix() const
DlIRect * map_device_bounds(const DlIRect &input_bounds, const DlMatrix &ctm, DlIRect &output_bounds) const override
DlRect * map_local_bounds(const DlRect &input_bounds, DlRect &output_bounds) const override
DlIRect * get_input_device_bounds(const DlIRect &output_bounds, const DlMatrix &ctm, DlIRect &input_bounds) const override
SkRect sk_rect
static void TestBoundsWithMatrix(const DlImageFilter &filter, const DlMatrix &matrix, const DlRect &sourceBounds, const DlQuad &expectedLocalOutputQuad)
static void TestBounds(const DlImageFilter &filter, const DlRect &sourceBounds, const DlQuad &expectedLocalOutputQuad)
static void TestEquals(const T &source1, const U &source2)
static void TestInvalidBounds(const DlImageFilter &filter, const DlMatrix &matrix, const DlRect &localInputBounds)
static void TestNotEquals(T &source1, U &source2, const std::string &label)
TEST(NativeAssetsManagerTest, NoAvailableAssets)
static void TestUnboundedBounds(DlImageFilter &filter, const DlRect &sourceBounds, const DlRect &expectedOutputBounds, const DlRect &expectedInputBounds)
static bool containsInclusive(const DlRect rect, const DlPoint p)
impeller::Scalar DlScalar
impeller::Matrix DlMatrix
impeller::Degrees DlDegrees
const SkIRect & ToSkIRect(const DlIRect &rect)
SkMatrix ToSkMatrix(const DlMatrix &matrix)
const DlIRect & ToDlIRect(const SkIRect &rect)
impeller::Quad DlQuad
DlMatrix ToDlMatrix(const SkMatrix &matrix)
impeller::Point DlPoint
static constexpr DlColor kBlue()
Definition dl_color.h:73
static constexpr DlColor kRed()
Definition dl_color.h:71
A 4x4 matrix using column-major storage.
Definition matrix.h:37
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition matrix.h:95
Scalar m[16]
Definition matrix.h:39
constexpr Matrix Translate(const Vector3 &t) const
Definition matrix.h:263
bool IsInvertible() const
Definition matrix.h:321
constexpr bool HasPerspective2D() const
Definition matrix.h:414
static constexpr Matrix MakeRow(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
Definition matrix.h:83
static constexpr Matrix MakeSkew(Scalar sx, Scalar sy)
Definition matrix.h:127
constexpr Quad Transform(const Quad &quad) const
Definition matrix.h:623
constexpr Matrix Scale(const Vector3 &s) const
Definition matrix.h:275
static Matrix MakeRotationZ(Radians r)
Definition matrix.h:223
static constexpr Matrix MakeScale(const Vector3 &s)
Definition matrix.h:104
constexpr auto GetBottom() const
Definition rect.h:357
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
Definition rect.h:472
constexpr auto GetTop() const
Definition rect.h:353
constexpr std::array< TPoint< T >, 4 > GetPoints() const
Get the points that represent the 4 corners of this rectangle in a Z order that is compatible with tr...
Definition rect.h:414
static constexpr std::enable_if_t< std::is_floating_point_v< FT >, TRect > Make(const TRect< U > &rect)
Definition rect.h:157
constexpr auto GetLeft() const
Definition rect.h:351
RoundOut(const TRect< U > &r)
Definition rect.h:679
constexpr auto GetRight() const
Definition rect.h:355
constexpr TRect TransformAndClipBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle, clipped against the near clippin...
Definition rect.h:438
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
Definition rect.h:618
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129