Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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_tile_mode.h"
15#include "flutter/display_list/effects/dl_color_filter.h"
16#include "flutter/display_list/effects/dl_color_source.h"
17#include "flutter/display_list/effects/dl_image_filter.h"
18#include "flutter/display_list/effects/dl_mask_filter.h"
19#include "flutter/testing/testing.h"
20#include "gtest/gtest.h"
31#include "impeller/scene/node.h"
32#include "third_party/imgui/imgui.h"
37
38namespace impeller {
39namespace testing {
40
41flutter::DlColor toColor(const float* components) {
43 Color(components[0], components[1], components[2], components[3])));
44}
45
48
49TEST_P(DisplayListTest, CanDrawRect) {
51 builder.DrawRect(SkRect::MakeXYWH(10, 10, 100, 100),
53 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
54}
55
56TEST_P(DisplayListTest, CanDrawTextBlob) {
58 builder.DrawTextBlob(SkTextBlob::MakeFromString("Hello", CreateTestFont()),
60 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
61}
62
63TEST_P(DisplayListTest, CanDrawTextBlobWithGradient) {
65
66 std::vector<flutter::DlColor> colors = {flutter::DlColor::kBlue(),
68 const float stops[2] = {0.0, 1.0};
69
70 auto linear = flutter::DlColorSource::MakeLinear({0.0, 0.0}, {300.0, 300.0},
71 2, colors.data(), stops,
74 paint.setColorSource(linear);
75
76 builder.DrawTextBlob(
77 SkTextBlob::MakeFromString("Hello World", CreateTestFont()), 100, 100,
78 paint);
79 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
80}
81
82TEST_P(DisplayListTest, CanDrawTextWithSaveLayer) {
84 builder.DrawTextBlob(SkTextBlob::MakeFromString("Hello", CreateTestFont()),
86
87 flutter::DlPaint save_paint;
88 float alpha = 0.5;
89 save_paint.setAlpha(static_cast<uint8_t>(255 * alpha));
90 builder.SaveLayer(nullptr, &save_paint);
91 builder.DrawTextBlob(SkTextBlob::MakeFromString("Hello with half alpha",
92 CreateTestFontOfSize(100)),
94 builder.Restore();
95 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
96}
97
98TEST_P(DisplayListTest, CanDrawImage) {
99 auto texture = CreateTextureForFixture("embarcadero.jpg");
101 builder.DrawImage(DlImageImpeller::Make(texture), SkPoint::Make(100, 100),
103 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
104}
105
106TEST_P(DisplayListTest, CanDrawCapsAndJoins) {
109
111 paint.setStrokeWidth(30);
112 paint.setColor(flutter::DlColor::kRed());
113
114 auto path =
115 SkPathBuilder{}.moveTo(-50, 0).lineTo(0, -50).lineTo(50, 0).snapshot();
116
117 builder.Translate(100, 100);
118 {
121 paint.setStrokeMiter(4);
122 builder.DrawPath(path, paint);
123 }
124
125 {
126 builder.Save();
127 builder.Translate(0, 100);
128 // The joint in the path is 45 degrees. A miter length of 1 convert to a
129 // bevel in this case.
130 paint.setStrokeMiter(1);
131 builder.DrawPath(path, paint);
132 builder.Restore();
133 }
134
135 builder.Translate(150, 0);
136 {
139 builder.DrawPath(path, paint);
140 }
141
142 builder.Translate(150, 0);
143 {
146 builder.DrawPath(path, paint);
147 }
148
149 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
150}
151
153 auto callback = [&]() {
154 static float start_angle = 45;
155 static float sweep_angle = 270;
156 static float stroke_width = 10;
157 static bool use_center = true;
158
159 static int selected_cap = 0;
160 const char* cap_names[] = {"Butt", "Round", "Square"};
162
163 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
164 ImGui::SliderFloat("Start angle", &start_angle, -360, 360);
165 ImGui::SliderFloat("Sweep angle", &sweep_angle, -360, 360);
166 ImGui::SliderFloat("Stroke width", &stroke_width, 0, 300);
167 ImGui::Combo("Cap", &selected_cap, cap_names,
168 sizeof(cap_names) / sizeof(char*));
169 ImGui::Checkbox("Use center", &use_center);
170 ImGui::End();
171
172 switch (selected_cap) {
173 case 0:
175 break;
176 case 1:
178 break;
179 case 2:
181 break;
182 default:
184 break;
185 }
186
187 static PlaygroundPoint point_a(Point(200, 200), 20, Color::White());
188 static PlaygroundPoint point_b(Point(400, 400), 20, Color::White());
189 auto [p1, p2] = DrawPlaygroundLine(point_a, point_b);
190
193
194 Vector2 scale = GetContentScale();
195 builder.Scale(scale.x, scale.y);
197 paint.setStrokeCap(cap);
199 paint.setStrokeMiter(10);
200 auto rect = SkRect::MakeLTRB(p1.x, p1.y, p2.x, p2.y);
202 paint.setStrokeWidth(2);
203 builder.DrawRect(rect, paint);
204 paint.setColor(flutter::DlColor::kRed());
205 paint.setStrokeWidth(stroke_width);
206 builder.DrawArc(rect, start_angle, sweep_angle, use_center, paint);
207
208 return builder.Build();
209 };
210 ASSERT_TRUE(OpenPlaygroundHere(callback));
211}
212
213TEST_P(DisplayListTest, StrokedPathsDrawCorrectly) {
214 auto callback = [&]() {
217
218 paint.setColor(flutter::DlColor::kRed());
220
221 static float stroke_width = 10.0f;
222 static int selected_stroke_type = 0;
223 static int selected_join_type = 0;
224 const char* stroke_types[] = {"Butte", "Round", "Square"};
225 const char* join_type[] = {"kMiter", "Round", "kBevel"};
226
227 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
228 ImGui::Combo("Cap", &selected_stroke_type, stroke_types,
229 sizeof(stroke_types) / sizeof(char*));
230 ImGui::Combo("Join", &selected_join_type, join_type,
231 sizeof(join_type) / sizeof(char*));
232 ImGui::SliderFloat("Stroke Width", &stroke_width, 10.0f, 50.0f);
233 ImGui::End();
234
237 switch (selected_stroke_type) {
238 case 0:
240 break;
241 case 1:
243 break;
244 case 2:
246 break;
247 default:
249 break;
250 }
251 switch (selected_join_type) {
252 case 0:
254 break;
255 case 1:
257 break;
258 case 2:
260 break;
261 default:
263 break;
264 }
265 paint.setStrokeCap(cap);
266 paint.setStrokeJoin(join);
267 paint.setStrokeWidth(stroke_width);
268
269 // Make rendering better to watch.
270 builder.Scale(1.5f, 1.5f);
271
272 // Rectangle
273 builder.Translate(100, 100);
274 builder.DrawRect(SkRect::MakeSize({100, 100}), paint);
275
276 // Rounded rectangle
277 builder.Translate(150, 0);
278 builder.DrawRRect(SkRRect::MakeRectXY(SkRect::MakeSize({100, 50}), 10, 10),
279 paint);
280
281 // Double rounded rectangle
282 builder.Translate(150, 0);
283 builder.DrawDRRect(
284 SkRRect::MakeRectXY(SkRect::MakeSize({100, 50}), 10, 10),
285 SkRRect::MakeRectXY(SkRect::MakeXYWH(10, 10, 80, 30), 10, 10), paint);
286
287 // Contour with duplicate join points
288 {
289 builder.Translate(150, 0);
290 SkPath path;
291 path.moveTo(0, 0);
292 path.lineTo(0, 0);
293 path.lineTo({100, 0});
294 path.lineTo({100, 0});
295 path.lineTo({100, 100});
296 builder.DrawPath(path, paint);
297 }
298
299 // Contour with duplicate start and end points
300
301 // Line.
302 builder.Translate(200, 0);
303 {
304 builder.Save();
305
306 SkPath line_path;
307 line_path.moveTo(0, 0);
308 line_path.moveTo(0, 0);
309 line_path.lineTo({0, 0});
310 line_path.lineTo({0, 0});
311 line_path.lineTo({50, 50});
312 line_path.lineTo({50, 50});
313 line_path.lineTo({100, 0});
314 line_path.lineTo({100, 0});
315 builder.DrawPath(line_path, paint);
316
317 builder.Translate(0, 100);
318 builder.DrawPath(line_path, paint);
319
320 builder.Translate(0, 100);
321 SkPath line_path2;
322 line_path2.moveTo(0, 0);
323 line_path2.lineTo(0, 0);
324 line_path2.lineTo(0, 0);
325 builder.DrawPath(line_path2, paint);
326
327 builder.Restore();
328 }
329
330 // Cubic.
331 builder.Translate(150, 0);
332 {
333 builder.Save();
334
336 cubic_path.moveTo({0, 0});
337 cubic_path.cubicTo(0, 0, 140.0, 100.0, 140, 20);
338 builder.DrawPath(cubic_path, paint);
339
340 builder.Translate(0, 100);
341 SkPath cubic_path2;
342 cubic_path2.moveTo({0, 0});
343 cubic_path2.cubicTo(0, 0, 0, 0, 150, 150);
344 builder.DrawPath(cubic_path2, paint);
345
346 builder.Translate(0, 100);
347 SkPath cubic_path3;
348 cubic_path3.moveTo({0, 0});
349 cubic_path3.cubicTo(0, 0, 0, 0, 0, 0);
350 builder.DrawPath(cubic_path3, paint);
351
352 builder.Restore();
353 }
354
355 // Quad.
356 builder.Translate(200, 0);
357 {
358 builder.Save();
359
361 quad_path.moveTo(0, 0);
362 quad_path.moveTo(0, 0);
363 quad_path.quadTo({100, 40}, {50, 80});
364 builder.DrawPath(quad_path, paint);
365
366 builder.Translate(0, 150);
367 SkPath quad_path2;
368 quad_path2.moveTo(0, 0);
369 quad_path2.moveTo(0, 0);
370 quad_path2.quadTo({0, 0}, {100, 100});
371 builder.DrawPath(quad_path2, paint);
372
373 builder.Translate(0, 100);
374 SkPath quad_path3;
375 quad_path3.moveTo(0, 0);
376 quad_path3.quadTo({0, 0}, {0, 0});
377 builder.DrawPath(quad_path3, paint);
378
379 builder.Restore();
380 }
381 return builder.Build();
382 };
383 ASSERT_TRUE(OpenPlaygroundHere(callback));
384}
385
386TEST_P(DisplayListTest, CanDrawWithOddPathWinding) {
389
390 paint.setColor(flutter::DlColor::kRed());
392
393 builder.Translate(300, 300);
394 SkPath path;
395 path.setFillType(SkPathFillType::kEvenOdd);
396 path.addCircle(0, 0, 100);
397 path.addCircle(0, 0, 50);
398 builder.DrawPath(path, paint);
399
400 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
401}
402
403// Regression test for https://github.com/flutter/flutter/issues/134816.
404//
405// It should be possible to draw 3 lines, and not have an implicit close path.
406TEST_P(DisplayListTest, CanDrawAnOpenPath) {
409
410 paint.setColor(flutter::DlColor::kRed());
412 paint.setStrokeWidth(10);
413
414 builder.Translate(300, 300);
415
416 // Move to (50, 50) and draw lines from:
417 // 1. (50, height)
418 // 2. (width, height)
419 // 3. (width, 50)
420 SkPath path;
421 path.moveTo(50, 50);
422 path.lineTo(50, 100);
423 path.lineTo(100, 100);
424 path.lineTo(100, 50);
425 builder.DrawPath(path, paint);
426
427 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
428}
429
430TEST_P(DisplayListTest, CanDrawWithMaskBlur) {
431 auto texture = CreateTextureForFixture("embarcadero.jpg");
434
435 // Mask blurred image.
436 {
437 auto filter =
439 paint.setMaskFilter(&filter);
440 builder.DrawImage(DlImageImpeller::Make(texture), SkPoint::Make(100, 100),
442 }
443
444 // Mask blurred filled path.
445 {
447 auto filter =
449 paint.setMaskFilter(&filter);
450 builder.DrawArc(SkRect::MakeXYWH(410, 110, 100, 100), 45, 270, true, paint);
451 }
452
453 // Mask blurred text.
454 {
455 auto filter =
457 paint.setMaskFilter(&filter);
458 builder.DrawTextBlob(
459 SkTextBlob::MakeFromString("Testing", CreateTestFont()), 220, 170,
460 paint);
461 }
462
463 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
464}
465
466TEST_P(DisplayListTest, CanDrawStrokedText) {
469
471 paint.setColor(flutter::DlColor::kRed());
472 builder.DrawTextBlob(
473 SkTextBlob::MakeFromString("stoked about stroked text", CreateTestFont()),
474 250, 250, paint);
475
476 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
477}
478
479// Regression test for https://github.com/flutter/flutter/issues/133157.
480TEST_P(DisplayListTest, StrokedTextNotOffsetFromNormalText) {
483 auto const& text_blob = SkTextBlob::MakeFromString("00000", CreateTestFont());
484
485 // https://api.flutter.dev/flutter/material/Colors/blue-constant.html.
486 auto const& mat_blue = flutter::DlColor(0xFF2196f3);
487
488 // Draw a blue filled rectangle so the text is easier to see.
490 paint.setColor(mat_blue);
491 builder.DrawRect(SkRect::MakeXYWH(0, 0, 500, 500), paint);
492
493 // Draw stacked text, with stroked text on top.
496 builder.DrawTextBlob(text_blob, 250, 250, paint);
497
500 builder.DrawTextBlob(text_blob, 250, 250, paint);
501
502 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
503}
504
505TEST_P(DisplayListTest, IgnoreMaskFilterWhenSavingLayer) {
506 auto texture = CreateTextureForFixture("embarcadero.jpg");
510 paint.setMaskFilter(&filter);
511 builder.SaveLayer(nullptr, &paint);
512 builder.DrawImage(DlImageImpeller::Make(texture), SkPoint::Make(100, 100),
514 builder.Restore();
515 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
516}
517
518TEST_P(DisplayListTest, CanDrawWithBlendColorFilter) {
519 auto texture = CreateTextureForFixture("embarcadero.jpg");
522
523 // Pipeline blended image.
524 {
527 paint.setColorFilter(&filter);
528 builder.DrawImage(DlImageImpeller::Make(texture), SkPoint::Make(100, 100),
530 }
531
532 // Advanced blended image.
533 {
536 paint.setColorFilter(&filter);
537 builder.DrawImage(DlImageImpeller::Make(texture), SkPoint::Make(250, 250),
539 }
540
541 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
542}
543
544TEST_P(DisplayListTest, CanDrawWithColorFilterImageFilter) {
545 const float invert_color_matrix[20] = {
546 -1, 0, 0, 0, 1, //
547 0, -1, 0, 0, 1, //
548 0, 0, -1, 0, 1, //
549 0, 0, 0, 1, 0, //
550 };
551 auto texture = CreateTextureForFixture("boston.jpg");
554
555 auto color_filter =
556 std::make_shared<flutter::DlMatrixColorFilter>(invert_color_matrix);
557 auto image_filter =
558 std::make_shared<flutter::DlColorFilterImageFilter>(color_filter);
559
560 paint.setImageFilter(image_filter.get());
561 builder.DrawImage(DlImageImpeller::Make(texture), SkPoint::Make(100, 100),
563
564 builder.Translate(0, 700);
565 paint.setColorFilter(color_filter.get());
566 builder.DrawImage(DlImageImpeller::Make(texture), SkPoint::Make(100, 100),
568 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
569}
570
571TEST_P(DisplayListTest, CanDrawWithImageBlurFilter) {
572 auto texture = CreateTextureForFixture("embarcadero.jpg");
573
574 auto callback = [&]() {
575 static float sigma[] = {10, 10};
576
577 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
578 ImGui::SliderFloat2("Sigma", sigma, 0, 100);
579 ImGui::End();
580
583
584 auto filter = flutter::DlBlurImageFilter(sigma[0], sigma[1],
586 paint.setImageFilter(&filter);
587 builder.DrawImage(DlImageImpeller::Make(texture), SkPoint::Make(200, 200),
589
590 return builder.Build();
591 };
592
593 ASSERT_TRUE(OpenPlaygroundHere(callback));
594}
595
596TEST_P(DisplayListTest, CanDrawWithComposeImageFilter) {
597 auto texture = CreateTextureForFixture("boston.jpg");
600
601 auto dilate = std::make_shared<flutter::DlDilateImageFilter>(10.0, 10.0);
602 auto erode = std::make_shared<flutter::DlErodeImageFilter>(10.0, 10.0);
603 auto open = std::make_shared<flutter::DlComposeImageFilter>(dilate, erode);
604 auto close = std::make_shared<flutter::DlComposeImageFilter>(erode, dilate);
605
606 paint.setImageFilter(open.get());
607 builder.DrawImage(DlImageImpeller::Make(texture), SkPoint::Make(100, 100),
609 builder.Translate(0, 700);
610 paint.setImageFilter(close.get());
611 builder.DrawImage(DlImageImpeller::Make(texture), SkPoint::Make(100, 100),
613 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
614}
615
616TEST_P(DisplayListTest, CanClampTheResultingColorOfColorMatrixFilter) {
617 auto texture = CreateTextureForFixture("boston.jpg");
618 const float inner_color_matrix[20] = {
619 1, 0, 0, 0, 0, //
620 0, 1, 0, 0, 0, //
621 0, 0, 1, 0, 0, //
622 0, 0, 0, 2, 0, //
623 };
624 const float outer_color_matrix[20] = {
625 1, 0, 0, 0, 0, //
626 0, 1, 0, 0, 0, //
627 0, 0, 1, 0, 0, //
628 0, 0, 0, 0.5, 0, //
629 };
630 auto inner_color_filter =
631 std::make_shared<flutter::DlMatrixColorFilter>(inner_color_matrix);
632 auto outer_color_filter =
633 std::make_shared<flutter::DlMatrixColorFilter>(outer_color_matrix);
634 auto inner =
635 std::make_shared<flutter::DlColorFilterImageFilter>(inner_color_filter);
636 auto outer =
637 std::make_shared<flutter::DlColorFilterImageFilter>(outer_color_filter);
638 auto compose = std::make_shared<flutter::DlComposeImageFilter>(outer, inner);
639
642 paint.setImageFilter(compose.get());
643 builder.DrawImage(DlImageImpeller::Make(texture), SkPoint::Make(100, 100),
645 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
646}
647
648TEST_P(DisplayListTest, CanDrawBackdropFilter) {
649 auto texture = CreateTextureForFixture("embarcadero.jpg");
650
651 auto callback = [&]() {
652 static float sigma[] = {10, 10};
653 static float ctm_scale = 1;
654 static bool use_bounds = true;
655 static bool draw_circle = true;
656 static bool add_clip = true;
657
658 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
659 ImGui::SliderFloat2("Sigma", sigma, 0, 100);
660 ImGui::SliderFloat("Scale", &ctm_scale, 0, 10);
661 ImGui::NewLine();
662 ImGui::TextWrapped(
663 "If everything is working correctly, none of the options below should "
664 "impact the filter's appearance.");
665 ImGui::Checkbox("Use SaveLayer bounds", &use_bounds);
666 ImGui::Checkbox("Draw child element", &draw_circle);
667 ImGui::Checkbox("Add pre-clip", &add_clip);
668 ImGui::End();
669
671
672 Vector2 scale = ctm_scale * GetContentScale();
673 builder.Scale(scale.x, scale.y);
674
675 auto filter = flutter::DlBlurImageFilter(sigma[0], sigma[1],
677
678 std::optional<SkRect> bounds;
679 if (use_bounds) {
680 static PlaygroundPoint point_a(Point(350, 150), 20, Color::White());
681 static PlaygroundPoint point_b(Point(800, 600), 20, Color::White());
682 auto [p1, p2] = DrawPlaygroundLine(point_a, point_b);
683 bounds = SkRect::MakeLTRB(p1.x, p1.y, p2.x, p2.y);
684 }
685
686 // Insert a clip to test that the backdrop filter handles stencil depths > 0
687 // correctly.
688 if (add_clip) {
689 builder.ClipRect(SkRect::MakeLTRB(0, 0, 99999, 99999),
691 }
692
693 builder.DrawImage(DlImageImpeller::Make(texture), SkPoint::Make(200, 200),
695 builder.SaveLayer(bounds.has_value() ? &bounds.value() : nullptr, nullptr,
696 &filter);
697
698 if (draw_circle) {
699 static PlaygroundPoint center_point(Point(500, 400), 20, Color::Red());
700 auto circle_center = DrawPlaygroundPoint(center_point);
701
706 paint.setStrokeWidth(10);
707 paint.setColor(flutter::DlColor::kRed().withAlpha(100));
708 builder.DrawCircle({circle_center.x, circle_center.y}, 100, paint);
709 }
710
711 return builder.Build();
712 };
713
714 ASSERT_TRUE(OpenPlaygroundHere(callback));
715}
716
717TEST_P(DisplayListTest, CanDrawNinePatchImage) {
718 // Image is drawn with corners to scale and center pieces stretched to fit.
719 auto texture = CreateTextureForFixture("embarcadero.jpg");
721 auto size = texture->GetSize();
722 builder.DrawImageNine(
724 SkIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
725 size.height * 3 / 4),
726 SkRect::MakeLTRB(0, 0, size.width * 2, size.height * 2),
728 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
729}
730
731TEST_P(DisplayListTest, CanDrawNinePatchImageCenterWidthBiggerThanDest) {
732 // Edge case, the width of the corners does not leave any room for the
733 // center slice. The center (across the vertical axis) is folded out of the
734 // resulting image.
735 auto texture = CreateTextureForFixture("embarcadero.jpg");
737 auto size = texture->GetSize();
738 builder.DrawImageNine(
740 SkIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
741 size.height * 3 / 4),
742 SkRect::MakeLTRB(0, 0, size.width / 2, size.height),
744 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
745}
746
747TEST_P(DisplayListTest, CanDrawNinePatchImageCenterHeightBiggerThanDest) {
748 // Edge case, the height of the corners does not leave any room for the
749 // center slice. The center (across the horizontal axis) is folded out of the
750 // resulting image.
751 auto texture = CreateTextureForFixture("embarcadero.jpg");
753 auto size = texture->GetSize();
754 builder.DrawImageNine(
756 SkIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
757 size.height * 3 / 4),
758 SkRect::MakeLTRB(0, 0, size.width, size.height / 2),
760 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
761}
762
763TEST_P(DisplayListTest, CanDrawNinePatchImageCenterBiggerThanDest) {
764 // Edge case, the width and height of the corners does not leave any
765 // room for the center slices. Only the corners are displayed.
766 auto texture = CreateTextureForFixture("embarcadero.jpg");
768 auto size = texture->GetSize();
769 builder.DrawImageNine(
771 SkIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
772 size.height * 3 / 4),
773 SkRect::MakeLTRB(0, 0, size.width / 2, size.height / 2),
775 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
776}
777
778TEST_P(DisplayListTest, CanDrawNinePatchImageCornersScaledDown) {
779 // Edge case, there is not enough room for the corners to be drawn
780 // without scaling them down.
781 auto texture = CreateTextureForFixture("embarcadero.jpg");
783 auto size = texture->GetSize();
784 builder.DrawImageNine(
786 SkIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
787 size.height * 3 / 4),
788 SkRect::MakeLTRB(0, 0, size.width / 4, size.height / 4),
790 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
791}
792
793TEST_P(DisplayListTest, NinePatchImagePrecision) {
794 // Draw a nine patch image with colored corners and verify that the corner
795 // color does not leak outside the intended region.
796 auto texture = CreateTextureForFixture("nine_patch_corners.png");
798 builder.DrawImageNine(DlImageImpeller::Make(texture),
799 SkIRect::MakeXYWH(10, 10, 1, 1),
800 SkRect::MakeXYWH(0, 0, 200, 100),
802 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
803}
804
805TEST_P(DisplayListTest, CanDrawPoints) {
807 SkPoint points[7] = {
808 {0, 0}, //
809 {100, 100}, //
810 {100, 0}, //
811 {0, 100}, //
812 {0, 0}, //
813 {48, 48}, //
814 {52, 52}, //
815 };
816 std::vector<flutter::DlStrokeCap> caps = {
820 };
823 .setColor(flutter::DlColor::kYellow().withAlpha(127)) //
824 .setStrokeWidth(20);
825 builder.Translate(50, 50);
826 for (auto cap : caps) {
827 paint.setStrokeCap(cap);
828 builder.Save();
829 builder.DrawPoints(flutter::DlCanvas::PointMode::kPoints, 7, points, paint);
830 builder.Translate(150, 0);
831 builder.DrawPoints(flutter::DlCanvas::PointMode::kLines, 5, points, paint);
832 builder.Translate(150, 0);
833 builder.DrawPoints(flutter::DlCanvas::PointMode::kPolygon, 5, points,
834 paint);
835 builder.Restore();
836 builder.Translate(0, 150);
837 }
838 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
839}
840
841TEST_P(DisplayListTest, CanDrawZeroLengthLine) {
843 std::vector<flutter::DlStrokeCap> caps = {
847 };
850 .setColor(flutter::DlColor::kYellow().withAlpha(127)) //
853 .setStrokeWidth(20);
854 SkPath path = SkPath().addPoly({{150, 50}, {150, 50}}, false);
855 for (auto cap : caps) {
856 paint.setStrokeCap(cap);
857 builder.DrawLine({50, 50}, {50, 50}, paint);
858 builder.DrawPath(path, paint);
859 builder.Translate(0, 150);
860 }
861 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
862}
863
864TEST_P(DisplayListTest, CanDrawShadow) {
867
868 auto content_scale = GetContentScale() * 0.8;
869 builder.Scale(content_scale.x, content_scale.y);
870
871 constexpr size_t star_spikes = 5;
872 constexpr SkScalar half_spike_rotation = kPi / star_spikes;
873 constexpr SkScalar radius = 40;
874 constexpr SkScalar spike_size = 10;
875 constexpr SkScalar outer_radius = radius + spike_size;
876 constexpr SkScalar inner_radius = radius - spike_size;
877 std::array<SkPoint, star_spikes * 2> star;
878 for (size_t i = 0; i < star_spikes; i++) {
879 const SkScalar rotation = half_spike_rotation * i * 2;
880 star[i * 2] = SkPoint::Make(50 + std::sin(rotation) * outer_radius,
881 50 - std::cos(rotation) * outer_radius);
882 star[i * 2 + 1] = SkPoint::Make(
883 50 + std::sin(rotation + half_spike_rotation) * inner_radius,
884 50 - std::cos(rotation + half_spike_rotation) * inner_radius);
885 }
886
887 std::array<SkPath, 4> paths = {
888 SkPath{}.addRect(SkRect::MakeXYWH(0, 0, 200, 100)),
890 SkRRect::MakeRectXY(SkRect::MakeXYWH(20, 0, 200, 100), 30, 30)),
891 SkPath{}.addCircle(100, 50, 50),
892 SkPath{}.addPoly(star.data(), star.size(), true),
893 };
895 builder.DrawPaint(paint);
896 paint.setColor(flutter::DlColor::kCyan());
897 builder.Translate(100, 50);
898 for (size_t x = 0; x < paths.size(); x++) {
899 builder.Save();
900 for (size_t y = 0; y < 6; y++) {
901 builder.DrawShadow(paths[x], flutter::DlColor::kBlack(), 3 + y * 8, false,
902 1);
903 builder.DrawPath(paths[x], paint);
904 builder.Translate(0, 150);
905 }
906 builder.Restore();
907 builder.Translate(250, 0);
908 }
909
910 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
911}
912
914 DispatcherDoesNotCullPerspectiveTransformedChildDisplayLists) {
915 // Regression test for https://github.com/flutter/flutter/issues/130613
916 flutter::DisplayListBuilder sub_builder(true);
917 sub_builder.DrawRect(SkRect::MakeXYWH(0, 0, 50, 50),
919 auto display_list = sub_builder.Build();
920
921 DlDispatcher dispatcher(Rect::MakeLTRB(0, 0, 2400, 1800));
922 dispatcher.scale(2.0, 2.0);
923 dispatcher.translate(-93.0, 0.0);
924 // clang-format off
925 dispatcher.transformFullPerspective(
926 0.8, -0.2, -0.1, -0.0,
927 0.0, 1.0, 0.0, 0.0,
928 1.4, 1.3, 1.0, 0.0,
929 63.2, 65.3, 48.6, 1.1
930 );
931 // clang-format on
932 dispatcher.translate(35.0, 75.0);
933 dispatcher.drawDisplayList(display_list, 1.0f);
934 auto picture = dispatcher.EndRecordingAsPicture();
935
936 bool found = false;
937 picture.pass->IterateAllEntities([&found](Entity& entity) {
938 if (std::static_pointer_cast<SolidColorContents>(entity.GetContents())
939 ->GetColor() == Color::Red()) {
940 found = true;
941 return false;
942 }
943
944 return true;
945 });
946 EXPECT_TRUE(found);
947}
948
949TEST_P(DisplayListTest, TransparentShadowProducesCorrectColor) {
950 DlDispatcher dispatcher;
951 dispatcher.save();
952 dispatcher.scale(1.618, 1.618);
953 SkPath path = SkPath{}.addRect(SkRect::MakeXYWH(0, 0, 200, 100));
955 dispatcher.drawShadow(cache, flutter::DlColor::kTransparent(), 15, false, 1);
956 dispatcher.restore();
957 auto picture = dispatcher.EndRecordingAsPicture();
958
959 std::shared_ptr<SolidRRectBlurContents> rrect_blur;
960 picture.pass->IterateAllEntities([&rrect_blur](Entity& entity) {
961 if (ScalarNearlyEqual(entity.GetTransform().GetScale().x, 1.618f)) {
962 rrect_blur = std::static_pointer_cast<SolidRRectBlurContents>(
963 entity.GetContents());
964 return false;
965 }
966 return true;
967 });
968
969 ASSERT_NE(rrect_blur, nullptr);
970 ASSERT_EQ(rrect_blur->GetColor().red, 0);
971 ASSERT_EQ(rrect_blur->GetColor().green, 0);
972 ASSERT_EQ(rrect_blur->GetColor().blue, 0);
973 ASSERT_EQ(rrect_blur->GetColor().alpha, 0);
974}
975
976// Draw a hexagon using triangle fan
977TEST_P(DisplayListTest, CanConvertTriangleFanToTriangles) {
978 constexpr Scalar hexagon_radius = 125;
979 auto hex_start = Point(200.0, -hexagon_radius + 200.0);
980 auto center_to_flat = 1.73 / 2 * hexagon_radius;
981
982 // clang-format off
983 std::vector<SkPoint> vertices = {
984 SkPoint::Make(hex_start.x, hex_start.y),
985 SkPoint::Make(hex_start.x + center_to_flat, hex_start.y + 0.5 * hexagon_radius),
986 SkPoint::Make(hex_start.x + center_to_flat, hex_start.y + 1.5 * hexagon_radius),
987 SkPoint::Make(hex_start.x + center_to_flat, hex_start.y + 1.5 * hexagon_radius),
988 SkPoint::Make(hex_start.x, hex_start.y + 2 * hexagon_radius),
989 SkPoint::Make(hex_start.x, hex_start.y + 2 * hexagon_radius),
990 SkPoint::Make(hex_start.x - center_to_flat, hex_start.y + 1.5 * hexagon_radius),
991 SkPoint::Make(hex_start.x - center_to_flat, hex_start.y + 1.5 * hexagon_radius),
992 SkPoint::Make(hex_start.x - center_to_flat, hex_start.y + 0.5 * hexagon_radius)
993 };
994 // clang-format on
996 auto dl_vertices = flutter::DlVertices::Make(
997 flutter::DlVertexMode::kTriangleFan, vertices.size(), vertices.data(),
998 nullptr, nullptr);
1000 builder.DrawVertices(dl_vertices, flutter::DlBlendMode::kSrcOver, paint);
1001 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1002}
1003
1004TEST_P(DisplayListTest, CanDrawZeroWidthLine) {
1006 std::vector<flutter::DlStrokeCap> caps = {
1010 };
1012 flutter::DlPaint() //
1015 .setStrokeWidth(0);
1016 flutter::DlPaint outline_paint = //
1017 flutter::DlPaint() //
1021 .setStrokeWidth(1);
1022 SkPath path = SkPath().addPoly({{150, 50}, {160, 50}}, false);
1023 for (auto cap : caps) {
1024 paint.setStrokeCap(cap);
1025 builder.DrawLine({50, 50}, {60, 50}, paint);
1026 builder.DrawRect({45, 45, 65, 55}, outline_paint);
1027 builder.DrawLine({100, 50}, {100, 50}, paint);
1028 if (cap != flutter::DlStrokeCap::kButt) {
1029 builder.DrawRect({95, 45, 105, 55}, outline_paint);
1030 }
1031 builder.DrawPath(path, paint);
1032 builder.DrawRect(path.getBounds().makeOutset(5, 5), outline_paint);
1033 builder.Translate(0, 150);
1034 }
1035 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1036}
1037
1038TEST_P(DisplayListTest, CanDrawWithMatrixFilter) {
1039 auto boston = CreateTextureForFixture("boston.jpg");
1040
1041 auto callback = [&]() {
1042 static int selected_matrix_type = 0;
1043 const char* matrix_type_names[] = {"Matrix", "Local Matrix"};
1044
1045 static float ctm_translation[2] = {200, 200};
1046 static float ctm_scale[2] = {0.65, 0.65};
1047 static float ctm_skew[2] = {0, 0};
1048
1049 static bool enable = true;
1050 static float translation[2] = {100, 100};
1051 static float scale[2] = {0.8, 0.8};
1052 static float skew[2] = {0.2, 0.2};
1053
1054 static bool enable_savelayer = true;
1055
1056 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1057 {
1058 ImGui::Combo("Filter type", &selected_matrix_type, matrix_type_names,
1059 sizeof(matrix_type_names) / sizeof(char*));
1060
1061 ImGui::TextWrapped("Current Transform");
1062 ImGui::SliderFloat2("CTM Translation", ctm_translation, 0, 1000);
1063 ImGui::SliderFloat2("CTM Scale", ctm_scale, 0, 3);
1064 ImGui::SliderFloat2("CTM Skew", ctm_skew, -3, 3);
1065
1066 ImGui::TextWrapped(
1067 "MatrixFilter and LocalMatrixFilter modify the CTM in the same way. "
1068 "The only difference is that MatrixFilter doesn't affect the effect "
1069 "transform, whereas LocalMatrixFilter does.");
1070 // Note: See this behavior in:
1071 // https://fiddle.skia.org/c/6cbb551ab36d06f163db8693972be954
1072 ImGui::Checkbox("Enable", &enable);
1073 ImGui::SliderFloat2("Filter Translation", translation, 0, 1000);
1074 ImGui::SliderFloat2("Filter Scale", scale, 0, 3);
1075 ImGui::SliderFloat2("Filter Skew", skew, -3, 3);
1076
1077 ImGui::TextWrapped(
1078 "Rendering the filtered image within a layer can expose bounds "
1079 "issues. If the rendered image gets cut off when this setting is "
1080 "enabled, there's a coverage bug in the filter.");
1081 ImGui::Checkbox("Render in layer", &enable_savelayer);
1082 }
1083 ImGui::End();
1084
1087
1088 if (enable_savelayer) {
1089 builder.SaveLayer(nullptr, nullptr);
1090 }
1091 {
1092 auto content_scale = GetContentScale();
1093 builder.Scale(content_scale.x, content_scale.y);
1094
1095 // Set the current transform
1096 auto ctm_matrix =
1097 SkMatrix::MakeAll(ctm_scale[0], ctm_skew[0], ctm_translation[0], //
1098 ctm_skew[1], ctm_scale[1], ctm_translation[1], //
1099 0, 0, 1);
1100 builder.Transform(ctm_matrix);
1101
1102 // Set the matrix filter
1103 auto filter_matrix =
1104 SkMatrix::MakeAll(scale[0], skew[0], translation[0], //
1105 skew[1], scale[1], translation[1], //
1106 0, 0, 1);
1107
1108 if (enable) {
1109 switch (selected_matrix_type) {
1110 case 0: {
1111 auto filter = flutter::DlMatrixImageFilter(
1112 filter_matrix, flutter::DlImageSampling::kLinear);
1113 paint.setImageFilter(&filter);
1114 break;
1115 }
1116 case 1: {
1117 auto internal_filter =
1119 .shared();
1120 auto filter = flutter::DlLocalMatrixImageFilter(filter_matrix,
1121 internal_filter);
1122 paint.setImageFilter(&filter);
1123 break;
1124 }
1125 }
1126 }
1127
1128 builder.DrawImage(DlImageImpeller::Make(boston), {},
1130 }
1131 if (enable_savelayer) {
1132 builder.Restore();
1133 }
1134
1135 return builder.Build();
1136 };
1137
1138 ASSERT_TRUE(OpenPlaygroundHere(callback));
1139}
1140
1141TEST_P(DisplayListTest, CanDrawWithMatrixFilterWhenSavingLayer) {
1142 auto callback = [&]() {
1143 static float translation[2] = {0, 0};
1144 static bool enable_save_layer = true;
1145
1146 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1147 ImGui::SliderFloat2("Translation", translation, -130, 130);
1148 ImGui::Checkbox("Enable save layer", &enable_save_layer);
1149 ImGui::End();
1150
1152 builder.Save();
1153 builder.Scale(2.0, 2.0);
1155 paint.setColor(flutter::DlColor::kYellow());
1156 builder.DrawRect(SkRect::MakeWH(300, 300), paint);
1157 paint.setStrokeWidth(1.0);
1159 paint.setColor(flutter::DlColor::kBlack().withAlpha(0x80));
1160 builder.DrawLine(SkPoint::Make(150, 0), SkPoint::Make(150, 300), paint);
1161 builder.DrawLine(SkPoint::Make(0, 150), SkPoint::Make(300, 150), paint);
1162
1163 flutter::DlPaint save_paint;
1164 SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
1165 SkMatrix translate_matrix =
1166 SkMatrix::Translate(translation[0], translation[1]);
1167 if (enable_save_layer) {
1168 auto filter = flutter::DlMatrixImageFilter(
1170 save_paint.setImageFilter(filter.shared());
1171 builder.SaveLayer(&bounds, &save_paint);
1172 } else {
1173 builder.Save();
1174 builder.Transform(translate_matrix);
1175 }
1176
1177 SkMatrix filter_matrix = SkMatrix::I();
1178 filter_matrix.postTranslate(-150, -150);
1179 filter_matrix.postScale(0.2f, 0.2f);
1180 filter_matrix.postTranslate(150, 150);
1181 auto filter = flutter::DlMatrixImageFilter(
1183
1184 save_paint.setImageFilter(filter.shared());
1185
1186 builder.SaveLayer(&bounds, &save_paint);
1187 flutter::DlPaint paint2;
1189 builder.DrawRect(bounds, paint2);
1190 builder.Restore();
1191 builder.Restore();
1192 return builder.Build();
1193 };
1194
1195 ASSERT_TRUE(OpenPlaygroundHere(callback));
1196}
1197
1198TEST_P(DisplayListTest, CanDrawRectWithLinearToSrgbColorFilter) {
1200 paint.setColor(flutter::DlColor(0xFF2196F3).withAlpha(128));
1202 paint.setColorFilter(
1204 builder.DrawRect(SkRect::MakeXYWH(0, 0, 200, 200), paint);
1205 builder.Translate(0, 200);
1206
1207 paint.setColorFilter(
1209 builder.DrawRect(SkRect::MakeXYWH(0, 0, 200, 200), paint);
1210
1211 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1212}
1213
1214TEST_P(DisplayListTest, CanDrawPaintWithColorSource) {
1215 const flutter::DlColor colors[2] = {
1216 flutter::DlColor(0xFFF44336),
1217 flutter::DlColor(0xFF2196F3),
1218 };
1219 const float stops[2] = {0.0, 1.0};
1222 auto clip_bounds = SkRect::MakeWH(300.0, 300.0);
1223 builder.Save();
1224 builder.Translate(100, 100);
1225 builder.ClipRect(clip_bounds, flutter::DlCanvas::ClipOp::kIntersect, false);
1226 auto linear =
1227 flutter::DlColorSource::MakeLinear({0.0, 0.0}, {100.0, 100.0}, 2, colors,
1229 paint.setColorSource(linear);
1230 builder.DrawPaint(paint);
1231 builder.Restore();
1232
1233 builder.Save();
1234 builder.Translate(500, 100);
1235 builder.ClipRect(clip_bounds, flutter::DlCanvas::ClipOp::kIntersect, false);
1237 {100.0, 100.0}, 100.0, 2, colors, stops, flutter::DlTileMode::kRepeat);
1238 paint.setColorSource(radial);
1239 builder.DrawPaint(paint);
1240 builder.Restore();
1241
1242 builder.Save();
1243 builder.Translate(100, 500);
1244 builder.ClipRect(clip_bounds, flutter::DlCanvas::ClipOp::kIntersect, false);
1245 auto sweep =
1246 flutter::DlColorSource::MakeSweep({100.0, 100.0}, 180.0, 270.0, 2, colors,
1248 paint.setColorSource(sweep);
1249 builder.DrawPaint(paint);
1250 builder.Restore();
1251
1252 builder.Save();
1253 builder.Translate(500, 500);
1254 builder.ClipRect(clip_bounds, flutter::DlCanvas::ClipOp::kIntersect, false);
1255 auto texture = CreateTextureForFixture("table_mountain_nx.png");
1256 auto image = std::make_shared<flutter::DlImageColorSource>(
1259 paint.setColorSource(image);
1260 builder.DrawPaint(paint);
1261 builder.Restore();
1262
1263 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1264}
1265
1266TEST_P(DisplayListTest, CanBlendDstOverAndDstCorrectly) {
1268
1269 {
1270 builder.SaveLayer(nullptr, nullptr);
1271 builder.Translate(100, 100);
1273 paint.setColor(flutter::DlColor::kRed());
1274 builder.DrawRect(SkRect::MakeSize({200, 200}), paint);
1275 paint.setColor(flutter::DlColor::kBlue().withAlpha(127));
1277 builder.DrawRect(SkRect::MakeSize({200, 200}), paint);
1278 builder.Restore();
1279 }
1280 {
1281 builder.SaveLayer(nullptr, nullptr);
1282 builder.Translate(300, 100);
1284 paint.setColor(flutter::DlColor::kBlue().withAlpha(127));
1285 builder.DrawRect(SkRect::MakeSize({200, 200}), paint);
1286 paint.setColor(flutter::DlColor::kRed());
1288 builder.DrawRect(SkRect::MakeSize({200, 200}), paint);
1289 builder.Restore();
1290 }
1291 {
1292 builder.SaveLayer(nullptr, nullptr);
1293 builder.Translate(100, 300);
1295 paint.setColor(flutter::DlColor::kRed());
1296 builder.DrawRect(SkRect::MakeSize({200, 200}), paint);
1297 paint.setColor(flutter::DlColor::kBlue().withAlpha(127));
1298 paint.setBlendMode(flutter::DlBlendMode::kSrc);
1299 builder.DrawRect(SkRect::MakeSize({200, 200}), paint);
1300 builder.Restore();
1301 }
1302 {
1303 builder.SaveLayer(nullptr, nullptr);
1304 builder.Translate(300, 300);
1306 paint.setColor(flutter::DlColor::kBlue().withAlpha(127));
1307 builder.DrawRect(SkRect::MakeSize({200, 200}), paint);
1308 paint.setColor(flutter::DlColor::kRed());
1309 paint.setBlendMode(flutter::DlBlendMode::kDst);
1310 builder.DrawRect(SkRect::MakeSize({200, 200}), paint);
1311 builder.Restore();
1312 }
1313
1314 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1315}
1316
1317TEST_P(DisplayListTest, CanDrawCorrectlyWithColorFilterAndImageFilter) {
1319 const float green_color_matrix[20] = {
1320 0, 0, 0, 0, 0, //
1321 0, 0, 0, 0, 1, //
1322 0, 0, 0, 0, 0, //
1323 0, 0, 0, 1, 0, //
1324 };
1325 const float blue_color_matrix[20] = {
1326 0, 0, 0, 0, 0, //
1327 0, 0, 0, 0, 0, //
1328 0, 0, 0, 0, 1, //
1329 0, 0, 0, 1, 0, //
1330 };
1331 auto green_color_filter =
1332 std::make_shared<flutter::DlMatrixColorFilter>(green_color_matrix);
1333 auto blue_color_filter =
1334 std::make_shared<flutter::DlMatrixColorFilter>(blue_color_matrix);
1335 auto blue_image_filter =
1336 std::make_shared<flutter::DlColorFilterImageFilter>(blue_color_filter);
1337
1339 paint.setColor(flutter::DlColor::kRed());
1340 paint.setColorFilter(green_color_filter);
1341 paint.setImageFilter(blue_image_filter);
1342 builder.DrawRect(SkRect::MakeLTRB(100, 100, 500, 500), paint);
1343 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1344}
1345
1346TEST_P(DisplayListTest, MaskBlursApplyCorrectlyToColorSources) {
1347 auto blur_filter = std::make_shared<flutter::DlBlurMaskFilter>(
1349
1351
1352 std::array<flutter::DlColor, 2> colors = {flutter::DlColor::kBlue(),
1354 std::array<float, 2> stops = {0, 1};
1355 std::array<std::shared_ptr<flutter::DlColorSource>, 2> color_sources = {
1356 std::make_shared<flutter::DlColorColorSource>(flutter::DlColor::kWhite()),
1358 SkPoint::Make(0, 0), SkPoint::Make(100, 50), 2, colors.data(),
1359 stops.data(), flutter::DlTileMode::kClamp)};
1360
1361 int offset = 100;
1362 for (const auto& color_source : color_sources) {
1364 paint.setColorSource(color_source);
1365 paint.setMaskFilter(blur_filter);
1366
1367 paint.setDrawStyle(flutter::DlDrawStyle::kFill);
1368 builder.DrawRRect(
1369 SkRRect::MakeRectXY(SkRect::MakeXYWH(100, offset, 100, 50), 30, 30),
1370 paint);
1372 paint.setStrokeWidth(10);
1373 builder.DrawRRect(
1374 SkRRect::MakeRectXY(SkRect::MakeXYWH(300, offset, 100, 50), 30, 30),
1375 paint);
1376
1377 offset += 100;
1378 }
1379
1380 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1381}
1382
1383TEST_P(DisplayListTest, DrawVerticesSolidColorTrianglesWithoutIndices) {
1384 // Use negative coordinates and then scale the transform by -1, -1 to make
1385 // sure coverage is taking the transform into account.
1386 std::vector<SkPoint> positions = {SkPoint::Make(-100, -300),
1387 SkPoint::Make(-200, -100),
1388 SkPoint::Make(-300, -300)};
1389 std::vector<flutter::DlColor> colors = {flutter::DlColor::kWhite(),
1392
1393 auto vertices = flutter::DlVertices::Make(
1394 flutter::DlVertexMode::kTriangles, 3, positions.data(),
1395 /*texture_coordinates=*/nullptr, colors.data());
1396
1399
1400 paint.setColor(flutter::DlColor::kRed().modulateOpacity(0.5));
1401 builder.Scale(-1, -1);
1402 builder.DrawVertices(vertices, flutter::DlBlendMode::kSrcOver, paint);
1403
1404 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1405}
1406
1407TEST_P(DisplayListTest, DrawVerticesLinearGradientWithoutIndices) {
1408 std::vector<SkPoint> positions = {SkPoint::Make(100, 300),
1409 SkPoint::Make(200, 100),
1410 SkPoint::Make(300, 300)};
1411
1412 auto vertices = flutter::DlVertices::Make(
1413 flutter::DlVertexMode::kTriangles, 3, positions.data(),
1414 /*texture_coordinates=*/nullptr, /*colors=*/nullptr);
1415
1416 std::vector<flutter::DlColor> colors = {flutter::DlColor::kBlue(),
1418 const float stops[2] = {0.0, 1.0};
1419
1421 {100.0, 100.0}, {300.0, 300.0}, 2, colors.data(), stops,
1423
1426
1427 paint.setColorSource(linear);
1428 builder.DrawVertices(vertices, flutter::DlBlendMode::kSrcOver, paint);
1429
1430 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1431}
1432
1433TEST_P(DisplayListTest, DrawVerticesLinearGradientWithTextureCoordinates) {
1434 std::vector<SkPoint> positions = {SkPoint::Make(100, 300),
1435 SkPoint::Make(200, 100),
1436 SkPoint::Make(300, 300)};
1437 std::vector<SkPoint> texture_coordinates = {SkPoint::Make(300, 100),
1438 SkPoint::Make(100, 200),
1439 SkPoint::Make(300, 300)};
1440
1441 auto vertices = flutter::DlVertices::Make(
1442 flutter::DlVertexMode::kTriangles, 3, positions.data(),
1443 texture_coordinates.data(), /*colors=*/nullptr);
1444
1445 std::vector<flutter::DlColor> colors = {flutter::DlColor::kBlue(),
1447 const float stops[2] = {0.0, 1.0};
1448
1450 {100.0, 100.0}, {300.0, 300.0}, 2, colors.data(), stops,
1452
1455
1456 paint.setColorSource(linear);
1457 builder.DrawVertices(vertices, flutter::DlBlendMode::kSrcOver, paint);
1458
1459 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1460}
1461
1462TEST_P(DisplayListTest, DrawVerticesImageSourceWithTextureCoordinates) {
1463 auto texture = CreateTextureForFixture("embarcadero.jpg");
1464 auto dl_image = DlImageImpeller::Make(texture);
1465 std::vector<SkPoint> positions = {SkPoint::Make(100, 300),
1466 SkPoint::Make(200, 100),
1467 SkPoint::Make(300, 300)};
1468 std::vector<SkPoint> texture_coordinates = {
1469 SkPoint::Make(0, 0), SkPoint::Make(100, 200), SkPoint::Make(200, 100)};
1470
1471 auto vertices = flutter::DlVertices::Make(
1472 flutter::DlVertexMode::kTriangles, 3, positions.data(),
1473 texture_coordinates.data(), /*colors=*/nullptr);
1474
1477
1478 auto image_source = flutter::DlImageColorSource(
1480
1481 paint.setColorSource(&image_source);
1482 builder.DrawVertices(vertices, flutter::DlBlendMode::kSrcOver, paint);
1483
1484 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1485}
1486
1488 DrawVerticesImageSourceWithTextureCoordinatesAndColorBlending) {
1489 auto texture = CreateTextureForFixture("embarcadero.jpg");
1490 auto dl_image = DlImageImpeller::Make(texture);
1491 std::vector<SkPoint> positions = {SkPoint::Make(100, 300),
1492 SkPoint::Make(200, 100),
1493 SkPoint::Make(300, 300)};
1494 std::vector<flutter::DlColor> colors = {flutter::DlColor::kWhite(),
1497 std::vector<SkPoint> texture_coordinates = {
1498 SkPoint::Make(0, 0), SkPoint::Make(100, 200), SkPoint::Make(200, 100)};
1499
1500 auto vertices = flutter::DlVertices::Make(
1501 flutter::DlVertexMode::kTriangles, 3, positions.data(),
1502 texture_coordinates.data(), colors.data());
1503
1506
1507 auto image_source = flutter::DlImageColorSource(
1509
1510 paint.setColorSource(&image_source);
1511 builder.DrawVertices(vertices, flutter::DlBlendMode::kModulate, paint);
1512
1513 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1514}
1515
1516TEST_P(DisplayListTest, DrawVerticesSolidColorTrianglesWithIndices) {
1517 std::vector<SkPoint> positions = {
1518 SkPoint::Make(100, 300), SkPoint::Make(200, 100), SkPoint::Make(300, 300),
1519 SkPoint::Make(200, 500)};
1520 std::vector<uint16_t> indices = {0, 1, 2, 0, 2, 3};
1521
1522 auto vertices = flutter::DlVertices::Make(
1523 flutter::DlVertexMode::kTriangles, positions.size(), positions.data(),
1524 /*texture_coordinates=*/nullptr, /*colors=*/nullptr, indices.size(),
1525 indices.data());
1526
1529
1530 paint.setColor(flutter::DlColor::kWhite());
1531 builder.DrawVertices(vertices, flutter::DlBlendMode::kSrcOver, paint);
1532
1533 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1534}
1535
1536TEST_P(DisplayListTest, DrawVerticesPremultipliesColors) {
1537 std::vector<SkPoint> positions = {
1538 SkPoint::Make(100, 300), SkPoint::Make(200, 100), SkPoint::Make(300, 300),
1539 SkPoint::Make(200, 500)};
1541 std::vector<uint16_t> indices = {0, 1, 2, 0, 2, 3};
1542 std::vector<flutter::DlColor> colors = {color, color, color, color};
1543
1544 auto vertices = flutter::DlVertices::Make(
1545 flutter::DlVertexMode::kTriangles, positions.size(), positions.data(),
1546 /*texture_coordinates=*/nullptr, colors.data(), indices.size(),
1547 indices.data());
1548
1552 paint.setColor(flutter::DlColor::kRed());
1553
1554 builder.DrawRect(SkRect::MakeLTRB(0, 0, 400, 400), paint);
1555 builder.DrawVertices(vertices, flutter::DlBlendMode::kDst, paint);
1556
1557 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1558}
1559
1562 std::vector<flutter::DlStrokeJoin> joins = {
1566 };
1568 flutter::DlPaint() //
1571 .setStrokeWidth(10);
1572 flutter::DlPaint stroke_paint = //
1573 flutter::DlPaint() //
1576 .setStrokeWidth(10);
1577 SkPath path = SkPath().addPoly({{150, 50}, {160, 50}}, false);
1578
1579 builder.Translate(300, 50);
1580 builder.Scale(0.8, 0.8);
1581 for (auto join : joins) {
1582 paint.setStrokeJoin(join);
1583 stroke_paint.setStrokeJoin(join);
1584 builder.DrawRect(SkRect::MakeXYWH(0, 0, 100, 100), paint);
1585 builder.DrawRect(SkRect::MakeXYWH(0, 150, 100, 100), stroke_paint);
1586 builder.DrawRRect(
1587 SkRRect::MakeRectXY(SkRect::MakeXYWH(150, 0, 100, 100), 30, 30), paint);
1588 builder.DrawRRect(
1589 SkRRect::MakeRectXY(SkRect::MakeXYWH(150, 150, 100, 100), 30, 30),
1590 stroke_paint);
1591 builder.DrawCircle({350, 50}, 50, paint);
1592 builder.DrawCircle({350, 200}, 50, stroke_paint);
1593 builder.Translate(0, 300);
1594 }
1595 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1596}
1597
1598TEST_P(DisplayListTest, ClipDrawRRectWithNonCircularRadii) {
1600
1601 flutter::DlPaint fill_paint = //
1602 flutter::DlPaint() //
1605 .setStrokeWidth(10);
1606 flutter::DlPaint stroke_paint = //
1607 flutter::DlPaint() //
1610 .setStrokeWidth(10);
1611
1612 builder.DrawRRect(
1613 SkRRect::MakeRectXY(SkRect::MakeXYWH(500, 100, 300, 300), 120, 40),
1614 fill_paint);
1615 builder.DrawRRect(
1616 SkRRect::MakeRectXY(SkRect::MakeXYWH(500, 100, 300, 300), 120, 40),
1617 stroke_paint);
1618
1619 builder.DrawRRect(
1620 SkRRect::MakeRectXY(SkRect::MakeXYWH(100, 500, 300, 300), 40, 120),
1621 fill_paint);
1622 builder.DrawRRect(
1623 SkRRect::MakeRectXY(SkRect::MakeXYWH(100, 500, 300, 300), 40, 120),
1624 stroke_paint);
1625
1626 flutter::DlPaint reference_paint = //
1627 flutter::DlPaint() //
1630 .setStrokeWidth(10);
1631
1632 builder.DrawRRect(
1633 SkRRect::MakeRectXY(SkRect::MakeXYWH(500, 500, 300, 300), 40, 40),
1634 reference_paint);
1635 builder.DrawRRect(
1636 SkRRect::MakeRectXY(SkRect::MakeXYWH(100, 100, 300, 300), 120, 120),
1637 reference_paint);
1638
1639 flutter::DlPaint clip_fill_paint = //
1640 flutter::DlPaint() //
1643 .setStrokeWidth(10);
1644
1645 builder.Save();
1646 builder.ClipRRect(
1647 SkRRect::MakeRectXY(SkRect::MakeXYWH(900, 100, 300, 300), 120, 40));
1648 builder.DrawPaint(clip_fill_paint);
1649 builder.Restore();
1650
1651 builder.Save();
1652 builder.ClipRRect(
1653 SkRRect::MakeRectXY(SkRect::MakeXYWH(100, 900, 300, 300), 40, 120));
1654 builder.DrawPaint(clip_fill_paint);
1655 builder.Restore();
1656
1657 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1658}
1659
1660TEST_P(DisplayListTest, DrawVerticesBlendModes) {
1661 std::vector<const char*> blend_mode_names;
1662 std::vector<flutter::DlBlendMode> blend_mode_values;
1663 {
1664 const std::vector<std::tuple<const char*, flutter::DlBlendMode>> blends = {
1665 // Pipeline blends (Porter-Duff alpha compositing)
1667 {"Source", flutter::DlBlendMode::kSrc},
1668 {"Destination", flutter::DlBlendMode::kDst},
1669 {"SourceOver", flutter::DlBlendMode::kSrcOver},
1670 {"DestinationOver", flutter::DlBlendMode::kDstOver},
1671 {"SourceIn", flutter::DlBlendMode::kSrcIn},
1672 {"DestinationIn", flutter::DlBlendMode::kDstIn},
1673 {"SourceOut", flutter::DlBlendMode::kSrcOut},
1674 {"DestinationOut", flutter::DlBlendMode::kDstOut},
1675 {"SourceATop", flutter::DlBlendMode::kSrcATop},
1676 {"DestinationATop", flutter::DlBlendMode::kDstATop},
1679 {"Modulate", flutter::DlBlendMode::kModulate},
1680 // Advanced blends (color component blends)
1682 {"Overlay", flutter::DlBlendMode::kOverlay},
1684 {"Lighten", flutter::DlBlendMode::kLighten},
1685 {"ColorDodge", flutter::DlBlendMode::kColorDodge},
1686 {"ColorBurn", flutter::DlBlendMode::kColorBurn},
1687 {"HardLight", flutter::DlBlendMode::kHardLight},
1688 {"SoftLight", flutter::DlBlendMode::kSoftLight},
1689 {"Difference", flutter::DlBlendMode::kDifference},
1690 {"Exclusion", flutter::DlBlendMode::kExclusion},
1691 {"Multiply", flutter::DlBlendMode::kMultiply},
1693 {"Saturation", flutter::DlBlendMode::kSaturation},
1695 {"Luminosity", flutter::DlBlendMode::kLuminosity},
1696 };
1697 assert(blends.size() ==
1698 static_cast<size_t>(flutter::DlBlendMode::kLastMode) + 1);
1699 for (const auto& [name, mode] : blends) {
1700 blend_mode_names.push_back(name);
1701 blend_mode_values.push_back(mode);
1702 }
1703 }
1704
1705 auto callback = [&]() {
1706 static int current_blend_index = 3;
1707 static float dst_alpha = 1;
1708 static float src_alpha = 1;
1709 static float color0[4] = {1.0f, 0.0f, 0.0f, 1.0f};
1710 static float color1[4] = {0.0f, 1.0f, 0.0f, 1.0f};
1711 static float color2[4] = {0.0f, 0.0f, 1.0f, 1.0f};
1712 static float src_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
1713
1714 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1715 {
1716 ImGui::ListBox("Blending mode", &current_blend_index,
1717 blend_mode_names.data(), blend_mode_names.size());
1718 ImGui::SliderFloat("Source alpha", &src_alpha, 0, 1);
1719 ImGui::ColorEdit4("Color A", color0);
1720 ImGui::ColorEdit4("Color B", color1);
1721 ImGui::ColorEdit4("Color C", color2);
1722 ImGui::ColorEdit4("Source Color", src_color);
1723 ImGui::SliderFloat("Destination alpha", &dst_alpha, 0, 1);
1724 }
1725 ImGui::End();
1726
1727 std::vector<SkPoint> positions = {SkPoint::Make(100, 300),
1728 SkPoint::Make(200, 100),
1729 SkPoint::Make(300, 300)};
1730 std::vector<flutter::DlColor> colors = {
1731 toColor(color0).modulateOpacity(dst_alpha),
1732 toColor(color1).modulateOpacity(dst_alpha),
1733 toColor(color2).modulateOpacity(dst_alpha)};
1734
1735 auto vertices = flutter::DlVertices::Make(
1736 flutter::DlVertexMode::kTriangles, 3, positions.data(),
1737 /*texture_coordinates=*/nullptr, colors.data());
1738
1741
1742 paint.setColor(toColor(src_color).modulateOpacity(src_alpha));
1743 builder.DrawVertices(vertices, blend_mode_values[current_blend_index],
1744 paint);
1745 return builder.Build();
1746 };
1747
1748 ASSERT_TRUE(OpenPlaygroundHere(callback));
1749}
1750
1751template <typename Contents>
1752static std::optional<Rect> GetCoverageOfFirstEntity(const Picture& picture) {
1753 std::optional<Rect> coverage;
1754 picture.pass->IterateAllEntities([&coverage](Entity& entity) {
1755 if (std::static_pointer_cast<Contents>(entity.GetContents())) {
1756 auto contents = std::static_pointer_cast<Contents>(entity.GetContents());
1757 Entity entity;
1758 coverage = contents->GetCoverage(entity);
1759 return false;
1760 }
1761 return true;
1762 });
1763 return coverage;
1764}
1765
1766TEST(DisplayListTest, RRectBoundsComputation) {
1767 SkRRect rrect = SkRRect::MakeRectXY(SkRect::MakeLTRB(0, 0, 100, 100), 4, 4);
1768 SkPath path = SkPath().addRRect(rrect);
1769
1772
1773 builder.DrawPath(path, paint);
1774 auto display_list = builder.Build();
1775
1776 DlDispatcher dispatcher;
1777 display_list->Dispatch(dispatcher);
1778 auto picture = dispatcher.EndRecordingAsPicture();
1779
1780 std::optional<Rect> coverage =
1781 GetCoverageOfFirstEntity<SolidColorContents>(picture);
1782
1783 // Validate that the RRect coverage is _exactly_ the same as the input rect.
1784 ASSERT_TRUE(coverage.has_value());
1785 ASSERT_EQ(coverage.value_or(Rect::MakeMaximum()),
1786 Rect::MakeLTRB(0, 0, 100, 100));
1787}
1788
1789TEST(DisplayListTest, CircleBoundsComputation) {
1790 SkPath path = SkPath().addCircle(0, 0, 5);
1791
1794
1795 builder.DrawPath(path, paint);
1796 auto display_list = builder.Build();
1797
1798 DlDispatcher dispatcher;
1799 display_list->Dispatch(dispatcher);
1800 auto picture = dispatcher.EndRecordingAsPicture();
1801
1802 std::optional<Rect> coverage =
1803 GetCoverageOfFirstEntity<SolidColorContents>(picture);
1804
1805 ASSERT_TRUE(coverage.has_value());
1806 ASSERT_EQ(coverage.value_or(Rect::MakeMaximum()),
1807 Rect::MakeLTRB(-5, -5, 5, 5));
1808}
1809
1810#ifdef IMPELLER_ENABLE_3D
1811TEST_P(DisplayListTest, SceneColorSource) {
1812 // Load up the scene.
1813 auto mapping =
1814 flutter::testing::OpenFixtureAsMapping("flutter_logo_baked.glb.ipscene");
1815 ASSERT_NE(mapping, nullptr);
1816
1817 std::shared_ptr<scene::Node> gltf_scene =
1819 *mapping, *GetContext()->GetResourceAllocator());
1820 ASSERT_NE(gltf_scene, nullptr);
1821
1823
1824 auto color_source = std::make_shared<flutter::DlSceneColorSource>(
1825 gltf_scene,
1826 Matrix::MakePerspective(Degrees(45), GetWindowSize(), 0.1, 1000) *
1827 Matrix::MakeLookAt({3, 2, -5}, {0, 0, 0}, {0, 1, 0}));
1828
1830
1831 builder.DrawPaint(paint);
1832
1833 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1834}
1835#endif
1836
1837TEST_P(DisplayListTest, DrawPaintIgnoresMaskFilter) {
1839 builder.DrawPaint(flutter::DlPaint().setColor(flutter::DlColor::kWhite()));
1840
1842 builder.DrawCircle({300, 300}, 200,
1843 flutter::DlPaint().setMaskFilter(&filter));
1844
1845 std::vector<flutter::DlColor> colors = {flutter::DlColor::kGreen(),
1847 const float stops[2] = {0.0, 1.0};
1849 {100.0, 100.0}, {300.0, 300.0}, 2, colors.data(), stops,
1851 flutter::DlPaint blend_paint =
1852 flutter::DlPaint() //
1855 builder.DrawPaint(blend_paint);
1856
1857 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1858}
1859
1860TEST_P(DisplayListTest, DrawMaskBlursThatMightUseSaveLayers) {
1863 Vector2 scale = GetContentScale();
1864 builder.Scale(scale.x, scale.y);
1865
1866 builder.Save();
1867 // We need a small transform op to avoid a deferred save
1868 builder.Translate(1.0f, 1.0f);
1869 auto solid_filter =
1871 flutter::DlPaint solid_alpha_paint =
1872 flutter::DlPaint() //
1873 .setMaskFilter(solid_filter) //
1875 .setAlpha(0x7f);
1876 for (int x = 1; x <= 4; x++) {
1877 for (int y = 1; y <= 4; y++) {
1878 builder.DrawRect(SkRect::MakeXYWH(x * 100, y * 100, 80, 80),
1879 solid_alpha_paint);
1880 }
1881 }
1882 builder.Restore();
1883
1884 builder.Save();
1885 builder.Translate(500.0f, 0.0f);
1886 auto normal_filter =
1888 auto rotate_if = flutter::DlMatrixImageFilter::Make(
1890 flutter::DlPaint normal_if_paint =
1891 flutter::DlPaint() //
1892 .setMaskFilter(solid_filter) //
1893 .setImageFilter(rotate_if) //
1895 .setAlpha(0x7f);
1896 for (int x = 1; x <= 4; x++) {
1897 for (int y = 1; y <= 4; y++) {
1898 builder.DrawRect(SkRect::MakeXYWH(x * 100, y * 100, 80, 80),
1899 normal_if_paint);
1900 }
1901 }
1902 builder.Restore();
1903
1904 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1905}
1906
1907} // namespace testing
1908} // namespace impeller
#define TEST(S, s, D, expected)
static const int points[]
SkColor4f color
static sk_sp< SkImage > color_filter(const SkImage *image, SkColorFilter *colorFilter)
SkMatrix & postTranslate(SkScalar dx, SkScalar dy)
Definition SkMatrix.cpp:281
static SkMatrix RotateDeg(SkScalar deg)
Definition SkMatrix.h:104
SkMatrix & postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition SkMatrix.cpp:360
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition SkMatrix.h:91
static SkMatrix MakeAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar pers0, SkScalar pers1, SkScalar pers2)
Definition SkMatrix.h:179
static const SkMatrix & I()
SkPathBuilder & lineTo(SkPoint pt)
SkPathBuilder & moveTo(SkPoint pt)
SkPath snapshot() const
SkPath & addCircle(SkScalar x, SkScalar y, SkScalar radius, SkPathDirection dir=SkPathDirection::kCW)
Definition SkPath.cpp:1149
SkPath & moveTo(SkScalar x, SkScalar y)
Definition SkPath.cpp:678
SkPath & addPoly(const SkPoint pts[], int count, bool close)
Definition SkPath.cpp:880
SkPath & lineTo(SkScalar x, SkScalar y)
Definition SkPath.cpp:718
SkPath & addRRect(const SkRRect &rrect, SkPathDirection dir=SkPathDirection::kCW)
Definition SkPath.cpp:990
SkPath & quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
Definition SkPath.cpp:736
SkPath & cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3)
Definition SkPath.cpp:789
SkPath & addRect(const SkRect &rect, SkPathDirection dir, unsigned start)
Definition SkPath.cpp:854
static SkRRect MakeRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition SkRRect.h:180
static sk_sp< SkTextBlob > MakeFromString(const char *string, const SkFont &font, SkTextEncoding encoding=SkTextEncoding::kUTF8)
Definition SkTextBlob.h:115
void DrawRect(const SkRect &rect, const DlPaint &paint) override
sk_sp< DisplayList > Build()
Definition dl_builder.cc:67
std::shared_ptr< DlImageFilter > shared() const override
static std::shared_ptr< DlMaskFilter > Make(DlBlurStyle style, SkScalar sigma, bool respect_ctm=true)
@ kLines
draw each separate pair of points as a line segment
@ kPolygon
draw each pair of overlapping points as a line segment
@ kPoints
draw each point separately
static std::shared_ptr< DlLinearGradientColorSource > MakeLinear(const SkPoint start_point, const SkPoint end_point, uint32_t stop_count, const DlColor *colors, const float *stops, DlTileMode tile_mode, const SkMatrix *matrix=nullptr)
static std::shared_ptr< DlSweepGradientColorSource > MakeSweep(SkPoint center, SkScalar start, SkScalar end, uint32_t stop_count, const DlColor *colors, const float *stops, DlTileMode tile_mode, const SkMatrix *matrix=nullptr)
static std::shared_ptr< DlRadialGradientColorSource > MakeRadial(SkPoint center, SkScalar radius, uint32_t stop_count, const DlColor *colors, const float *stops, DlTileMode tile_mode, const SkMatrix *matrix=nullptr)
static const std::shared_ptr< DlLinearToSrgbGammaColorFilter > kInstance
static std::shared_ptr< DlImageFilter > Make(const SkMatrix &matrix, DlImageSampling sampling)
DlPaint & setColor(DlColor color)
Definition dl_paint.h:71
DlPaint & setMaskFilter(const std::shared_ptr< DlMaskFilter > &filter)
Definition dl_paint.h:171
DlPaint & setStrokeCap(DlStrokeCap cap)
Definition dl_paint.h:103
DlPaint & setStrokeWidth(float width)
Definition dl_paint.h:117
DlPaint & setAlpha(uint8_t alpha)
Definition dl_paint.h:77
DlPaint & setBlendMode(DlBlendMode mode)
Definition dl_paint.h:87
DlPaint & setImageFilter(const std::shared_ptr< const DlImageFilter > &filter)
Definition dl_paint.h:158
DlPaint & setDrawStyle(DlDrawStyle style)
Definition dl_paint.h:95
DlPaint & setStrokeJoin(DlStrokeJoin join)
Definition dl_paint.h:111
DlPaint & setColorSource(std::shared_ptr< const DlColorSource > source)
Definition dl_paint.h:132
static const std::shared_ptr< DlSrgbToLinearGammaColorFilter > kInstance
static std::shared_ptr< DlVertices > Make(DlVertexMode mode, int vertex_count, const SkPoint vertices[], const SkPoint texture_coordinates[], const DlColor colors[], int index_count=0, const uint16_t indices[]=nullptr)
Constructs a DlVector with compact inline storage for all of its required and optional lists of data.
void transformFullPerspective(SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt, SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt, SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt, SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt) override
void translate(SkScalar tx, SkScalar ty) override
void drawShadow(const SkPath &path, const flutter::DlColor color, const SkScalar elevation, bool transparent_occluder, SkScalar dpr) override
void scale(SkScalar sx, SkScalar sy) override
void drawDisplayList(const sk_sp< flutter::DisplayList > display_list, SkScalar opacity) override
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
const std::shared_ptr< Contents > & GetContents() const
Definition entity.cc:94
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
Definition entity.cc:46
static std::shared_ptr< Node > MakeFromFlatbuffer(const fml::Mapping &ipscene_mapping, Allocator &allocator)
Definition node.cc:47
T * get() const
Definition SkRefCnt.h:303
const Paint & paint
sk_sp< SkImage > image
Definition examples.cpp:29
float SkScalar
Definition extension.cpp:12
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
const char * name
Definition fuchsia.cc:50
FlTexture * texture
double y
double x
std::unique_ptr< fml::Mapping > OpenFixtureAsMapping(const std::string &fixture_name)
Opens a fixture of the given file name and returns a mapping to its contents.
Definition testing.cc:59
DlStrokeJoin
Definition dl_paint.h:38
@ kMiter
extends to miter limit
@ kBevel
connects outside edges
DlStrokeCap
Definition dl_paint.h:29
@ kRound
adds circle
@ kButt
no stroke extension
@ kSquare
adds square
@ kTriangles
The vertices are taken 3 at a time to form a triangle.
@ kStroke
strokes boundary of shapes
@ kFill
fills interior of shapes
@ kNormal
fuzzy inside and outside
@ kOuter
nothing inside, fuzzy outside
@ kSolid
solid inside, fuzzy outside
@ kSrcOut
r = s * (1-da)
@ kExclusion
rc = s + d - two(s*d), ra = kSrcOver
@ kSaturation
saturation of source with hue and luminosity of destination
@ kColorBurn
darken destination to reflect source
@ kPlus
r = min(s + d, 1)
@ kLighten
rc = s + d - min(s*da, d*sa), ra = kSrcOver
@ kHue
hue of source with saturation and luminosity of destination
@ kMultiply
r = s*(1-da) + d*(1-sa) + s*d
@ kColorDodge
brighten destination to reflect source
@ kScreen
r = s + d - s*d
@ kSrcOver
r = s + (1-sa)*d
@ kXor
r = s*(1-da) + d*(1-sa)
@ kLuminosity
luminosity of source with hue and saturation of destination
@ kSoftLight
lighten or darken, depending on source
@ kDifference
rc = s + d - 2*(min(s*da, d*sa)), ra = kSrcOver
@ kOverlay
multiply or screen, depending on destination
@ kSrcATop
r = s*da + d*(1-sa)
@ kDstATop
r = d*sa + s*(1-da)
@ kDstOver
r = d + (1-da)*s
@ kLastMode
last valid value
@ kColor
hue and saturation of source with luminosity of destination
@ kHardLight
multiply or screen, depending on source
@ kDstOut
r = d * (1-sa)
@ kDarken
rc = s + d - max(s*da, d*sa), ra = kSrcOver
DlPlayground DisplayListTest
flutter::DlColor toColor(const float *components)
TEST_P(AiksTest, CanRenderAdvancedBlendColorFilterWithSaveLayer)
static std::optional< Rect > GetCoverageOfFirstEntity(const Picture &picture)
constexpr float kPi
Definition constants.h:26
float Scalar
Definition scalar.h:18
Point DrawPlaygroundPoint(PlaygroundPoint &point)
Definition widgets.cc:9
std::tuple< Point, Point > DrawPlaygroundLine(PlaygroundPoint &point_a, PlaygroundPoint &point_b)
Definition widgets.cc:50
TPoint< Scalar > Point
Definition point.h:316
constexpr bool ScalarNearlyEqual(Scalar x, Scalar y, Scalar tolerance=kEhCloseEnough)
Definition scalar.h:30
SkPath quad_path()
SkPath cubic_path()
#define INSTANTIATE_PLAYGROUND_SUITE(playground)
const Scalar stroke_width
const Scalar scale
Point offset
static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b)
Definition SkRect.h:91
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition SkRect.h:104
static constexpr SkPoint Make(float x, float y)
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition SkRect.h:659
static constexpr SkRect MakeSize(const SkSize &size)
Definition SkRect.h:633
static constexpr SkRect MakeWH(float w, float h)
Definition SkRect.h:609
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition SkRect.h:646
constexpr DlColor modulateOpacity(float opacity) const
Definition dl_color.h:72
static constexpr DlColor kWhite()
Definition dl_color.h:23
static constexpr DlColor kBlue()
Definition dl_color.h:26
static constexpr DlColor kBlack()
Definition dl_color.h:22
static constexpr DlColor kYellow()
Definition dl_color.h:29
constexpr DlColor withAlpha(uint8_t alpha) const
Definition dl_color.h:59
static constexpr DlColor kMidGrey()
Definition dl_color.h:31
static constexpr DlColor kTransparent()
Definition dl_color.h:21
static constexpr DlColor kRed()
Definition dl_color.h:24
static constexpr DlColor kGreen()
Definition dl_color.h:25
static constexpr DlColor kDarkGrey()
Definition dl_color.h:30
static constexpr DlColor kCyan()
Definition dl_color.h:27
static constexpr uint32_t ToIColor(Color color)
Convert this color to a 32-bit representation.
Definition color.h:161
static constexpr Color White()
Definition color.h:256
static constexpr Color Red()
Definition color.h:264
static constexpr Matrix MakePerspective(Radians fov_y, Scalar aspect_ratio, Scalar z_near, Scalar z_far)
Definition matrix.h:504
constexpr Vector3 GetScale() const
Definition matrix.h:311
static constexpr Matrix MakeLookAt(Vector3 position, Vector3 target, Vector3 up)
Definition matrix.h:530
static constexpr TRect MakeMaximum()
Definition rect.h:174
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129
#define EXPECT_TRUE(handle)
Definition unit_test.h:685
static sk_sp< SkShader > linear(sk_sp< SkShader > shader)