| Flutter Impeller |

dl_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
5 #include <array>
6 #include <cmath>
7 #include <memory>
8 #include <vector>
9
10 #include "flutter/display_list/dl_blend_mode.h"
11 #include "flutter/display_list/dl_builder.h"
12 #include "flutter/display_list/dl_color.h"
13 #include "flutter/display_list/dl_paint.h"
14 #include "flutter/display_list/dl_text_skia.h"
15 #include "flutter/display_list/dl_tile_mode.h"
16 #include "flutter/display_list/effects/dl_color_filter.h"
17 #include "flutter/display_list/effects/dl_color_source.h"
18 #include "flutter/display_list/effects/dl_image_filters.h"
19 #include "flutter/display_list/effects/dl_mask_filter.h"
20 #include "flutter/display_list/geometry/dl_path_builder.h"
21 #include "flutter/testing/testing.h"
22 #include "gtest/gtest.h"
23 #include "impeller/display_list/aiks_context.h"
24 #include "impeller/display_list/dl_dispatcher.h"
25 #include "impeller/display_list/dl_image_impeller.h"
26 #include "impeller/display_list/dl_playground.h"
27 #include "impeller/entity/contents/clip_contents.h"
28 #include "impeller/entity/contents/solid_color_contents.h"
29 #include "impeller/entity/contents/solid_rrect_blur_contents.h"
30 #include "impeller/geometry/constants.h"
31 #include "impeller/geometry/point.h"
32 #include "impeller/geometry/scalar.h"
33 #include "impeller/playground/widgets.h"
34 #include "third_party/imgui/imgui.h"
35
36 namespace impeller {
37 namespace testing {
38
39 flutter::DlColor toColor(const float* components) {
40 return flutter::DlColor(Color::ToIColor(
41 Color(components[0], components[1], components[2], components[3])));
42 }
43
44 using DisplayListTest = DlPlayground;
45 INSTANTIATE_PLAYGROUND_SUITE(DisplayListTest);
46
47 TEST_P(DisplayListTest, CanDrawRect) {
48 flutter::DisplayListBuilder builder;
49 builder.DrawRect(DlRect::MakeXYWH(10, 10, 100, 100),
50 flutter::DlPaint(flutter::DlColor::kBlue()));
51 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
52 }
53
54 TEST_P(DisplayListTest, CanDrawTextBlob) {
55 flutter::DisplayListBuilder builder;
56 builder.DrawText(flutter::DlTextSkia::Make(
57 SkTextBlob::MakeFromString("Hello", CreateTestFont())),
58 100, 100, flutter::DlPaint(flutter::DlColor::kBlue()));
59 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
60 }
61
62 TEST_P(DisplayListTest, CanDrawTextBlobWithGradient) {
63 flutter::DisplayListBuilder builder;
64
65 std::vector<flutter::DlColor> colors = {flutter::DlColor::kBlue(),
66 flutter::DlColor::kRed()};
67 const float stops[2] = {0.0, 1.0};
68
69 auto linear = flutter::DlColorSource::MakeLinear({0.0, 0.0}, {300.0, 300.0},
70 2, colors.data(), stops,
71 flutter::DlTileMode::kClamp);
72 flutter::DlPaint paint;
73 paint.setColorSource(linear);
74
75 builder.DrawText(flutter::DlTextSkia::Make(SkTextBlob::MakeFromString(
76 "Hello World", CreateTestFont())),
77 100, 100, paint);
78 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
79 }
80
81 TEST_P(DisplayListTest, CanDrawTextWithSaveLayer) {
82 flutter::DisplayListBuilder builder;
83 builder.DrawText(flutter::DlTextSkia::Make(
84 SkTextBlob::MakeFromString("Hello", CreateTestFont())),
85 100, 100, flutter::DlPaint(flutter::DlColor::kRed()));
86
87 flutter::DlPaint save_paint;
88 float alpha = 0.5;
89 save_paint.setAlpha(static_cast<uint8_t>(255 * alpha));
90 builder.SaveLayer(std::nullopt, &save_paint);
91 builder.DrawText(flutter::DlTextSkia::Make(SkTextBlob::MakeFromString(
92 "Hello with half alpha", CreateTestFontOfSize(100))),
93 100, 300, flutter::DlPaint(flutter::DlColor::kRed()));
94 builder.Restore();
95 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
96 }
97
98 TEST_P(DisplayListTest, CanDrawImage) {
99 auto texture = CreateTextureForFixture("embarcadero.jpg");
100 flutter::DisplayListBuilder builder;
101 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
102 flutter::DlImageSampling::kNearestNeighbor, nullptr);
103 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
104 }
105
106 TEST_P(DisplayListTest, CanDrawCapsAndJoins) {
107 flutter::DisplayListBuilder builder;
108 flutter::DlPaint paint;
109
110 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
111 paint.setStrokeWidth(30);
112 paint.setColor(flutter::DlColor::kRed());
113
114 flutter::DlPathBuilder path_builder;
115 path_builder.MoveTo(DlPoint(-50, 0));
116 path_builder.LineTo(DlPoint(0, -50));
117 path_builder.LineTo(DlPoint(50, 0));
118 flutter::DlPath path = path_builder.TakePath();
119
120 builder.Translate(100, 100);
121 {
122 paint.setStrokeCap(flutter::DlStrokeCap::kButt);
123 paint.setStrokeJoin(flutter::DlStrokeJoin::kMiter);
124 paint.setStrokeMiter(4);
125 builder.DrawPath(path, paint);
126 }
127
128 {
129 builder.Save();
130 builder.Translate(0, 100);
131 // The joint in the path is 45 degrees. A miter length of 1 convert to a
132 // bevel in this case.
133 paint.setStrokeMiter(1);
134 builder.DrawPath(path, paint);
135 builder.Restore();
136 }
137
138 builder.Translate(150, 0);
139 {
140 paint.setStrokeCap(flutter::DlStrokeCap::kSquare);
141 paint.setStrokeJoin(flutter::DlStrokeJoin::kBevel);
142 builder.DrawPath(path, paint);
143 }
144
145 builder.Translate(150, 0);
146 {
147 paint.setStrokeCap(flutter::DlStrokeCap::kRound);
148 paint.setStrokeJoin(flutter::DlStrokeJoin::kRound);
149 builder.DrawPath(path, paint);
150 }
151
152 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
153 }
154
155 TEST_P(DisplayListTest, CanDrawArc) {
156 auto callback = [&]() {
157 static float start_angle = 45;
158 static float sweep_angle = 270;
159 static float stroke_width = 10;
160 static bool use_center = true;
161
162 static int selected_cap = 0;
163 const char* cap_names[] = {"Butt", "Round", "Square"};
164 flutter::DlStrokeCap cap;
165
166 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
167 ImGui::SliderFloat("Start angle", &start_angle, -360, 360);
168 ImGui::SliderFloat("Sweep angle", &sweep_angle, -360, 360);
169 ImGui::SliderFloat("Stroke width", &stroke_width, 0, 300);
170 ImGui::Combo("Cap", &selected_cap, cap_names,
171 sizeof(cap_names) / sizeof(char*));
172 ImGui::Checkbox("Use center", &use_center);
173 ImGui::End();
174
175 switch (selected_cap) {
176 case 0:
177 cap = flutter::DlStrokeCap::kButt;
178 break;
179 case 1:
180 cap = flutter::DlStrokeCap::kRound;
181 break;
182 case 2:
183 cap = flutter::DlStrokeCap::kSquare;
184 break;
185 default:
186 cap = flutter::DlStrokeCap::kButt;
187 break;
188 }
189
190 static PlaygroundPoint point_a(Point(200, 200), 20, Color::White());
191 static PlaygroundPoint point_b(Point(400, 400), 20, Color::White());
192 auto [p1, p2] = DrawPlaygroundLine(point_a, point_b);
193
194 flutter::DisplayListBuilder builder;
195 flutter::DlPaint paint;
196
197 Vector2 scale = GetContentScale();
198 builder.Scale(scale.x, scale.y);
199 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
200 paint.setStrokeCap(cap);
201 paint.setStrokeJoin(flutter::DlStrokeJoin::kMiter);
202 paint.setStrokeMiter(10);
203 auto rect = DlRect::MakeLTRB(p1.x, p1.y, p2.x, p2.y);
204 paint.setColor(flutter::DlColor::kGreen());
205 paint.setStrokeWidth(2);
206 builder.DrawRect(rect, paint);
207 paint.setColor(flutter::DlColor::kRed());
208 paint.setStrokeWidth(stroke_width);
209 builder.DrawArc(rect, start_angle, sweep_angle, use_center, paint);
210
211 return builder.Build();
212 };
213 ASSERT_TRUE(OpenPlaygroundHere(callback));
214 }
215
216 TEST_P(DisplayListTest, StrokedPathsDrawCorrectly) {
217 auto callback = [&]() {
218 flutter::DisplayListBuilder builder;
219 flutter::DlPaint paint;
220
221 paint.setColor(flutter::DlColor::kRed());
222 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
223
224 static float stroke_width = 10.0f;
225 static int selected_stroke_type = 0;
226 static int selected_join_type = 0;
227 const char* stroke_types[] = {"Butte", "Round", "Square"};
228 const char* join_type[] = {"kMiter", "Round", "kBevel"};
229
230 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
231 ImGui::Combo("Cap", &selected_stroke_type, stroke_types,
232 sizeof(stroke_types) / sizeof(char*));
233 ImGui::Combo("Join", &selected_join_type, join_type,
234 sizeof(join_type) / sizeof(char*));
235 ImGui::SliderFloat("Stroke Width", &stroke_width, 10.0f, 50.0f);
236 ImGui::End();
237
238 flutter::DlStrokeCap cap;
239 flutter::DlStrokeJoin join;
240 switch (selected_stroke_type) {
241 case 0:
242 cap = flutter::DlStrokeCap::kButt;
243 break;
244 case 1:
245 cap = flutter::DlStrokeCap::kRound;
246 break;
247 case 2:
248 cap = flutter::DlStrokeCap::kSquare;
249 break;
250 default:
251 cap = flutter::DlStrokeCap::kButt;
252 break;
253 }
254 switch (selected_join_type) {
255 case 0:
256 join = flutter::DlStrokeJoin::kMiter;
257 break;
258 case 1:
259 join = flutter::DlStrokeJoin::kRound;
260 break;
261 case 2:
262 join = flutter::DlStrokeJoin::kBevel;
263 break;
264 default:
265 join = flutter::DlStrokeJoin::kMiter;
266 break;
267 }
268 paint.setStrokeCap(cap);
269 paint.setStrokeJoin(join);
270 paint.setStrokeWidth(stroke_width);
271
272 // Make rendering better to watch.
273 builder.Scale(1.5f, 1.5f);
274
275 // Rectangle
276 builder.Translate(100, 100);
277 builder.DrawRect(DlRect::MakeWH(100, 100), paint);
278
279 // Rounded rectangle
280 builder.Translate(150, 0);
281 builder.DrawRoundRect(
282 DlRoundRect::MakeRectXY(DlRect::MakeWH(100, 50), 10, 10), paint);
283
284 // Double rounded rectangle
285 builder.Translate(150, 0);
286 builder.DrawDiffRoundRect(
287 DlRoundRect::MakeRectXY(DlRect::MakeWH(100, 50), 10, 10),
288 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(10, 10, 80, 30), 10, 10),
289 paint);
290
291 // Contour with duplicate join points
292 {
293 builder.Translate(150, 0);
294 flutter::DlPathBuilder path_builder;
295 path_builder.MoveTo(DlPoint(0, 0));
296 path_builder.LineTo(DlPoint(0, 0));
297 path_builder.LineTo(DlPoint(100, 0));
298 path_builder.LineTo(DlPoint(100, 0));
299 path_builder.LineTo(DlPoint(100, 100));
300 builder.DrawPath(path_builder.TakePath(), paint);
301 }
302
303 // Contour with duplicate start and end points
304
305 // Line.
306 builder.Translate(200, 0);
307 {
308 builder.Save();
309
310 flutter::DlPathBuilder line_path_builder;
311 line_path_builder.MoveTo(DlPoint(0, 0));
312 line_path_builder.MoveTo(DlPoint(0, 0));
313 line_path_builder.LineTo(DlPoint(0, 0));
314 line_path_builder.LineTo(DlPoint(0, 0));
315 line_path_builder.LineTo(DlPoint(50, 50));
316 line_path_builder.LineTo(DlPoint(50, 50));
317 line_path_builder.LineTo(DlPoint(100, 0));
318 line_path_builder.LineTo(DlPoint(100, 0));
319 DlPath line_path = line_path_builder.TakePath();
320 builder.DrawPath(line_path, paint);
321
322 builder.Translate(0, 100);
323 builder.DrawPath(line_path, paint);
324
325 builder.Translate(0, 100);
326 flutter::DlPathBuilder line_path_builder2;
327 line_path_builder2.MoveTo(DlPoint(0, 0));
328 line_path_builder2.LineTo(DlPoint(0, 0));
329 line_path_builder2.LineTo(DlPoint(0, 0));
330 builder.DrawPath(line_path_builder2.TakePath(), paint);
331
332 builder.Restore();
333 }
334
335 // Cubic.
336 builder.Translate(150, 0);
337 {
338 builder.Save();
339
340 flutter::DlPathBuilder cubic_path;
341 cubic_path.MoveTo(DlPoint(0, 0));
342 cubic_path.CubicCurveTo(DlPoint(0, 0), //
343 DlPoint(140.0, 100.0), //
344 DlPoint(140, 20));
345 builder.DrawPath(cubic_path.TakePath(), paint);
346
347 builder.Translate(0, 100);
348 flutter::DlPathBuilder cubic_path2;
349 cubic_path2.MoveTo(DlPoint(0, 0));
350 cubic_path2.CubicCurveTo(DlPoint(0, 0), //
351 DlPoint(0, 0), //
352 DlPoint(150, 150));
353 builder.DrawPath(cubic_path2.TakePath(), paint);
354
355 builder.Translate(0, 100);
356 flutter::DlPathBuilder cubic_path3;
357 cubic_path3.MoveTo(DlPoint(0, 0));
358 cubic_path3.CubicCurveTo(DlPoint(0, 0), //
359 DlPoint(0, 0), //
360 DlPoint(0, 0));
361 builder.DrawPath(cubic_path3.TakePath(), paint);
362
363 builder.Restore();
364 }
365
366 // Quad.
367 builder.Translate(200, 0);
368 {
369 builder.Save();
370
371 flutter::DlPathBuilder quad_path;
372 quad_path.MoveTo(DlPoint(0, 0));
373 quad_path.MoveTo(DlPoint(0, 0));
374 quad_path.QuadraticCurveTo(DlPoint(100, 40), DlPoint(50, 80));
375 builder.DrawPath(quad_path.TakePath(), paint);
376
377 builder.Translate(0, 150);
378 flutter::DlPathBuilder quad_path2;
379 quad_path2.MoveTo(DlPoint(0, 0));
380 quad_path2.MoveTo(DlPoint(0, 0));
381 quad_path2.QuadraticCurveTo(DlPoint(0, 0), DlPoint(100, 100));
382 builder.DrawPath(quad_path2.TakePath(), paint);
383
384 builder.Translate(0, 100);
385 flutter::DlPathBuilder quad_path3;
386 quad_path3.MoveTo(DlPoint(0, 0));
387 quad_path3.QuadraticCurveTo(DlPoint(0, 0), DlPoint(0, 0));
388 builder.DrawPath(quad_path3.TakePath(), paint);
389
390 builder.Restore();
391 }
392 return builder.Build();
393 };
394 ASSERT_TRUE(OpenPlaygroundHere(callback));
395 }
396
397 TEST_P(DisplayListTest, CanDrawWithOddPathWinding) {
398 flutter::DisplayListBuilder builder;
399 flutter::DlPaint paint;
400
401 paint.setColor(flutter::DlColor::kRed());
402 paint.setDrawStyle(flutter::DlDrawStyle::kFill);
403
404 builder.Translate(300, 300);
405 flutter::DlPathBuilder path_builder;
406 path_builder.AddCircle(DlPoint(0, 0), 100);
407 path_builder.AddCircle(DlPoint(0, 0), 50);
408 path_builder.SetFillType(flutter::DlPathFillType::kOdd);
409 builder.DrawPath(path_builder.TakePath(), paint);
410
411 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
412 }
413
414 // Regression test for https://github.com/flutter/flutter/issues/134816.
415 //
416 // It should be possible to draw 3 lines, and not have an implicit close path.
417 TEST_P(DisplayListTest, CanDrawAnOpenPath) {
418 flutter::DisplayListBuilder builder;
419 flutter::DlPaint paint;
420
421 paint.setColor(flutter::DlColor::kRed());
422 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
423 paint.setStrokeWidth(10);
424
425 builder.Translate(300, 300);
426
427 // Move to (50, 50) and draw lines from:
428 // 1. (50, height)
429 // 2. (width, height)
430 // 3. (width, 50)
431 flutter::DlPathBuilder path_builder;
432 path_builder.MoveTo(DlPoint(50, 50));
433 path_builder.LineTo(DlPoint(50, 100));
434 path_builder.LineTo(DlPoint(100, 100));
435 path_builder.LineTo(DlPoint(100, 50));
436 builder.DrawPath(path_builder.TakePath(), paint);
437
438 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
439 }
440
441 TEST_P(DisplayListTest, CanDrawWithMaskBlur) {
442 auto texture = CreateTextureForFixture("embarcadero.jpg");
443 flutter::DisplayListBuilder builder;
444 flutter::DlPaint paint;
445
446 // Mask blurred image.
447 {
448 auto filter =
449 flutter::DlBlurMaskFilter(flutter::DlBlurStyle::kNormal, 10.0f);
450 paint.setMaskFilter(&filter);
451 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
452 flutter::DlImageSampling::kNearestNeighbor, &paint);
453 }
454
455 // Mask blurred filled path.
456 {
457 paint.setColor(flutter::DlColor::kYellow());
458 auto filter =
459 flutter::DlBlurMaskFilter(flutter::DlBlurStyle::kOuter, 10.0f);
460 paint.setMaskFilter(&filter);
461 builder.DrawArc(DlRect::MakeXYWH(410, 110, 100, 100), 45, 270, true, paint);
462 }
463
464 // Mask blurred text.
465 {
466 auto filter =
467 flutter::DlBlurMaskFilter(flutter::DlBlurStyle::kSolid, 10.0f);
468 paint.setMaskFilter(&filter);
469 builder.DrawText(flutter::DlTextSkia::Make(SkTextBlob::MakeFromString(
470 "Testing", CreateTestFont())),
471 220, 170, paint);
472 }
473
474 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
475 }
476
477 TEST_P(DisplayListTest, CanDrawStrokedText) {
478 flutter::DisplayListBuilder builder;
479 flutter::DlPaint paint;
480
481 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
482 paint.setColor(flutter::DlColor::kRed());
483 builder.DrawText(flutter::DlTextSkia::Make(SkTextBlob::MakeFromString(
484 "stoked about stroked text", CreateTestFont())),
485 250, 250, paint);
486
487 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
488 }
489
490 // Regression test for https://github.com/flutter/flutter/issues/133157.
491 TEST_P(DisplayListTest, StrokedTextNotOffsetFromNormalText) {
492 flutter::DisplayListBuilder builder;
493 flutter::DlPaint paint;
494 auto const& text_blob = SkTextBlob::MakeFromString("00000", CreateTestFont());
495 auto text = flutter::DlTextSkia::Make(text_blob);
496
497 // https://api.flutter.dev/flutter/material/Colors/blue-constant.html.
498 auto const& mat_blue = flutter::DlColor(0xFF2196f3);
499
500 // Draw a blue filled rectangle so the text is easier to see.
501 paint.setDrawStyle(flutter::DlDrawStyle::kFill);
502 paint.setColor(mat_blue);
503 builder.DrawRect(DlRect::MakeXYWH(0, 0, 500, 500), paint);
504
505 // Draw stacked text, with stroked text on top.
506 paint.setDrawStyle(flutter::DlDrawStyle::kFill);
507 paint.setColor(flutter::DlColor::kWhite());
508 builder.DrawText(text, 250, 250, paint);
509
510 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
511 paint.setColor(flutter::DlColor::kBlack());
512 builder.DrawText(text, 250, 250, paint);
513
514 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
515 }
516
517 TEST_P(DisplayListTest, IgnoreMaskFilterWhenSavingLayer) {
518 auto texture = CreateTextureForFixture("embarcadero.jpg");
519 flutter::DisplayListBuilder builder;
520 auto filter = flutter::DlBlurMaskFilter(flutter::DlBlurStyle::kNormal, 10.0f);
521 flutter::DlPaint paint;
522 paint.setMaskFilter(&filter);
523 builder.SaveLayer(std::nullopt, &paint);
524 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
525 flutter::DlImageSampling::kNearestNeighbor);
526 builder.Restore();
527 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
528 }
529
530 TEST_P(DisplayListTest, CanDrawWithBlendColorFilter) {
531 auto texture = CreateTextureForFixture("embarcadero.jpg");
532 flutter::DisplayListBuilder builder;
533 flutter::DlPaint paint;
534
535 // Pipeline blended image.
536 {
537 auto filter = flutter::DlColorFilter::MakeBlend(
538 flutter::DlColor::kYellow(), flutter::DlBlendMode::kModulate);
539 paint.setColorFilter(filter);
540 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
541 flutter::DlImageSampling::kNearestNeighbor, &paint);
542 }
543
544 // Advanced blended image.
545 {
546 auto filter = flutter::DlColorFilter::MakeBlend(
547 flutter::DlColor::kRed(), flutter::DlBlendMode::kScreen);
548 paint.setColorFilter(filter);
549 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(250, 250),
550 flutter::DlImageSampling::kNearestNeighbor, &paint);
551 }
552
553 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
554 }
555
556 TEST_P(DisplayListTest, CanDrawWithColorFilterImageFilter) {
557 const float invert_color_matrix[20] = {
558 -1, 0, 0, 0, 1, //
559 0, -1, 0, 0, 1, //
560 0, 0, -1, 0, 1, //
561 0, 0, 0, 1, 0, //
562 };
563 auto texture = CreateTextureForFixture("boston.jpg");
564 flutter::DisplayListBuilder builder;
565 flutter::DlPaint paint;
566
567 auto color_filter = flutter::DlColorFilter::MakeMatrix(invert_color_matrix);
568 auto image_filter = flutter::DlImageFilter::MakeColorFilter(color_filter);
569
570 paint.setImageFilter(image_filter);
571 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
572 flutter::DlImageSampling::kNearestNeighbor, &paint);
573
574 builder.Translate(0, 700);
575 paint.setColorFilter(color_filter);
576 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
577 flutter::DlImageSampling::kNearestNeighbor, &paint);
578 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
579 }
580
581 TEST_P(DisplayListTest, CanDrawWithImageBlurFilter) {
582 auto texture = CreateTextureForFixture("embarcadero.jpg");
583
584 auto callback = [&]() {
585 static float sigma[] = {10, 10};
586
587 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
588 ImGui::SliderFloat2("Sigma", sigma, 0, 100);
589 ImGui::End();
590
591 flutter::DisplayListBuilder builder;
592 flutter::DlPaint paint;
593
594 auto filter = flutter::DlBlurImageFilter(sigma[0], sigma[1],
595 flutter::DlTileMode::kClamp);
596 paint.setImageFilter(&filter);
597 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(200, 200),
598 flutter::DlImageSampling::kNearestNeighbor, &paint);
599
600 return builder.Build();
601 };
602
603 ASSERT_TRUE(OpenPlaygroundHere(callback));
604 }
605
606 TEST_P(DisplayListTest, CanDrawWithComposeImageFilter) {
607 auto texture = CreateTextureForFixture("boston.jpg");
608 flutter::DisplayListBuilder builder;
609 flutter::DlPaint paint;
610
611 auto dilate = std::make_shared<flutter::DlDilateImageFilter>(10.0, 10.0);
612 auto erode = std::make_shared<flutter::DlErodeImageFilter>(10.0, 10.0);
613 auto open = std::make_shared<flutter::DlComposeImageFilter>(dilate, erode);
614 auto close = std::make_shared<flutter::DlComposeImageFilter>(erode, dilate);
615
616 paint.setImageFilter(open.get());
617 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
618 flutter::DlImageSampling::kNearestNeighbor, &paint);
619 builder.Translate(0, 700);
620 paint.setImageFilter(close.get());
621 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
622 flutter::DlImageSampling::kNearestNeighbor, &paint);
623 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
624 }
625
626 TEST_P(DisplayListTest, CanClampTheResultingColorOfColorMatrixFilter) {
627 auto texture = CreateTextureForFixture("boston.jpg");
628 const float inner_color_matrix[20] = {
629 1, 0, 0, 0, 0, //
630 0, 1, 0, 0, 0, //
631 0, 0, 1, 0, 0, //
632 0, 0, 0, 2, 0, //
633 };
634 const float outer_color_matrix[20] = {
635 1, 0, 0, 0, 0, //
636 0, 1, 0, 0, 0, //
637 0, 0, 1, 0, 0, //
638 0, 0, 0, 0.5, 0, //
639 };
640 auto inner_color_filter =
641 flutter::DlColorFilter::MakeMatrix(inner_color_matrix);
642 auto outer_color_filter =
643 flutter::DlColorFilter::MakeMatrix(outer_color_matrix);
644 auto inner = flutter::DlImageFilter::MakeColorFilter(inner_color_filter);
645 auto outer = flutter::DlImageFilter::MakeColorFilter(outer_color_filter);
646 auto compose = std::make_shared<flutter::DlComposeImageFilter>(outer, inner);
647
648 flutter::DisplayListBuilder builder;
649 flutter::DlPaint paint;
650 paint.setImageFilter(compose.get());
651 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
652 flutter::DlImageSampling::kNearestNeighbor, &paint);
653 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
654 }
655
656 TEST_P(DisplayListTest, CanDrawBackdropFilter) {
657 auto texture = CreateTextureForFixture("embarcadero.jpg");
658
659 auto callback = [&]() {
660 static float sigma[] = {10, 10};
661 static float ctm_scale = 1;
662 static bool use_bounds = true;
663 static bool draw_circle = true;
664 static bool add_clip = true;
665
666 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
667 ImGui::SliderFloat2("Sigma", sigma, 0, 100);
668 ImGui::SliderFloat("Scale", &ctm_scale, 0, 10);
669 ImGui::NewLine();
670 ImGui::TextWrapped(
671 "If everything is working correctly, none of the options below should "
672 "impact the filter's appearance.");
673 ImGui::Checkbox("Use SaveLayer bounds", &use_bounds);
674 ImGui::Checkbox("Draw child element", &draw_circle);
675 ImGui::Checkbox("Add pre-clip", &add_clip);
676 ImGui::End();
677
678 flutter::DisplayListBuilder builder;
679
680 Vector2 scale = ctm_scale * GetContentScale();
681 builder.Scale(scale.x, scale.y);
682
683 auto filter = flutter::DlBlurImageFilter(sigma[0], sigma[1],
684 flutter::DlTileMode::kClamp);
685
686 std::optional<DlRect> bounds;
687 if (use_bounds) {
688 static PlaygroundPoint point_a(Point(350, 150), 20, Color::White());
689 static PlaygroundPoint point_b(Point(800, 600), 20, Color::White());
690 auto [p1, p2] = DrawPlaygroundLine(point_a, point_b);
691 bounds = DlRect::MakeLTRB(p1.x, p1.y, p2.x, p2.y);
692 }
693
694 // Insert a clip to test that the backdrop filter handles stencil depths > 0
695 // correctly.
696 if (add_clip) {
697 builder.ClipRect(DlRect::MakeLTRB(0, 0, 99999, 99999),
698 flutter::DlClipOp::kIntersect, true);
699 }
700
701 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(200, 200),
702 flutter::DlImageSampling::kNearestNeighbor, nullptr);
703 builder.SaveLayer(bounds, nullptr, &filter);
704
705 if (draw_circle) {
706 static PlaygroundPoint center_point(Point(500, 400), 20, Color::Red());
707 auto circle_center = DrawPlaygroundPoint(center_point);
708
709 flutter::DlPaint paint;
710 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
711 paint.setStrokeCap(flutter::DlStrokeCap::kButt);
712 paint.setStrokeJoin(flutter::DlStrokeJoin::kBevel);
713 paint.setStrokeWidth(10);
714 paint.setColor(flutter::DlColor::kRed().withAlpha(100));
715 builder.DrawCircle(DlPoint(circle_center.x, circle_center.y), 100, paint);
716 }
717
718 return builder.Build();
719 };
720
721 ASSERT_TRUE(OpenPlaygroundHere(callback));
722 }
723
724 TEST_P(DisplayListTest, CanDrawNinePatchImage) {
725 // Image is drawn with corners to scale and center pieces stretched to fit.
726 auto texture = CreateTextureForFixture("embarcadero.jpg");
727 flutter::DisplayListBuilder builder;
728 auto size = texture->GetSize();
729 builder.DrawImageNine(
730 DlImageImpeller::Make(texture),
731 DlIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
732 size.height * 3 / 4),
733 DlRect::MakeLTRB(0, 0, size.width * 2, size.height * 2),
734 flutter::DlFilterMode::kNearest, nullptr);
735 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
736 }
737
738 TEST_P(DisplayListTest, CanDrawNinePatchImageCenterWidthBiggerThanDest) {
739 // Edge case, the width of the corners does not leave any room for the
740 // center slice. The center (across the vertical axis) is folded out of the
741 // resulting image.
742 auto texture = CreateTextureForFixture("embarcadero.jpg");
743 flutter::DisplayListBuilder builder;
744 auto size = texture->GetSize();
745 builder.DrawImageNine(
746 DlImageImpeller::Make(texture),
747 DlIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
748 size.height * 3 / 4),
749 DlRect::MakeLTRB(0, 0, size.width / 2, size.height),
750 flutter::DlFilterMode::kNearest, nullptr);
751 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
752 }
753
754 TEST_P(DisplayListTest, CanDrawNinePatchImageCenterHeightBiggerThanDest) {
755 // Edge case, the height of the corners does not leave any room for the
756 // center slice. The center (across the horizontal axis) is folded out of the
757 // resulting image.
758 auto texture = CreateTextureForFixture("embarcadero.jpg");
759 flutter::DisplayListBuilder builder;
760 auto size = texture->GetSize();
761 builder.DrawImageNine(
762 DlImageImpeller::Make(texture),
763 DlIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
764 size.height * 3 / 4),
765 DlRect::MakeLTRB(0, 0, size.width, size.height / 2),
766 flutter::DlFilterMode::kNearest, nullptr);
767 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
768 }
769
770 TEST_P(DisplayListTest, CanDrawNinePatchImageCenterBiggerThanDest) {
771 // Edge case, the width and height of the corners does not leave any
772 // room for the center slices. Only the corners are displayed.
773 auto texture = CreateTextureForFixture("embarcadero.jpg");
774 flutter::DisplayListBuilder builder;
775 auto size = texture->GetSize();
776 builder.DrawImageNine(
777 DlImageImpeller::Make(texture),
778 DlIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
779 size.height * 3 / 4),
780 DlRect::MakeLTRB(0, 0, size.width / 2, size.height / 2),
781 flutter::DlFilterMode::kNearest, nullptr);
782 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
783 }
784
785 TEST_P(DisplayListTest, CanDrawNinePatchImageCornersScaledDown) {
786 // Edge case, there is not enough room for the corners to be drawn
787 // without scaling them down.
788 auto texture = CreateTextureForFixture("embarcadero.jpg");
789 flutter::DisplayListBuilder builder;
790 auto size = texture->GetSize();
791 builder.DrawImageNine(
792 DlImageImpeller::Make(texture),
793 DlIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
794 size.height * 3 / 4),
795 DlRect::MakeLTRB(0, 0, size.width / 4, size.height / 4),
796 flutter::DlFilterMode::kNearest, nullptr);
797 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
798 }
799
800 TEST_P(DisplayListTest, NinePatchImagePrecision) {
801 // Draw a nine patch image with colored corners and verify that the corner
802 // color does not leak outside the intended region.
803 auto texture = CreateTextureForFixture("nine_patch_corners.png");
804 flutter::DisplayListBuilder builder;
805 builder.DrawImageNine(DlImageImpeller::Make(texture),
806 DlIRect::MakeXYWH(10, 10, 1, 1),
807 DlRect::MakeXYWH(0, 0, 200, 100),
808 flutter::DlFilterMode::kNearest, nullptr);
809 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
810 }
811
812 TEST_P(DisplayListTest, NinePatchImageColorFilter) {
813 auto texture = CreateTextureForFixture("nine_patch2.png");
814
815 auto filter = flutter::DlColorFilter::MakeBlend(flutter::DlColor::kGreen(),
816 flutter::DlBlendMode::kSrcIn);
817 flutter::DlPaint paint;
818 paint.setColorFilter(filter);
819
820 flutter::DisplayListBuilder builder;
821 builder.DrawImageNine(DlImageImpeller::Make(texture),
822 DlIRect::MakeXYWH(10, 10, 1, 1),
823 DlRect::MakeXYWH(0, 0, 200, 100),
824 flutter::DlFilterMode::kNearest, &paint);
825 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
826 }
827
828 TEST_P(DisplayListTest, CanDrawPoints) {
829 flutter::DisplayListBuilder builder;
830 DlPoint points[7] = {
831 {0, 0}, //
832 {100, 100}, //
833 {100, 0}, //
834 {0, 100}, //
835 {0, 0}, //
836 {48, 48}, //
837 {52, 52}, //
838 };
839 std::vector<flutter::DlStrokeCap> caps = {
840 flutter::DlStrokeCap::kButt,
841 flutter::DlStrokeCap::kRound,
842 flutter::DlStrokeCap::kSquare,
843 };
844 flutter::DlPaint paint =
845 flutter::DlPaint() //
846 .setColor(flutter::DlColor::kYellow().withAlpha(127)) //
847 .setStrokeWidth(20);
848 builder.Translate(50, 50);
849 for (auto cap : caps) {
850 paint.setStrokeCap(cap);
851 builder.Save();
852 builder.DrawPoints(flutter::DlPointMode::kPoints, 7, points, paint);
853 builder.Translate(150, 0);
854 builder.DrawPoints(flutter::DlPointMode::kLines, 5, points, paint);
855 builder.Translate(150, 0);
856 builder.DrawPoints(flutter::DlPointMode::kPolygon, 5, points, paint);
857 builder.Restore();
858 builder.Translate(0, 150);
859 }
860 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
861 }
862
863 TEST_P(DisplayListTest, CanDrawZeroLengthLine) {
864 flutter::DisplayListBuilder builder;
865 std::vector<flutter::DlStrokeCap> caps = {
866 flutter::DlStrokeCap::kButt,
867 flutter::DlStrokeCap::kRound,
868 flutter::DlStrokeCap::kSquare,
869 };
870 flutter::DlPaint paint =
871 flutter::DlPaint() //
872 .setColor(flutter::DlColor::kYellow().withAlpha(127)) //
873 .setDrawStyle(flutter::DlDrawStyle::kStroke) //
874 .setStrokeCap(flutter::DlStrokeCap::kButt) //
875 .setStrokeWidth(20);
876 DlPath path = DlPath::MakeLine({150, 50}, {150, 50});
877 for (auto cap : caps) {
878 paint.setStrokeCap(cap);
879 builder.DrawLine(DlPoint(50, 50), DlPoint(50, 50), paint);
880 builder.DrawPath(path, paint);
881 builder.Translate(0, 150);
882 }
883 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
884 }
885
886 TEST_P(DisplayListTest, CanDrawShadow) {
887 flutter::DisplayListBuilder builder;
888 flutter::DlPaint paint;
889
890 auto content_scale = GetContentScale() * 0.8;
891 builder.Scale(content_scale.x, content_scale.y);
892
893 constexpr size_t star_spikes = 5;
894 constexpr DlScalar half_spike_rotation = kPi / star_spikes;
895 constexpr DlScalar radius = 40;
896 constexpr DlScalar spike_size = 10;
897 constexpr DlScalar outer_radius = radius + spike_size;
898 constexpr DlScalar inner_radius = radius - spike_size;
899 std::array<DlPoint, star_spikes * 2> star;
900 for (size_t i = 0; i < star_spikes; i++) {
901 const DlScalar rotation = half_spike_rotation * i * 2;
902 star[i * 2] = DlPoint(50 + std::sin(rotation) * outer_radius,
903 50 - std::cos(rotation) * outer_radius);
904 star[i * 2 + 1] =
905 DlPoint(50 + std::sin(rotation + half_spike_rotation) * inner_radius,
906 50 - std::cos(rotation + half_spike_rotation) * inner_radius);
907 }
908
909 std::array<DlPath, 4> paths = {
910 DlPath::MakeRect(DlRect::MakeXYWH(0, 0, 200, 100)),
911 DlPath::MakeRoundRectXY(DlRect::MakeXYWH(20, 0, 200, 100), 30, 30),
912 DlPath::MakeCircle(DlPoint(100, 50), 50),
913 DlPath::MakePoly(star.data(), star.size(), true),
914 };
915 paint.setColor(flutter::DlColor::kWhite());
916 builder.DrawPaint(paint);
917 paint.setColor(flutter::DlColor::kCyan());
918 builder.Translate(100, 50);
919 for (size_t x = 0; x < paths.size(); x++) {
920 builder.Save();
921 for (size_t y = 0; y < 6; y++) {
922 builder.DrawShadow(paths[x], flutter::DlColor::kBlack(), 3 + y * 8, false,
923 1);
924 builder.DrawPath(paths[x], paint);
925 builder.Translate(0, 150);
926 }
927 builder.Restore();
928 builder.Translate(250, 0);
929 }
930
931 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
932 }
933
934 TEST_P(DisplayListTest, CanDrawZeroWidthLine) {
935 flutter::DisplayListBuilder builder;
936 std::vector<flutter::DlStrokeCap> caps = {
937 flutter::DlStrokeCap::kButt,
938 flutter::DlStrokeCap::kRound,
939 flutter::DlStrokeCap::kSquare,
940 };
941 flutter::DlPaint paint = //
942 flutter::DlPaint() //
943 .setColor(flutter::DlColor::kWhite()) //
944 .setDrawStyle(flutter::DlDrawStyle::kStroke) //
945 .setStrokeWidth(0);
946 flutter::DlPaint outline_paint = //
947 flutter::DlPaint() //
948 .setColor(flutter::DlColor::kYellow()) //
949 .setDrawStyle(flutter::DlDrawStyle::kStroke) //
950 .setStrokeCap(flutter::DlStrokeCap::kSquare) //
951 .setStrokeWidth(1);
952 DlPath path = DlPath::MakeLine({150, 50}, {160, 50});
953 for (auto cap : caps) {
954 paint.setStrokeCap(cap);
955 builder.DrawLine(DlPoint(50, 50), DlPoint(60, 50), paint);
956 builder.DrawRect(DlRect::MakeLTRB(45, 45, 65, 55), outline_paint);
957 builder.DrawLine(DlPoint{100, 50}, DlPoint{100, 50}, paint);
958 if (cap != flutter::DlStrokeCap::kButt) {
959 builder.DrawRect(DlRect::MakeLTRB(95, 45, 105, 55), outline_paint);
960 }
961 builder.DrawPath(path, paint);
962 builder.DrawRect(path.GetBounds().Expand(5, 5), outline_paint);
963 builder.Translate(0, 150);
964 }
965 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
966 }
967
968 TEST_P(DisplayListTest, CanDrawWithMatrixFilter) {
969 auto boston = CreateTextureForFixture("boston.jpg");
970
971 auto callback = [&]() {
972 static int selected_matrix_type = 0;
973 const char* matrix_type_names[] = {"Matrix", "Local Matrix"};
974
975 static float ctm_translation[2] = {200, 200};
976 static float ctm_scale[2] = {0.65, 0.65};
977 static float ctm_skew[2] = {0, 0};
978
979 static bool enable = true;
980 static float translation[2] = {100, 100};
981 static float scale[2] = {0.8, 0.8};
982 static float skew[2] = {0.2, 0.2};
983
984 static bool enable_savelayer = true;
985
986 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
987 {
988 ImGui::Combo("Filter type", &selected_matrix_type, matrix_type_names,
989 sizeof(matrix_type_names) / sizeof(char*));
990
991 ImGui::TextWrapped("Current Transform");
992 ImGui::SliderFloat2("CTM Translation", ctm_translation, 0, 1000);
993 ImGui::SliderFloat2("CTM Scale", ctm_scale, 0, 3);
994 ImGui::SliderFloat2("CTM Skew", ctm_skew, -3, 3);
995
996 ImGui::TextWrapped(
997 "MatrixFilter and LocalMatrixFilter modify the CTM in the same way. "
998 "The only difference is that MatrixFilter doesn't affect the effect "
999 "transform, whereas LocalMatrixFilter does.");
1000 // Note: See this behavior in:
1001 // https://fiddle.skia.org/c/6cbb551ab36d06f163db8693972be954
1002 ImGui::Checkbox("Enable", &enable);
1003 ImGui::SliderFloat2("Filter Translation", translation, 0, 1000);
1004 ImGui::SliderFloat2("Filter Scale", scale, 0, 3);
1005 ImGui::SliderFloat2("Filter Skew", skew, -3, 3);
1006
1007 ImGui::TextWrapped(
1008 "Rendering the filtered image within a layer can expose bounds "
1009 "issues. If the rendered image gets cut off when this setting is "
1010 "enabled, there's a coverage bug in the filter.");
1011 ImGui::Checkbox("Render in layer", &enable_savelayer);
1012 }
1013 ImGui::End();
1014
1015 flutter::DisplayListBuilder builder;
1016 flutter::DlPaint paint;
1017
1018 if (enable_savelayer) {
1019 builder.SaveLayer(std::nullopt, nullptr);
1020 }
1021 {
1022 auto content_scale = GetContentScale();
1023 builder.Scale(content_scale.x, content_scale.y);
1024
1025 // Set the current transform
1026 auto ctm_matrix = Matrix::MakeRow(
1027 ctm_scale[0], ctm_skew[0], 0.0f, ctm_translation[0], //
1028 ctm_skew[1], ctm_scale[1], 0.0f, ctm_translation[1], //
1029 0, 0, 1, 0, //
1030 0, 0, 0, 1);
1031 builder.Transform(ctm_matrix);
1032
1033 // Set the matrix filter
1034 auto filter_matrix =
1035 Matrix::MakeRow(scale[0], skew[0], 0.0f, translation[0], //
1036 skew[1], scale[1], 0.0f, translation[1], //
1037 0.0f, 0.0f, 1.0f, 0.0f, //
1038 0.0f, 0.0f, 0.0f, 1.0f);
1039
1040 if (enable) {
1041 switch (selected_matrix_type) {
1042 case 0: {
1043 auto filter = flutter::DlMatrixImageFilter(
1044 filter_matrix, flutter::DlImageSampling::kLinear);
1045 paint.setImageFilter(&filter);
1046 break;
1047 }
1048 case 1: {
1049 auto internal_filter =
1050 flutter::DlBlurImageFilter(10, 10, flutter::DlTileMode::kDecal)
1051 .shared();
1052 auto filter = flutter::DlLocalMatrixImageFilter(filter_matrix,
1053 internal_filter);
1054 paint.setImageFilter(&filter);
1055 break;
1056 }
1057 }
1058 }
1059
1060 builder.DrawImage(DlImageImpeller::Make(boston), DlPoint(),
1061 flutter::DlImageSampling::kLinear, &paint);
1062 }
1063 if (enable_savelayer) {
1064 builder.Restore();
1065 }
1066
1067 return builder.Build();
1068 };
1069
1070 ASSERT_TRUE(OpenPlaygroundHere(callback));
1071 }
1072
1073 TEST_P(DisplayListTest, CanDrawWithMatrixFilterWhenSavingLayer) {
1074 auto callback = [&]() {
1075 static float translation[2] = {0, 0};
1076 static bool enable_save_layer = true;
1077
1078 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1079 ImGui::SliderFloat2("Translation", translation, -130, 130);
1080 ImGui::Checkbox("Enable save layer", &enable_save_layer);
1081 ImGui::End();
1082
1083 flutter::DisplayListBuilder builder;
1084 builder.Save();
1085 builder.Scale(2.0, 2.0);
1086 flutter::DlPaint paint;
1087 paint.setColor(flutter::DlColor::kYellow());
1088 builder.DrawRect(DlRect::MakeWH(300, 300), paint);
1089 paint.setStrokeWidth(1.0);
1090 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
1091 paint.setColor(flutter::DlColor::kBlack().withAlpha(0x80));
1092 builder.DrawLine(DlPoint(150, 0), DlPoint(150, 300), paint);
1093 builder.DrawLine(DlPoint(0, 150), DlPoint(300, 150), paint);
1094
1095 flutter::DlPaint save_paint;
1096 DlRect bounds = DlRect::MakeXYWH(100, 100, 100, 100);
1097 Matrix translate_matrix =
1098 Matrix::MakeTranslation({translation[0], translation[1]});
1099 if (enable_save_layer) {
1100 auto filter = flutter::DlMatrixImageFilter(
1101 translate_matrix, flutter::DlImageSampling::kNearestNeighbor);
1102 save_paint.setImageFilter(filter.shared());
1103 builder.SaveLayer(bounds, &save_paint);
1104 } else {
1105 builder.Save();
1106 builder.Transform(translate_matrix);
1107 }
1108
1109 Matrix filter_matrix;
1110 filter_matrix.Translate({150, 150});
1111 filter_matrix.Scale({0.2f, 0.2f});
1112 filter_matrix.Translate({-150, -150});
1113 auto filter = flutter::DlMatrixImageFilter(
1114 filter_matrix, flutter::DlImageSampling::kNearestNeighbor);
1115
1116 save_paint.setImageFilter(filter.shared());
1117
1118 builder.SaveLayer(bounds, &save_paint);
1119 flutter::DlPaint paint2;
1120 paint2.setColor(flutter::DlColor::kBlue());
1121 builder.DrawRect(bounds, paint2);
1122 builder.Restore();
1123 builder.Restore();
1124 return builder.Build();
1125 };
1126
1127 ASSERT_TRUE(OpenPlaygroundHere(callback));
1128 }
1129
1130 TEST_P(DisplayListTest, CanDrawRectWithLinearToSrgbColorFilter) {
1131 flutter::DlPaint paint;
1132 paint.setColor(flutter::DlColor(0xFF2196F3).withAlpha(128));
1133 flutter::DisplayListBuilder builder;
1134 paint.setColorFilter(flutter::DlColorFilter::MakeLinearToSrgbGamma());
1135 builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), paint);
1136 builder.Translate(0, 200);
1137
1138 paint.setColorFilter(flutter::DlColorFilter::MakeSrgbToLinearGamma());
1139 builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), paint);
1140
1141 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1142 }
1143
1144 TEST_P(DisplayListTest, CanDrawPaintWithColorSource) {
1145 const flutter::DlColor colors[2] = {
1146 flutter::DlColor(0xFFF44336),
1147 flutter::DlColor(0xFF2196F3),
1148 };
1149 const float stops[2] = {0.0, 1.0};
1150 flutter::DlPaint paint;
1151 flutter::DisplayListBuilder builder;
1152 auto clip_bounds = DlRect::MakeWH(300.0, 300.0);
1153 builder.Save();
1154 builder.Translate(100, 100);
1155 builder.ClipRect(clip_bounds, flutter::DlClipOp::kIntersect, false);
1156 auto linear =
1157 flutter::DlColorSource::MakeLinear({0.0, 0.0}, {100.0, 100.0}, 2, colors,
1158 stops, flutter::DlTileMode::kRepeat);
1159 paint.setColorSource(linear);
1160 builder.DrawPaint(paint);
1161 builder.Restore();
1162
1163 builder.Save();
1164 builder.Translate(500, 100);
1165 builder.ClipRect(clip_bounds, flutter::DlClipOp::kIntersect, false);
1166 auto radial = flutter::DlColorSource::MakeRadial(
1167 {100.0, 100.0}, 100.0, 2, colors, stops, flutter::DlTileMode::kRepeat);
1168 paint.setColorSource(radial);
1169 builder.DrawPaint(paint);
1170 builder.Restore();
1171
1172 builder.Save();
1173 builder.Translate(100, 500);
1174 builder.ClipRect(clip_bounds, flutter::DlClipOp::kIntersect, false);
1175 auto sweep =
1176 flutter::DlColorSource::MakeSweep({100.0, 100.0}, 180.0, 270.0, 2, colors,
1177 stops, flutter::DlTileMode::kRepeat);
1178 paint.setColorSource(sweep);
1179 builder.DrawPaint(paint);
1180 builder.Restore();
1181
1182 builder.Save();
1183 builder.Translate(500, 500);
1184 builder.ClipRect(clip_bounds, flutter::DlClipOp::kIntersect, false);
1185 auto texture = CreateTextureForFixture("table_mountain_nx.png");
1186 auto image = flutter::DlColorSource::MakeImage(DlImageImpeller::Make(texture),
1187 flutter::DlTileMode::kRepeat,
1188 flutter::DlTileMode::kRepeat);
1189 paint.setColorSource(image);
1190 builder.DrawPaint(paint);
1191 builder.Restore();
1192
1193 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1194 }
1195
1196 TEST_P(DisplayListTest, CanBlendDstOverAndDstCorrectly) {
1197 flutter::DisplayListBuilder builder;
1198
1199 {
1200 builder.SaveLayer(std::nullopt, nullptr);
1201 builder.Translate(100, 100);
1202 flutter::DlPaint paint;
1203 paint.setColor(flutter::DlColor::kRed());
1204 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1205 paint.setColor(flutter::DlColor::kBlue().withAlpha(127));
1206 paint.setBlendMode(flutter::DlBlendMode::kSrcOver);
1207 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1208 builder.Restore();
1209 }
1210 {
1211 builder.SaveLayer(std::nullopt, nullptr);
1212 builder.Translate(300, 100);
1213 flutter::DlPaint paint;
1214 paint.setColor(flutter::DlColor::kBlue().withAlpha(127));
1215 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1216 paint.setColor(flutter::DlColor::kRed());
1217 paint.setBlendMode(flutter::DlBlendMode::kDstOver);
1218 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1219 builder.Restore();
1220 }
1221 {
1222 builder.SaveLayer(std::nullopt, nullptr);
1223 builder.Translate(100, 300);
1224 flutter::DlPaint paint;
1225 paint.setColor(flutter::DlColor::kRed());
1226 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1227 paint.setColor(flutter::DlColor::kBlue().withAlpha(127));
1228 paint.setBlendMode(flutter::DlBlendMode::kSrc);
1229 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1230 builder.Restore();
1231 }
1232 {
1233 builder.SaveLayer(std::nullopt, nullptr);
1234 builder.Translate(300, 300);
1235 flutter::DlPaint paint;
1236 paint.setColor(flutter::DlColor::kBlue().withAlpha(127));
1237 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1238 paint.setColor(flutter::DlColor::kRed());
1239 paint.setBlendMode(flutter::DlBlendMode::kDst);
1240 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1241 builder.Restore();
1242 }
1243
1244 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1245 }
1246
1247 TEST_P(DisplayListTest, CanDrawCorrectlyWithColorFilterAndImageFilter) {
1248 flutter::DisplayListBuilder builder;
1249 const float green_color_matrix[20] = {
1250 0, 0, 0, 0, 0, //
1251 0, 0, 0, 0, 1, //
1252 0, 0, 0, 0, 0, //
1253 0, 0, 0, 1, 0, //
1254 };
1255 const float blue_color_matrix[20] = {
1256 0, 0, 0, 0, 0, //
1257 0, 0, 0, 0, 0, //
1258 0, 0, 0, 0, 1, //
1259 0, 0, 0, 1, 0, //
1260 };
1261 auto green_color_filter =
1262 flutter::DlColorFilter::MakeMatrix(green_color_matrix);
1263 auto blue_color_filter =
1264 flutter::DlColorFilter::MakeMatrix(blue_color_matrix);
1265 auto blue_image_filter =
1266 flutter::DlImageFilter::MakeColorFilter(blue_color_filter);
1267
1268 flutter::DlPaint paint;
1269 paint.setColor(flutter::DlColor::kRed());
1270 paint.setColorFilter(green_color_filter);
1271 paint.setImageFilter(blue_image_filter);
1272 builder.DrawRect(DlRect::MakeLTRB(100, 100, 500, 500), paint);
1273 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1274 }
1275
1276 TEST_P(DisplayListTest, MaskBlursApplyCorrectlyToColorSources) {
1277 auto blur_filter = std::make_shared<flutter::DlBlurMaskFilter>(
1278 flutter::DlBlurStyle::kNormal, 10);
1279
1280 flutter::DisplayListBuilder builder;
1281
1282 std::array<flutter::DlColor, 2> colors = {flutter::DlColor::kBlue(),
1283 flutter::DlColor::kGreen()};
1284 std::array<float, 2> stops = {0, 1};
1285 auto texture = CreateTextureForFixture("airplane.jpg");
1286 auto matrix = flutter::DlMatrix::MakeTranslation({-300, -110});
1287 std::array<std::shared_ptr<flutter::DlColorSource>, 2> color_sources = {
1288 flutter::DlColorSource::MakeImage(
1289 DlImageImpeller::Make(texture), flutter::DlTileMode::kRepeat,
1290 flutter::DlTileMode::kRepeat, flutter::DlImageSampling::kLinear,
1291 &matrix),
1292 flutter::DlColorSource::MakeLinear(
1293 flutter::DlPoint(0, 0), flutter::DlPoint(100, 50), 2, colors.data(),
1294 stops.data(), flutter::DlTileMode::kClamp),
1295 };
1296
1297 builder.Save();
1298 builder.Translate(0, 100);
1299 for (const auto& color_source : color_sources) {
1300 flutter::DlPaint paint;
1301 paint.setColorSource(color_source);
1302 paint.setMaskFilter(blur_filter);
1303
1304 builder.Save();
1305 builder.Translate(100, 0);
1306 paint.setDrawStyle(flutter::DlDrawStyle::kFill);
1307 builder.DrawRoundRect(
1308 DlRoundRect::MakeRectXY(DlRect::MakeWH(100, 50), 30, 30), paint);
1309
1310 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
1311 paint.setStrokeWidth(10);
1312 builder.Translate(200, 0);
1313 builder.DrawRoundRect(
1314 DlRoundRect::MakeRectXY(DlRect::MakeWH(100, 50), 30, 30), paint);
1315
1316 builder.Restore();
1317 builder.Translate(0, 100);
1318 }
1319 builder.Restore();
1320
1321 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1322 }
1323
1324 TEST_P(DisplayListTest, DrawShapes) {
1325 flutter::DisplayListBuilder builder;
1326 std::vector<flutter::DlStrokeJoin> joins = {
1327 flutter::DlStrokeJoin::kBevel,
1328 flutter::DlStrokeJoin::kRound,
1329 flutter::DlStrokeJoin::kMiter,
1330 };
1331 flutter::DlPaint paint = //
1332 flutter::DlPaint() //
1333 .setColor(flutter::DlColor::kWhite()) //
1334 .setDrawStyle(flutter::DlDrawStyle::kFill) //
1335 .setStrokeWidth(10);
1336 flutter::DlPaint stroke_paint = //
1337 flutter::DlPaint() //
1338 .setColor(flutter::DlColor::kWhite()) //
1339 .setDrawStyle(flutter::DlDrawStyle::kStroke) //
1340 .setStrokeWidth(10);
1341 DlPath path = DlPath::MakeLine({150, 50}, {160, 50});
1342
1343 builder.Translate(300, 50);
1344 builder.Scale(0.8, 0.8);
1345 for (auto join : joins) {
1346 paint.setStrokeJoin(join);
1347 stroke_paint.setStrokeJoin(join);
1348 builder.DrawRect(DlRect::MakeXYWH(0, 0, 100, 100), paint);
1349 builder.DrawRect(DlRect::MakeXYWH(0, 150, 100, 100), stroke_paint);
1350 builder.DrawRoundRect(
1351 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(150, 0, 100, 100), 30, 30),
1352 paint);
1353 builder.DrawRoundRect(
1354 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(150, 150, 100, 100), 30, 30),
1355 stroke_paint);
1356 builder.DrawCircle(DlPoint(350, 50), 50, paint);
1357 builder.DrawCircle(DlPoint(350, 200), 50, stroke_paint);
1358 builder.Translate(0, 300);
1359 }
1360 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1361 }
1362
1363 TEST_P(DisplayListTest, DrawCirclesWithTransformations) {
1364 auto callback = [&]() {
1365 static float filled_radius = 100.0;
1366 static float filled_alpha = 255.0;
1367 static float filled_scale[2] = {1.0, 1.0};
1368 static float stroked_radius = 20.0;
1369 static float stroke_width = 10.0;
1370 static float stroked_alpha = 255.0;
1371 static float stroked_scale[2] = {1.0, 1.0};
1372
1373 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1374 {
1375 ImGui::SliderFloat("Filled Radius", &filled_radius, 0, 500);
1376 ImGui::SliderFloat("Filled Alpha", &filled_alpha, 0, 255);
1377 ImGui::SliderFloat2("Filled Scale", filled_scale, 0, 10.0);
1378 ImGui::SliderFloat("Stroked Radius", &stroked_radius, 0, 10.0);
1379 ImGui::SliderFloat("Stroked Width", &stroke_width, 0, 500);
1380 ImGui::SliderFloat("Stroked Alpha", &stroked_alpha, 0, 10.0);
1381 ImGui::SliderFloat2("Stroked Scale", stroked_scale, 0, 10.0);
1382 }
1383 ImGui::End();
1384
1385 flutter::DisplayListBuilder builder;
1386 flutter::DlPaint paint;
1387
1388 paint.setColor(flutter::DlColor::kBlue().withAlpha(filled_alpha));
1389 paint.setDrawStyle(flutter::DlDrawStyle::kFill);
1390 builder.Save();
1391 builder.Scale(filled_scale[0], filled_scale[1]);
1392 builder.DrawCircle(DlPoint(500, 750), filled_radius, paint);
1393 builder.Restore();
1394
1395 paint.setColor(flutter::DlColor::kRed().withAlpha(stroked_alpha));
1396 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
1397 paint.setStrokeWidth(stroke_width);
1398 builder.Save();
1399 builder.Scale(stroked_scale[0], stroked_scale[1]);
1400 builder.DrawCircle(DlPoint(1250, 750), stroked_radius, paint);
1401 builder.Restore();
1402 return builder.Build();
1403 };
1404
1405 ASSERT_TRUE(OpenPlaygroundHere(callback));
1406 }
1407
1408 TEST_P(DisplayListTest, ClipDrawRRectWithNonCircularRadii) {
1409 flutter::DisplayListBuilder builder;
1410
1411 flutter::DlPaint fill_paint = //
1412 flutter::DlPaint() //
1413 .setColor(flutter::DlColor::kBlue()) //
1414 .setDrawStyle(flutter::DlDrawStyle::kFill) //
1415 .setStrokeWidth(10);
1416 flutter::DlPaint stroke_paint = //
1417 flutter::DlPaint() //
1418 .setColor(flutter::DlColor::kGreen()) //
1419 .setDrawStyle(flutter::DlDrawStyle::kStroke) //
1420 .setStrokeWidth(10);
1421
1422 builder.DrawRoundRect(
1423 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(500, 100, 300, 300), 120, 40),
1424 fill_paint);
1425 builder.DrawRoundRect(
1426 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(500, 100, 300, 300), 120, 40),
1427 stroke_paint);
1428
1429 builder.DrawRoundRect(
1430 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(100, 500, 300, 300), 40, 120),
1431 fill_paint);
1432 builder.DrawRoundRect(
1433 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(100, 500, 300, 300), 40, 120),
1434 stroke_paint);
1435
1436 flutter::DlPaint reference_paint = //
1437 flutter::DlPaint() //
1438 .setColor(flutter::DlColor::kMidGrey()) //
1439 .setDrawStyle(flutter::DlDrawStyle::kFill) //
1440 .setStrokeWidth(10);
1441
1442 builder.DrawRoundRect(
1443 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(500, 500, 300, 300), 40, 40),
1444 reference_paint);
1445 builder.DrawRoundRect(
1446 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(100, 100, 300, 300), 120, 120),
1447 reference_paint);
1448
1449 flutter::DlPaint clip_fill_paint = //
1450 flutter::DlPaint() //
1451 .setColor(flutter::DlColor::kCyan()) //
1452 .setDrawStyle(flutter::DlDrawStyle::kFill) //
1453 .setStrokeWidth(10);
1454
1455 builder.Save();
1456 builder.ClipRoundRect(
1457 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(900, 100, 300, 300), 120, 40));
1458 builder.DrawPaint(clip_fill_paint);
1459 builder.Restore();
1460
1461 builder.Save();
1462 builder.ClipRoundRect(
1463 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(100, 900, 300, 300), 40, 120));
1464 builder.DrawPaint(clip_fill_paint);
1465 builder.Restore();
1466
1467 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1468 }
1469
1470 TEST_P(DisplayListTest, DrawVerticesBlendModes) {
1471 std::vector<const char*> blend_mode_names;
1472 std::vector<flutter::DlBlendMode> blend_mode_values;
1473 {
1474 const std::vector<std::tuple<const char*, flutter::DlBlendMode>> blends = {
1475 // Pipeline blends (Porter-Duff alpha compositing)
1476 {"Clear", flutter::DlBlendMode::kClear},
1477 {"Source", flutter::DlBlendMode::kSrc},
1478 {"Destination", flutter::DlBlendMode::kDst},
1479 {"SourceOver", flutter::DlBlendMode::kSrcOver},
1480 {"DestinationOver", flutter::DlBlendMode::kDstOver},
1481 {"SourceIn", flutter::DlBlendMode::kSrcIn},
1482 {"DestinationIn", flutter::DlBlendMode::kDstIn},
1483 {"SourceOut", flutter::DlBlendMode::kSrcOut},
1484 {"DestinationOut", flutter::DlBlendMode::kDstOut},
1485 {"SourceATop", flutter::DlBlendMode::kSrcATop},
1486 {"DestinationATop", flutter::DlBlendMode::kDstATop},
1487 {"Xor", flutter::DlBlendMode::kXor},
1488 {"Plus", flutter::DlBlendMode::kPlus},
1489 {"Modulate", flutter::DlBlendMode::kModulate},
1490 // Advanced blends (color component blends)
1491 {"Screen", flutter::DlBlendMode::kScreen},
1492 {"Overlay", flutter::DlBlendMode::kOverlay},
1493 {"Darken", flutter::DlBlendMode::kDarken},
1494 {"Lighten", flutter::DlBlendMode::kLighten},
1495 {"ColorDodge", flutter::DlBlendMode::kColorDodge},
1496 {"ColorBurn", flutter::DlBlendMode::kColorBurn},
1497 {"HardLight", flutter::DlBlendMode::kHardLight},
1498 {"SoftLight", flutter::DlBlendMode::kSoftLight},
1499 {"Difference", flutter::DlBlendMode::kDifference},
1500 {"Exclusion", flutter::DlBlendMode::kExclusion},
1501 {"Multiply", flutter::DlBlendMode::kMultiply},
1502 {"Hue", flutter::DlBlendMode::kHue},
1503 {"Saturation", flutter::DlBlendMode::kSaturation},
1504 {"Color", flutter::DlBlendMode::kColor},
1505 {"Luminosity", flutter::DlBlendMode::kLuminosity},
1506 };
1507 assert(blends.size() ==
1508 static_cast<size_t>(flutter::DlBlendMode::kLastMode) + 1);
1509 for (const auto& [name, mode] : blends) {
1510 blend_mode_names.push_back(name);
1511 blend_mode_values.push_back(mode);
1512 }
1513 }
1514
1515 auto callback = [&]() {
1516 static int current_blend_index = 3;
1517 static float dst_alpha = 1;
1518 static float src_alpha = 1;
1519 static float color0[4] = {1.0f, 0.0f, 0.0f, 1.0f};
1520 static float color1[4] = {0.0f, 1.0f, 0.0f, 1.0f};
1521 static float color2[4] = {0.0f, 0.0f, 1.0f, 1.0f};
1522 static float src_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
1523
1524 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1525 {
1526 ImGui::ListBox("Blending mode", &current_blend_index,
1527 blend_mode_names.data(), blend_mode_names.size());
1528 ImGui::SliderFloat("Source alpha", &src_alpha, 0, 1);
1529 ImGui::ColorEdit4("Color A", color0);
1530 ImGui::ColorEdit4("Color B", color1);
1531 ImGui::ColorEdit4("Color C", color2);
1532 ImGui::ColorEdit4("Source Color", src_color);
1533 ImGui::SliderFloat("Destination alpha", &dst_alpha, 0, 1);
1534 }
1535 ImGui::End();
1536
1537 std::vector<DlPoint> positions = {DlPoint(100, 300), //
1538 DlPoint(200, 100), //
1539 DlPoint(300, 300)};
1540 std::vector<flutter::DlColor> colors = {
1541 toColor(color0).modulateOpacity(dst_alpha),
1542 toColor(color1).modulateOpacity(dst_alpha),
1543 toColor(color2).modulateOpacity(dst_alpha)};
1544
1545 auto vertices = flutter::DlVertices::Make(
1546 flutter::DlVertexMode::kTriangles, 3, positions.data(),
1547 /*texture_coordinates=*/nullptr, colors.data());
1548
1549 flutter::DisplayListBuilder builder;
1550 flutter::DlPaint paint;
1551
1552 paint.setColor(toColor(src_color).modulateOpacity(src_alpha));
1553 builder.DrawVertices(vertices, blend_mode_values[current_blend_index],
1554 paint);
1555 return builder.Build();
1556 };
1557
1558 ASSERT_TRUE(OpenPlaygroundHere(callback));
1559 }
1560
1561 TEST_P(DisplayListTest, DrawPaintIgnoresMaskFilter) {
1562 flutter::DisplayListBuilder builder;
1563 builder.DrawPaint(flutter::DlPaint().setColor(flutter::DlColor::kWhite()));
1564
1565 auto filter = flutter::DlBlurMaskFilter(flutter::DlBlurStyle::kNormal, 10.0f);
1566 builder.DrawCircle(DlPoint(300, 300), 200,
1567 flutter::DlPaint().setMaskFilter(&filter));
1568
1569 std::vector<flutter::DlColor> colors = {flutter::DlColor::kGreen(),
1570 flutter::DlColor::kGreen()};
1571 const float stops[2] = {0.0, 1.0};
1572 auto linear = flutter::DlColorSource::MakeLinear(
1573 {100.0, 100.0}, {300.0, 300.0}, 2, colors.data(), stops,
1574 flutter::DlTileMode::kRepeat);
1575 flutter::DlPaint blend_paint =
1576 flutter::DlPaint() //
1577 .setColorSource(linear) //
1578 .setBlendMode(flutter::DlBlendMode::kScreen);
1579 builder.DrawPaint(blend_paint);
1580
1581 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1582 }
1583
1584 TEST_P(DisplayListTest, DrawMaskBlursThatMightUseSaveLayers) {
1585 flutter::DisplayListBuilder builder;
1586 builder.DrawColor(flutter::DlColor::kWhite(), flutter::DlBlendMode::kSrc);
1587 Vector2 scale = GetContentScale();
1588 builder.Scale(scale.x, scale.y);
1589
1590 builder.Save();
1591 // We need a small transform op to avoid a deferred save
1592 builder.Translate(1.0f, 1.0f);
1593 auto solid_filter =
1594 flutter::DlBlurMaskFilter::Make(flutter::DlBlurStyle::kSolid, 5.0f);
1595 flutter::DlPaint solid_alpha_paint =
1596 flutter::DlPaint() //
1597 .setMaskFilter(solid_filter) //
1598 .setColor(flutter::DlColor::kBlue()) //
1599 .setAlpha(0x7f);
1600 for (int x = 1; x <= 4; x++) {
1601 for (int y = 1; y <= 4; y++) {
1602 builder.DrawRect(DlRect::MakeXYWH(x * 100, y * 100, 80, 80),
1603 solid_alpha_paint);
1604 }
1605 }
1606 builder.Restore();
1607
1608 builder.Save();
1609 builder.Translate(500.0f, 0.0f);
1610 auto normal_filter =
1611 flutter::DlBlurMaskFilter::Make(flutter::DlBlurStyle::kNormal, 5.0f);
1612 auto rotate_if = flutter::DlMatrixImageFilter::Make(
1613 Matrix::MakeRotationZ(Degrees(10)), flutter::DlImageSampling::kLinear);
1614 flutter::DlPaint normal_if_paint =
1615 flutter::DlPaint() //
1616 .setMaskFilter(solid_filter) //
1617 .setImageFilter(rotate_if) //
1618 .setColor(flutter::DlColor::kGreen()) //
1619 .setAlpha(0x7f);
1620 for (int x = 1; x <= 4; x++) {
1621 for (int y = 1; y <= 4; y++) {
1622 builder.DrawRect(DlRect::MakeXYWH(x * 100, y * 100, 80, 80),
1623 normal_if_paint);
1624 }
1625 }
1626 builder.Restore();
1627
1628 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1629 }
1630
1631 } // namespace testing
1632 } // namespace impeller
aiks_context.h
use_center
bool use_center
Definition: aiks_dl_basic_unittests.cc:830
impeller::DlImageImpeller::Make
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
Definition: dl_image_impeller.cc:23
impeller::DlPlayground
Definition: dl_playground.h:16
clip_contents.h
dl_dispatcher.h
x
int32_t x
Definition: dl_golden_unittests.cc:458
dl_image_impeller.h
dl_playground.h
constants.h
impeller::testing::TEST_P
TEST_P(AiksTest, DrawAtlasNoColor)
Definition: aiks_dl_atlas_unittests.cc:59
impeller::testing::toColor
flutter::DlColor toColor(const float *components)
Definition: dl_unittests.cc:39
impeller::testing::INSTANTIATE_PLAYGROUND_SUITE
INSTANTIATE_PLAYGROUND_SUITE(AiksTest)
impeller
Definition: allocation.cc:12
impeller::DlRect
flutter::DlRect DlRect
Definition: dl_dispatcher.h:25
impeller::kPi
constexpr float kPi
Definition: constants.h:26
impeller::DrawPlaygroundPoint
Point DrawPlaygroundPoint(PlaygroundPoint &point)
Definition: widgets.cc:11
impeller::DrawPlaygroundLine
std::tuple< Point, Point > DrawPlaygroundLine(PlaygroundPoint &point_a, PlaygroundPoint &point_b)
Definition: widgets.cc:51
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::DlPoint
flutter::DlPoint DlPoint
Definition: dl_dispatcher.h:24
impeller::DlPath
flutter::DlPath DlPath
Definition: dl_dispatcher.h:29
impeller::DlScalar
flutter::DlScalar DlScalar
Definition: dl_dispatcher.h:23
point.h
scalar.h
solid_color_contents.h
solid_rrect_blur_contents.h
impeller::Color
Definition: color.h:124
impeller::Color::ToIColor
static uint32_t ToIColor(Color color)
Convert this color to a 32-bit representation.
Definition: color.h:159
impeller::Color::White
static constexpr Color White()
Definition: color.h:264
impeller::Color::Red
static constexpr Color Red()
Definition: color.h:272
impeller::Degrees
Definition: scalar.h:66
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
impeller::Matrix::Translate
constexpr Matrix Translate(const Vector3 &t) const
Definition: matrix.h:263
impeller::Matrix::MakeRow
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
impeller::Matrix::Scale
constexpr Matrix Scale(const Vector3 &s) const
Definition: matrix.h:275
impeller::Matrix::MakeRotationZ
static Matrix MakeRotationZ(Radians r)
Definition: matrix.h:223
impeller::PlaygroundPoint
Definition: widgets.h:21
impeller::TPoint< Scalar >
impeller::TPoint::y
Type y
Definition: point.h:31
impeller::TPoint::x
Type x
Definition: point.h:30
points
std::vector< Point > points
Definition: tessellator_libtess.cc:76
widgets.h