Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
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
22#include "gtest/gtest.h"
35#include "third_party/imgui/imgui.h"
36
37namespace impeller {
38namespace testing {
39
40flutter::DlColor toColor(const float* components) {
42 Color(components[0], components[1], components[2], components[3])));
43}
44
47
48TEST_P(DisplayListTest, CanDrawRect) {
50 builder.DrawRect(DlRect::MakeXYWH(10, 10, 100, 100),
52 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
53}
54
55TEST_P(DisplayListTest, CanDrawTextBlob) {
58 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
71 {0.0, 0.0}, {300.0, 300.0}, 2, colors.data(), stops,
73 flutter::DlPaint paint;
74 paint.setColorSource(linear);
75
76 builder.DrawText(
78 SkTextBlob::MakeFromString("Hello World", CreateTestFont())),
79 100, 100, paint);
80 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
81}
82
83TEST_P(DisplayListTest, CanDrawTextWithSaveLayer) {
86 SkTextBlob::MakeFromString("Hello", CreateTestFont())),
88
89 flutter::DlPaint save_paint;
90 float alpha = 0.5;
91 save_paint.setAlpha(static_cast<uint8_t>(255 * alpha));
92 builder.SaveLayer(std::nullopt, &save_paint);
93 builder.DrawText(
94 flutter::DlTextImpeller::MakeFromBlob(SkTextBlob::MakeFromString(
95 "Hello with half alpha", CreateTestFontOfSize(100))),
97 builder.Restore();
98 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
99}
100
101TEST_P(DisplayListTest, CanDrawImage) {
102 auto texture = CreateTextureForFixture("embarcadero.jpg");
106 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
107}
108
109TEST_P(DisplayListTest, CanDrawCapsAndJoins) {
111 flutter::DlPaint paint;
112
114 paint.setStrokeWidth(30);
116
117 flutter::DlPathBuilder path_builder;
118 path_builder.MoveTo(DlPoint(-50, 0));
119 path_builder.LineTo(DlPoint(0, -50));
120 path_builder.LineTo(DlPoint(50, 0));
121 flutter::DlPath path = path_builder.TakePath();
122
123 builder.Translate(100, 100);
124 {
127 paint.setStrokeMiter(4);
128 builder.DrawPath(path, paint);
129 }
130
131 {
132 builder.Save();
133 builder.Translate(0, 100);
134 // The joint in the path is 45 degrees. A miter length of 1 convert to a
135 // bevel in this case.
136 paint.setStrokeMiter(1);
137 builder.DrawPath(path, paint);
138 builder.Restore();
139 }
140
141 builder.Translate(150, 0);
142 {
145 builder.DrawPath(path, paint);
146 }
147
148 builder.Translate(150, 0);
149 {
152 builder.DrawPath(path, paint);
153 }
154
155 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
156}
157
159 auto callback = [&]() {
160 static float start_angle = 45;
161 static float sweep_angle = 270;
162 static float stroke_width = 10;
163 static bool use_center = true;
164
165 static int selected_cap = 0;
166 const char* cap_names[] = {"Butt", "Round", "Square"};
168
169 if (IsPlaygroundEnabled()) {
170 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
171 ImGui::SliderFloat("Start angle", &start_angle, -360, 360);
172 ImGui::SliderFloat("Sweep angle", &sweep_angle, -360, 360);
173 ImGui::SliderFloat("Stroke width", &stroke_width, 0, 300);
174 ImGui::Combo("Cap", &selected_cap, cap_names,
175 sizeof(cap_names) / sizeof(char*));
176 ImGui::Checkbox("Use center", &use_center);
177 ImGui::End();
178 }
179
180 switch (selected_cap) {
181 case 0:
183 break;
184 case 1:
186 break;
187 case 2:
189 break;
190 default:
192 break;
193 }
194
195 static PlaygroundPoint point_a(Point(200, 200), 20, Color::White());
196 static PlaygroundPoint point_b(Point(400, 400), 20, Color::White());
197 auto [p1, p2] = DrawPlaygroundLine(point_a, point_b);
198
200 flutter::DlPaint paint;
201
202 Vector2 scale = GetContentScale();
203 builder.Scale(scale.x, scale.y);
205 paint.setStrokeCap(cap);
207 paint.setStrokeMiter(10);
208 auto rect = DlRect::MakeLTRB(p1.x, p1.y, p2.x, p2.y);
210 paint.setStrokeWidth(2);
211 builder.DrawRect(rect, paint);
213 paint.setStrokeWidth(stroke_width);
214 builder.DrawArc(rect, start_angle, sweep_angle, use_center, paint);
215
216 return builder.Build();
217 };
218 ASSERT_TRUE(OpenPlaygroundHere(callback));
219}
220
221TEST_P(DisplayListTest, StrokedPathsDrawCorrectly) {
222 auto callback = [&]() {
224 flutter::DlPaint paint;
225
228
229 static float stroke_width = 10.0f;
230 static int selected_stroke_type = 0;
231 static int selected_join_type = 0;
232 const char* stroke_types[] = {"Butte", "Round", "Square"};
233 const char* join_type[] = {"kMiter", "Round", "kBevel"};
234
235 if (IsPlaygroundEnabled()) {
236 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
237 ImGui::Combo("Cap", &selected_stroke_type, stroke_types,
238 sizeof(stroke_types) / sizeof(char*));
239 ImGui::Combo("Join", &selected_join_type, join_type,
240 sizeof(join_type) / sizeof(char*));
241 ImGui::SliderFloat("Stroke Width", &stroke_width, 10.0f, 50.0f);
242 ImGui::End();
243 }
244
247 switch (selected_stroke_type) {
248 case 0:
250 break;
251 case 1:
253 break;
254 case 2:
256 break;
257 default:
259 break;
260 }
261 switch (selected_join_type) {
262 case 0:
264 break;
265 case 1:
267 break;
268 case 2:
270 break;
271 default:
273 break;
274 }
275 paint.setStrokeCap(cap);
276 paint.setStrokeJoin(join);
277 paint.setStrokeWidth(stroke_width);
278
279 // Make rendering better to watch.
280 builder.Scale(1.5f, 1.5f);
281
282 // Rectangle
283 builder.Translate(100, 100);
284 builder.DrawRect(DlRect::MakeWH(100, 100), paint);
285
286 // Rounded rectangle
287 builder.Translate(150, 0);
288 builder.DrawRoundRect(
289 DlRoundRect::MakeRectXY(DlRect::MakeWH(100, 50), 10, 10), paint);
290
291 // Double rounded rectangle
292 builder.Translate(150, 0);
293 builder.DrawDiffRoundRect(
294 DlRoundRect::MakeRectXY(DlRect::MakeWH(100, 50), 10, 10),
295 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(10, 10, 80, 30), 10, 10),
296 paint);
297
298 // Contour with duplicate join points
299 {
300 builder.Translate(150, 0);
301 flutter::DlPathBuilder path_builder;
302 path_builder.MoveTo(DlPoint(0, 0));
303 path_builder.LineTo(DlPoint(0, 0));
304 path_builder.LineTo(DlPoint(100, 0));
305 path_builder.LineTo(DlPoint(100, 0));
306 path_builder.LineTo(DlPoint(100, 100));
307 builder.DrawPath(path_builder.TakePath(), paint);
308 }
309
310 // Contour with duplicate start and end points
311
312 // Line.
313 builder.Translate(200, 0);
314 {
315 builder.Save();
316
317 flutter::DlPathBuilder line_path_builder;
318 line_path_builder.MoveTo(DlPoint(0, 0));
319 line_path_builder.MoveTo(DlPoint(0, 0));
320 line_path_builder.LineTo(DlPoint(0, 0));
321 line_path_builder.LineTo(DlPoint(0, 0));
322 line_path_builder.LineTo(DlPoint(50, 50));
323 line_path_builder.LineTo(DlPoint(50, 50));
324 line_path_builder.LineTo(DlPoint(100, 0));
325 line_path_builder.LineTo(DlPoint(100, 0));
326 DlPath line_path = line_path_builder.TakePath();
327 builder.DrawPath(line_path, paint);
328
329 builder.Translate(0, 100);
330 builder.DrawPath(line_path, paint);
331
332 builder.Translate(0, 100);
333 flutter::DlPathBuilder line_path_builder2;
334 line_path_builder2.MoveTo(DlPoint(0, 0));
335 line_path_builder2.LineTo(DlPoint(0, 0));
336 line_path_builder2.LineTo(DlPoint(0, 0));
337 builder.DrawPath(line_path_builder2.TakePath(), paint);
338
339 builder.Restore();
340 }
341
342 // Cubic.
343 builder.Translate(150, 0);
344 {
345 builder.Save();
346
347 flutter::DlPathBuilder cubic_path;
348 cubic_path.MoveTo(DlPoint(0, 0));
349 cubic_path.CubicCurveTo(DlPoint(0, 0), //
350 DlPoint(140.0, 100.0), //
351 DlPoint(140, 20));
352 builder.DrawPath(cubic_path.TakePath(), paint);
353
354 builder.Translate(0, 100);
355 flutter::DlPathBuilder cubic_path2;
356 cubic_path2.MoveTo(DlPoint(0, 0));
357 cubic_path2.CubicCurveTo(DlPoint(0, 0), //
358 DlPoint(0, 0), //
359 DlPoint(150, 150));
360 builder.DrawPath(cubic_path2.TakePath(), paint);
361
362 builder.Translate(0, 100);
363 flutter::DlPathBuilder cubic_path3;
364 cubic_path3.MoveTo(DlPoint(0, 0));
365 cubic_path3.CubicCurveTo(DlPoint(0, 0), //
366 DlPoint(0, 0), //
367 DlPoint(0, 0));
368 builder.DrawPath(cubic_path3.TakePath(), paint);
369
370 builder.Restore();
371 }
372
373 // Quad.
374 builder.Translate(200, 0);
375 {
376 builder.Save();
377
378 flutter::DlPathBuilder quad_path;
379 quad_path.MoveTo(DlPoint(0, 0));
380 quad_path.MoveTo(DlPoint(0, 0));
381 quad_path.QuadraticCurveTo(DlPoint(100, 40), DlPoint(50, 80));
382 builder.DrawPath(quad_path.TakePath(), paint);
383
384 builder.Translate(0, 150);
385 flutter::DlPathBuilder quad_path2;
386 quad_path2.MoveTo(DlPoint(0, 0));
387 quad_path2.MoveTo(DlPoint(0, 0));
388 quad_path2.QuadraticCurveTo(DlPoint(0, 0), DlPoint(100, 100));
389 builder.DrawPath(quad_path2.TakePath(), paint);
390
391 builder.Translate(0, 100);
392 flutter::DlPathBuilder quad_path3;
393 quad_path3.MoveTo(DlPoint(0, 0));
394 quad_path3.QuadraticCurveTo(DlPoint(0, 0), DlPoint(0, 0));
395 builder.DrawPath(quad_path3.TakePath(), paint);
396
397 builder.Restore();
398 }
399 return builder.Build();
400 };
401 ASSERT_TRUE(OpenPlaygroundHere(callback));
402}
403
404TEST_P(DisplayListTest, CanDrawWithOddPathWinding) {
406 flutter::DlPaint paint;
407
410
411 builder.Translate(300, 300);
412 flutter::DlPathBuilder path_builder;
413 path_builder.AddCircle(DlPoint(0, 0), 100);
414 path_builder.AddCircle(DlPoint(0, 0), 50);
415 path_builder.SetFillType(flutter::DlPathFillType::kOdd);
416 builder.DrawPath(path_builder.TakePath(), paint);
417
418 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
419}
420
421// Regression test for https://github.com/flutter/flutter/issues/134816.
422//
423// It should be possible to draw 3 lines, and not have an implicit close path.
424TEST_P(DisplayListTest, CanDrawAnOpenPath) {
426 flutter::DlPaint paint;
427
430 paint.setStrokeWidth(10);
431
432 builder.Translate(300, 300);
433
434 // Move to (50, 50) and draw lines from:
435 // 1. (50, height)
436 // 2. (width, height)
437 // 3. (width, 50)
438 flutter::DlPathBuilder path_builder;
439 path_builder.MoveTo(DlPoint(50, 50));
440 path_builder.LineTo(DlPoint(50, 100));
441 path_builder.LineTo(DlPoint(100, 100));
442 path_builder.LineTo(DlPoint(100, 50));
443 builder.DrawPath(path_builder.TakePath(), paint);
444
445 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
446}
447
448TEST_P(DisplayListTest, CanDrawWithMaskBlur) {
449 auto texture = CreateTextureForFixture("embarcadero.jpg");
451 flutter::DlPaint paint;
452
453 // Mask blurred image.
454 {
455 auto filter =
457 paint.setMaskFilter(&filter);
460 }
461
462 // Mask blurred filled path.
463 {
465 auto filter =
467 paint.setMaskFilter(&filter);
468 builder.DrawArc(DlRect::MakeXYWH(410, 110, 100, 100), 45, 270, true, paint);
469 }
470
471 // Mask blurred text.
472 {
473 auto filter =
475 paint.setMaskFilter(&filter);
476 builder.DrawText(
478 SkTextBlob::MakeFromString("Testing", CreateTestFont())),
479 220, 170, paint);
480 }
481
482 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
483}
484
485TEST_P(DisplayListTest, CanDrawStrokedText) {
487 flutter::DlPaint paint;
488
491 builder.DrawText(
492 flutter::DlTextImpeller::MakeFromBlob(SkTextBlob::MakeFromString(
493 "stoked about stroked text", CreateTestFont())),
494 250, 250, paint);
495
496 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
497}
498
499// Regression test for https://github.com/flutter/flutter/issues/133157.
500TEST_P(DisplayListTest, StrokedTextNotOffsetFromNormalText) {
502 flutter::DlPaint paint;
503 auto const& text_blob = SkTextBlob::MakeFromString("00000", CreateTestFont());
505
506 // https://api.flutter.dev/flutter/material/Colors/blue-constant.html.
507 auto const& mat_blue = flutter::DlColor(0xFF2196f3);
508
509 // Draw a blue filled rectangle so the text is easier to see.
511 paint.setColor(mat_blue);
512 builder.DrawRect(DlRect::MakeXYWH(0, 0, 500, 500), paint);
513
514 // Draw stacked text, with stroked text on top.
517 builder.DrawText(text, 250, 250, paint);
518
521 builder.DrawText(text, 250, 250, paint);
522
523 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
524}
525
526TEST_P(DisplayListTest, IgnoreMaskFilterWhenSavingLayer) {
527 auto texture = CreateTextureForFixture("embarcadero.jpg");
530 flutter::DlPaint paint;
531 paint.setMaskFilter(&filter);
532 builder.SaveLayer(std::nullopt, &paint);
535 builder.Restore();
536 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
537}
538
539TEST_P(DisplayListTest, CanDrawWithBlendColorFilter) {
540 auto texture = CreateTextureForFixture("embarcadero.jpg");
542 flutter::DlPaint paint;
543
544 // Pipeline blended image.
545 {
547 flutter::DlColor::kYellow(), flutter::DlBlendMode::kModulate);
548 paint.setColorFilter(filter);
551 }
552
553 // Advanced blended image.
554 {
556 flutter::DlColor::kRed(), flutter::DlBlendMode::kScreen);
557 paint.setColorFilter(filter);
560 }
561
562 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
563}
564
565TEST_P(DisplayListTest, CanDrawWithColorFilterImageFilter) {
566 const float invert_color_matrix[20] = {
567 -1, 0, 0, 0, 1, //
568 0, -1, 0, 0, 1, //
569 0, 0, -1, 0, 1, //
570 0, 0, 0, 1, 0, //
571 };
572 auto texture = CreateTextureForFixture("boston.jpg");
574 flutter::DlPaint paint;
575
576 auto color_filter = flutter::DlColorFilter::MakeMatrix(invert_color_matrix);
577 auto image_filter = flutter::DlImageFilter::MakeColorFilter(color_filter);
578
579 paint.setImageFilter(image_filter);
582
583 builder.Translate(0, 700);
584 paint.setColorFilter(color_filter);
587 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
588}
589
590TEST_P(DisplayListTest, CanDrawWithImageBlurFilter) {
591 auto texture = CreateTextureForFixture("embarcadero.jpg");
592
593 auto callback = [&]() {
594 static float sigma[] = {10, 10};
595
596 if (IsPlaygroundEnabled()) {
597 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
598 ImGui::SliderFloat2("Sigma", sigma, 0, 100);
599 ImGui::End();
600 }
601
603 flutter::DlPaint paint;
604
605 auto filter = flutter::DlBlurImageFilter(sigma[0], sigma[1],
607 paint.setImageFilter(&filter);
610
611 return builder.Build();
612 };
613
614 ASSERT_TRUE(OpenPlaygroundHere(callback));
615}
616
617TEST_P(DisplayListTest, CanDrawWithComposeImageFilter) {
618 auto texture = CreateTextureForFixture("boston.jpg");
620 flutter::DlPaint paint;
621
622 auto dilate = std::make_shared<flutter::DlDilateImageFilter>(10.0, 10.0);
623 auto erode = std::make_shared<flutter::DlErodeImageFilter>(10.0, 10.0);
624 auto open = std::make_shared<flutter::DlComposeImageFilter>(dilate, erode);
625 auto close = std::make_shared<flutter::DlComposeImageFilter>(erode, dilate);
626
627 paint.setImageFilter(open.get());
630 builder.Translate(0, 700);
631 paint.setImageFilter(close.get());
634 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
635}
636
637TEST_P(DisplayListTest, CanClampTheResultingColorOfColorMatrixFilter) {
638 auto texture = CreateTextureForFixture("boston.jpg");
639 const float inner_color_matrix[20] = {
640 1, 0, 0, 0, 0, //
641 0, 1, 0, 0, 0, //
642 0, 0, 1, 0, 0, //
643 0, 0, 0, 2, 0, //
644 };
645 const float outer_color_matrix[20] = {
646 1, 0, 0, 0, 0, //
647 0, 1, 0, 0, 0, //
648 0, 0, 1, 0, 0, //
649 0, 0, 0, 0.5, 0, //
650 };
651 auto inner_color_filter =
652 flutter::DlColorFilter::MakeMatrix(inner_color_matrix);
653 auto outer_color_filter =
654 flutter::DlColorFilter::MakeMatrix(outer_color_matrix);
655 auto inner = flutter::DlImageFilter::MakeColorFilter(inner_color_filter);
656 auto outer = flutter::DlImageFilter::MakeColorFilter(outer_color_filter);
657 auto compose = std::make_shared<flutter::DlComposeImageFilter>(outer, inner);
658
660 flutter::DlPaint paint;
661 paint.setImageFilter(compose.get());
664 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
665}
666
667TEST_P(DisplayListTest, CanDrawBackdropFilter) {
668 auto texture = CreateTextureForFixture("embarcadero.jpg");
669
670 auto callback = [&]() {
671 static float sigma[] = {10, 10};
672 static float ctm_scale = 1;
673 static bool use_bounds = true;
674 static bool draw_circle = true;
675 static bool add_clip = true;
676
677 if (IsPlaygroundEnabled()) {
678 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
679 ImGui::SliderFloat2("Sigma", sigma, 0, 100);
680 ImGui::SliderFloat("Scale", &ctm_scale, 0, 10);
681 ImGui::NewLine();
682 ImGui::TextWrapped(
683 "If everything is working correctly, none of the options below "
684 "should impact the filter's appearance.");
685 ImGui::Checkbox("Use SaveLayer bounds", &use_bounds);
686 ImGui::Checkbox("Draw child element", &draw_circle);
687 ImGui::Checkbox("Add pre-clip", &add_clip);
688 ImGui::End();
689 }
690
692
693 Vector2 scale = ctm_scale * GetContentScale();
694 builder.Scale(scale.x, scale.y);
695
696 auto filter = flutter::DlBlurImageFilter(sigma[0], sigma[1],
698
699 std::optional<DlRect> bounds;
700 if (use_bounds) {
701 static PlaygroundPoint point_a(Point(350, 150), 20, Color::White());
702 static PlaygroundPoint point_b(Point(800, 600), 20, Color::White());
703 auto [p1, p2] = DrawPlaygroundLine(point_a, point_b);
704 bounds = DlRect::MakeLTRB(p1.x, p1.y, p2.x, p2.y);
705 }
706
707 // Insert a clip to test that the backdrop filter handles stencil depths > 0
708 // correctly.
709 if (add_clip) {
710 builder.ClipRect(DlRect::MakeLTRB(0, 0, 99999, 99999),
712 }
713
716 builder.SaveLayer(bounds, nullptr, &filter);
717
718 if (draw_circle) {
719 static PlaygroundPoint center_point(Point(500, 400), 20, Color::Red());
720 auto circle_center = DrawPlaygroundPoint(center_point);
721
722 flutter::DlPaint paint;
726 paint.setStrokeWidth(10);
727 paint.setColor(flutter::DlColor::kRed().withAlpha(100));
728 builder.DrawCircle(DlPoint(circle_center.x, circle_center.y), 100, paint);
729 }
730
731 return builder.Build();
732 };
733
734 ASSERT_TRUE(OpenPlaygroundHere(callback));
735}
736
737TEST_P(DisplayListTest, CanDrawBoundedBlur) {
738 auto texture = CreateTextureForFixture("kalimba.jpg");
739 const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
740 const flutter::DlTileMode tile_modes[] = {
743
744 auto callback = [&]() {
745 static float sigma = 20;
746 static float bg_scale = 2.1;
747 static float rotate_degree = 0;
748 static float bounds_scale = 1.0;
749 static bool use_bounds = true;
750 static int selected_tile_mode = 0;
751
752 if (IsPlaygroundEnabled()) {
753 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
754 ImGui::SliderFloat("Background scale", &bg_scale, 0, 10);
755 ImGui::SliderFloat("Sigma", &sigma, 0, 100);
756 ImGui::SliderFloat("Bounds rotate", &rotate_degree, -200, 200);
757 ImGui::SliderFloat("Bounds scale", &bounds_scale, 0.5f, 2.0f);
758 ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
759 sizeof(tile_mode_names) / sizeof(char*));
760 ImGui::NewLine();
761 ImGui::Checkbox("Bounded blur", &use_bounds);
762 ImGui::End();
763 }
764
765 // Draw from top right to bottom left.
766 static PlaygroundPoint blur_point_a(Point(410, 30), 10, Color::White());
767 static PlaygroundPoint blur_point_b(Point(150, 320), 10, Color::White());
768 auto [p1_raw, p2_raw] = DrawPlaygroundLine(blur_point_a, blur_point_b);
769 Matrix content_scale_transform = Matrix::MakeScale(GetContentScale());
770 Point p1_global = content_scale_transform * p1_raw;
771 Point p2_global = content_scale_transform * p2_raw;
772
774
775 builder.Save();
776 builder.Scale(bg_scale, bg_scale);
779 builder.Restore();
780
782 Matrix::MakeRotationZ(Radians(rotate_degree / 180.0f * kPi));
783 Matrix inverse_transform = transform.Invert();
784
785 builder.Transform(transform);
786
787 Point p1 = inverse_transform * p1_global;
788 Point p2 = inverse_transform * p2_global;
789 DlRect bounds =
790 DlRect::MakeLTRB(p2.x, p1.y, p1.x, p2.y).Scale(bounds_scale);
791
792 builder.ClipRect(bounds);
793 builder.Save();
794
795 flutter::DlPaint save_paint;
796 save_paint.setBlendMode(flutter::DlBlendMode::kSrcOver);
797
798 std::optional<DlRect> blur_bounds;
799 if (use_bounds) {
800 blur_bounds = bounds;
801 }
802 auto filter = flutter::DlBlurImageFilter(
803 sigma, sigma, tile_modes[selected_tile_mode], blur_bounds);
804 builder.SaveLayer(std::nullopt, &save_paint, &filter);
805 builder.Restore();
806 builder.Restore();
807
808 return builder.Build();
809 };
810
811 ASSERT_TRUE(OpenPlaygroundHere(callback));
812}
813
814TEST_P(DisplayListTest, CanDrawNinePatchImage) {
815 // Image is drawn with corners to scale and center pieces stretched to fit.
816 auto texture = CreateTextureForFixture("embarcadero.jpg");
818 auto size = texture->GetSize();
819 builder.DrawImageNine(
821 DlIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
822 size.height * 3 / 4),
823 DlRect::MakeLTRB(0, 0, size.width * 2, size.height * 2),
825 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
826}
827
828TEST_P(DisplayListTest, CanDrawNinePatchImageCenterWidthBiggerThanDest) {
829 // Edge case, the width of the corners does not leave any room for the
830 // center slice. The center (across the vertical axis) is folded out of the
831 // resulting image.
832 auto texture = CreateTextureForFixture("embarcadero.jpg");
834 auto size = texture->GetSize();
835 builder.DrawImageNine(
837 DlIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
838 size.height * 3 / 4),
839 DlRect::MakeLTRB(0, 0, size.width / 2, size.height),
841 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
842}
843
844TEST_P(DisplayListTest, CanDrawNinePatchImageCenterHeightBiggerThanDest) {
845 // Edge case, the height of the corners does not leave any room for the
846 // center slice. The center (across the horizontal axis) is folded out of the
847 // resulting image.
848 auto texture = CreateTextureForFixture("embarcadero.jpg");
850 auto size = texture->GetSize();
851 builder.DrawImageNine(
853 DlIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
854 size.height * 3 / 4),
855 DlRect::MakeLTRB(0, 0, size.width, size.height / 2),
857 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
858}
859
860TEST_P(DisplayListTest, CanDrawNinePatchImageCenterBiggerThanDest) {
861 // Edge case, the width and height of the corners does not leave any
862 // room for the center slices. Only the corners are displayed.
863 auto texture = CreateTextureForFixture("embarcadero.jpg");
865 auto size = texture->GetSize();
866 builder.DrawImageNine(
868 DlIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
869 size.height * 3 / 4),
870 DlRect::MakeLTRB(0, 0, size.width / 2, size.height / 2),
872 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
873}
874
875TEST_P(DisplayListTest, CanDrawNinePatchImageCornersScaledDown) {
876 // Edge case, there is not enough room for the corners to be drawn
877 // without scaling them down.
878 auto texture = CreateTextureForFixture("embarcadero.jpg");
880 auto size = texture->GetSize();
881 builder.DrawImageNine(
883 DlIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
884 size.height * 3 / 4),
885 DlRect::MakeLTRB(0, 0, size.width / 4, size.height / 4),
887 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
888}
889
890TEST_P(DisplayListTest, NinePatchImagePrecision) {
891 // Draw a nine patch image with colored corners and verify that the corner
892 // color does not leak outside the intended region.
893 auto texture = CreateTextureForFixture("nine_patch_corners.png");
896 DlIRect::MakeXYWH(10, 10, 1, 1),
897 DlRect::MakeXYWH(0, 0, 200, 100),
899 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
900}
901
902TEST_P(DisplayListTest, NinePatchImageColorFilter) {
903 auto texture = CreateTextureForFixture("nine_patch2.png");
904
906 flutter::DlBlendMode::kSrcIn);
907 flutter::DlPaint paint;
908 paint.setColorFilter(filter);
909
912 DlIRect::MakeXYWH(10, 10, 1, 1),
913 DlRect::MakeXYWH(0, 0, 200, 100),
915 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
916}
917
918TEST_P(DisplayListTest, CanDrawPoints) {
920 DlPoint points[7] = {
921 {0, 0}, //
922 {100, 100}, //
923 {100, 0}, //
924 {0, 100}, //
925 {0, 0}, //
926 {48, 48}, //
927 {52, 52}, //
928 };
929 std::vector<flutter::DlStrokeCap> caps = {
933 };
934 flutter::DlPaint paint =
936 .setColor(flutter::DlColor::kYellow().withAlpha(127)) //
937 .setStrokeWidth(20);
938 builder.Translate(50, 50);
939 for (auto cap : caps) {
940 paint.setStrokeCap(cap);
941 builder.Save();
943 builder.Translate(150, 0);
945 builder.Translate(150, 0);
947 builder.Restore();
948 builder.Translate(0, 150);
949 }
950 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
951}
952
953TEST_P(DisplayListTest, CanDrawZeroLengthLine) {
955 std::vector<flutter::DlStrokeCap> caps = {
959 };
960 flutter::DlPaint paint =
962 .setColor(flutter::DlColor::kYellow().withAlpha(127)) //
965 .setStrokeWidth(20);
966 DlPath path = DlPath::MakeLine({150, 50}, {150, 50});
967 for (auto cap : caps) {
968 paint.setStrokeCap(cap);
969 builder.DrawLine(DlPoint(50, 50), DlPoint(50, 50), paint);
970 builder.DrawPath(path, paint);
971 builder.Translate(0, 150);
972 }
973 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
974}
975
976TEST_P(DisplayListTest, CanDrawShadow) {
978 flutter::DlPaint paint;
979
980 auto content_scale = GetContentScale() * 0.8;
981 builder.Scale(content_scale.x, content_scale.y);
982
983 constexpr size_t star_spikes = 5;
984 constexpr DlScalar half_spike_rotation = kPi / star_spikes;
985 constexpr DlScalar radius = 40;
986 constexpr DlScalar spike_size = 10;
987 constexpr DlScalar outer_radius = radius + spike_size;
988 constexpr DlScalar inner_radius = radius - spike_size;
989 std::array<DlPoint, star_spikes * 2> star;
990 for (size_t i = 0; i < star_spikes; i++) {
991 const DlScalar rotation = half_spike_rotation * i * 2;
992 star[i * 2] = DlPoint(50 + std::sin(rotation) * outer_radius,
993 50 - std::cos(rotation) * outer_radius);
994 star[i * 2 + 1] =
995 DlPoint(50 + std::sin(rotation + half_spike_rotation) * inner_radius,
996 50 - std::cos(rotation + half_spike_rotation) * inner_radius);
997 }
998
999 std::array<DlPath, 4> paths = {
1000 DlPath::MakeRect(DlRect::MakeXYWH(0, 0, 200, 100)),
1001 DlPath::MakeRoundRectXY(DlRect::MakeXYWH(20, 0, 200, 100), 30, 30),
1002 DlPath::MakeCircle(DlPoint(100, 50), 50),
1003 DlPath::MakePoly(star.data(), star.size(), true),
1004 };
1006 builder.DrawPaint(paint);
1008 builder.Translate(100, 50);
1009 for (size_t x = 0; x < paths.size(); x++) {
1010 builder.Save();
1011 for (size_t y = 0; y < 6; y++) {
1012 builder.DrawShadow(paths[x], flutter::DlColor::kBlack(), 3 + y * 8, false,
1013 1);
1014 builder.DrawPath(paths[x], paint);
1015 builder.Translate(0, 150);
1016 }
1017 builder.Restore();
1018 builder.Translate(250, 0);
1019 }
1020
1021 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1022}
1023
1024TEST_P(DisplayListTest, CanDrawZeroWidthLine) {
1026 std::vector<flutter::DlStrokeCap> caps = {
1030 };
1031 flutter::DlPaint paint = //
1032 flutter::DlPaint() //
1035 .setStrokeWidth(0);
1036 flutter::DlPaint outline_paint = //
1037 flutter::DlPaint() //
1041 .setStrokeWidth(1);
1042 DlPath path = DlPath::MakeLine({150, 50}, {160, 50});
1043 for (auto cap : caps) {
1044 paint.setStrokeCap(cap);
1045 builder.DrawLine(DlPoint(50, 50), DlPoint(60, 50), paint);
1046 builder.DrawRect(DlRect::MakeLTRB(45, 45, 65, 55), outline_paint);
1047 builder.DrawLine(DlPoint{100, 50}, DlPoint{100, 50}, paint);
1048 if (cap != flutter::DlStrokeCap::kButt) {
1049 builder.DrawRect(DlRect::MakeLTRB(95, 45, 105, 55), outline_paint);
1050 }
1051 builder.DrawPath(path, paint);
1052 builder.DrawRect(path.GetBounds().Expand(5, 5), outline_paint);
1053 builder.Translate(0, 150);
1054 }
1055 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1056}
1057
1058TEST_P(DisplayListTest, CanDrawWithMatrixFilter) {
1059 auto boston = CreateTextureForFixture("boston.jpg");
1060
1061 auto callback = [&]() {
1062 static int selected_matrix_type = 0;
1063 const char* matrix_type_names[] = {"Matrix", "Local Matrix"};
1064
1065 static float ctm_translation[2] = {200, 200};
1066 static float ctm_scale[2] = {0.65, 0.65};
1067 static float ctm_skew[2] = {0, 0};
1068
1069 static bool enable = true;
1070 static float translation[2] = {100, 100};
1071 static float scale[2] = {0.8, 0.8};
1072 static float skew[2] = {0.2, 0.2};
1073
1074 static bool enable_savelayer = true;
1075
1076 if (IsPlaygroundEnabled()) {
1077 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1078 ImGui::Combo("Filter type", &selected_matrix_type, matrix_type_names,
1079 sizeof(matrix_type_names) / sizeof(char*));
1080
1081 ImGui::TextWrapped("Current Transform");
1082 ImGui::SliderFloat2("CTM Translation", ctm_translation, 0, 1000);
1083 ImGui::SliderFloat2("CTM Scale", ctm_scale, 0, 3);
1084 ImGui::SliderFloat2("CTM Skew", ctm_skew, -3, 3);
1085
1086 ImGui::TextWrapped(
1087 "MatrixFilter and LocalMatrixFilter modify the CTM in the same way. "
1088 "The only difference is that MatrixFilter doesn't affect the effect "
1089 "transform, whereas LocalMatrixFilter does.");
1090 // Note: See this behavior in:
1091 // https://fiddle.skia.org/c/6cbb551ab36d06f163db8693972be954
1092 ImGui::Checkbox("Enable", &enable);
1093 ImGui::SliderFloat2("Filter Translation", translation, 0, 1000);
1094 ImGui::SliderFloat2("Filter Scale", scale, 0, 3);
1095 ImGui::SliderFloat2("Filter Skew", skew, -3, 3);
1096
1097 ImGui::TextWrapped(
1098 "Rendering the filtered image within a layer can expose bounds "
1099 "issues. If the rendered image gets cut off when this setting is "
1100 "enabled, there's a coverage bug in the filter.");
1101 ImGui::Checkbox("Render in layer", &enable_savelayer);
1102 ImGui::End();
1103 }
1104
1106 flutter::DlPaint paint;
1107
1108 if (enable_savelayer) {
1109 builder.SaveLayer(std::nullopt, nullptr);
1110 }
1111 {
1112 auto content_scale = GetContentScale();
1113 builder.Scale(content_scale.x, content_scale.y);
1114
1115 // Set the current transform
1116 auto ctm_matrix = Matrix::MakeRow(
1117 ctm_scale[0], ctm_skew[0], 0.0f, ctm_translation[0], //
1118 ctm_skew[1], ctm_scale[1], 0.0f, ctm_translation[1], //
1119 0, 0, 1, 0, //
1120 0, 0, 0, 1);
1121 builder.Transform(ctm_matrix);
1122
1123 // Set the matrix filter
1124 auto filter_matrix =
1125 Matrix::MakeRow(scale[0], skew[0], 0.0f, translation[0], //
1126 skew[1], scale[1], 0.0f, translation[1], //
1127 0.0f, 0.0f, 1.0f, 0.0f, //
1128 0.0f, 0.0f, 0.0f, 1.0f);
1129
1130 if (enable) {
1131 switch (selected_matrix_type) {
1132 case 0: {
1133 auto filter = flutter::DlMatrixImageFilter(
1134 filter_matrix, flutter::DlImageSampling::kLinear);
1135 paint.setImageFilter(&filter);
1136 break;
1137 }
1138 case 1: {
1139 auto internal_filter =
1141 .shared();
1142 auto filter = flutter::DlLocalMatrixImageFilter(filter_matrix,
1143 internal_filter);
1144 paint.setImageFilter(&filter);
1145 break;
1146 }
1147 }
1148 }
1149
1150 builder.DrawImage(DlImageImpeller::Make(boston), DlPoint(),
1152 }
1153 if (enable_savelayer) {
1154 builder.Restore();
1155 }
1156
1157 return builder.Build();
1158 };
1159
1160 ASSERT_TRUE(OpenPlaygroundHere(callback));
1161}
1162
1163TEST_P(DisplayListTest, CanDrawWithMatrixFilterWhenSavingLayer) {
1164 auto callback = [&]() {
1165 static float translation[2] = {0, 0};
1166 static bool enable_save_layer = true;
1167
1168 if (IsPlaygroundEnabled()) {
1169 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1170 ImGui::SliderFloat2("Translation", translation, -130, 130);
1171 ImGui::Checkbox("Enable save layer", &enable_save_layer);
1172 ImGui::End();
1173 }
1174
1176 builder.Save();
1177 builder.Scale(2.0, 2.0);
1178 flutter::DlPaint paint;
1180 builder.DrawRect(DlRect::MakeWH(300, 300), paint);
1181 paint.setStrokeWidth(1.0);
1183 paint.setColor(flutter::DlColor::kBlack().withAlpha(0x80));
1184 builder.DrawLine(DlPoint(150, 0), DlPoint(150, 300), paint);
1185 builder.DrawLine(DlPoint(0, 150), DlPoint(300, 150), paint);
1186
1187 flutter::DlPaint save_paint;
1188 DlRect bounds = DlRect::MakeXYWH(100, 100, 100, 100);
1189 Matrix translate_matrix =
1190 Matrix::MakeTranslation({translation[0], translation[1]});
1191 if (enable_save_layer) {
1192 auto filter = flutter::DlMatrixImageFilter(
1194 save_paint.setImageFilter(filter.shared());
1195 builder.SaveLayer(bounds, &save_paint);
1196 } else {
1197 builder.Save();
1198 builder.Transform(translate_matrix);
1199 }
1200
1201 Matrix filter_matrix;
1202 filter_matrix.Translate({150, 150});
1203 filter_matrix.Scale({0.2f, 0.2f});
1204 filter_matrix.Translate({-150, -150});
1205 auto filter = flutter::DlMatrixImageFilter(
1207
1208 save_paint.setImageFilter(filter.shared());
1209
1210 builder.SaveLayer(bounds, &save_paint);
1211 flutter::DlPaint paint2;
1213 builder.DrawRect(bounds, paint2);
1214 builder.Restore();
1215 builder.Restore();
1216 return builder.Build();
1217 };
1218
1219 ASSERT_TRUE(OpenPlaygroundHere(callback));
1220}
1221
1222TEST_P(DisplayListTest, CanDrawRectWithLinearToSrgbColorFilter) {
1223 flutter::DlPaint paint;
1224 paint.setColor(flutter::DlColor(0xFF2196F3).withAlpha(128));
1227 builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), paint);
1228 builder.Translate(0, 200);
1229
1231 builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), paint);
1232
1233 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1234}
1235
1236TEST_P(DisplayListTest, CanDrawPaintWithColorSource) {
1237 const flutter::DlColor colors[2] = {
1238 flutter::DlColor(0xFFF44336),
1239 flutter::DlColor(0xFF2196F3),
1240 };
1241 const float stops[2] = {0.0, 1.0};
1242 flutter::DlPaint paint;
1244 auto clip_bounds = DlRect::MakeWH(300.0, 300.0);
1245 builder.Save();
1246 builder.Translate(100, 100);
1247 builder.ClipRect(clip_bounds, flutter::DlClipOp::kIntersect, false);
1248 auto linear =
1249 flutter::DlColorSource::MakeLinear({0.0, 0.0}, {100.0, 100.0}, 2, colors,
1251 paint.setColorSource(linear);
1252 builder.DrawPaint(paint);
1253 builder.Restore();
1254
1255 builder.Save();
1256 builder.Translate(500, 100);
1257 builder.ClipRect(clip_bounds, flutter::DlClipOp::kIntersect, false);
1259 {100.0, 100.0}, 100.0, 2, colors, stops, flutter::DlTileMode::kRepeat);
1260 paint.setColorSource(radial);
1261 builder.DrawPaint(paint);
1262 builder.Restore();
1263
1264 builder.Save();
1265 builder.Translate(100, 500);
1266 builder.ClipRect(clip_bounds, flutter::DlClipOp::kIntersect, false);
1267 auto sweep =
1268 flutter::DlColorSource::MakeSweep({100.0, 100.0}, 180.0, 270.0, 2, colors,
1270 paint.setColorSource(sweep);
1271 builder.DrawPaint(paint);
1272 builder.Restore();
1273
1274 builder.Save();
1275 builder.Translate(500, 500);
1276 builder.ClipRect(clip_bounds, flutter::DlClipOp::kIntersect, false);
1277 auto texture = CreateTextureForFixture("table_mountain_nx.png");
1281 paint.setColorSource(image);
1282 builder.DrawPaint(paint);
1283 builder.Restore();
1284
1285 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1286}
1287
1288TEST_P(DisplayListTest, CanBlendDstOverAndDstCorrectly) {
1290
1291 {
1292 builder.SaveLayer(std::nullopt, nullptr);
1293 builder.Translate(100, 100);
1294 flutter::DlPaint paint;
1296 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1297 paint.setColor(flutter::DlColor::kBlue().withAlpha(127));
1298 paint.setBlendMode(flutter::DlBlendMode::kSrcOver);
1299 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1300 builder.Restore();
1301 }
1302 {
1303 builder.SaveLayer(std::nullopt, nullptr);
1304 builder.Translate(300, 100);
1305 flutter::DlPaint paint;
1306 paint.setColor(flutter::DlColor::kBlue().withAlpha(127));
1307 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1309 paint.setBlendMode(flutter::DlBlendMode::kDstOver);
1310 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1311 builder.Restore();
1312 }
1313 {
1314 builder.SaveLayer(std::nullopt, nullptr);
1315 builder.Translate(100, 300);
1316 flutter::DlPaint paint;
1318 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1319 paint.setColor(flutter::DlColor::kBlue().withAlpha(127));
1320 paint.setBlendMode(flutter::DlBlendMode::kSrc);
1321 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1322 builder.Restore();
1323 }
1324 {
1325 builder.SaveLayer(std::nullopt, nullptr);
1326 builder.Translate(300, 300);
1327 flutter::DlPaint paint;
1328 paint.setColor(flutter::DlColor::kBlue().withAlpha(127));
1329 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1331 paint.setBlendMode(flutter::DlBlendMode::kDst);
1332 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1333 builder.Restore();
1334 }
1335
1336 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1337}
1338
1339TEST_P(DisplayListTest, CanDrawCorrectlyWithColorFilterAndImageFilter) {
1341 const float green_color_matrix[20] = {
1342 0, 0, 0, 0, 0, //
1343 0, 0, 0, 0, 1, //
1344 0, 0, 0, 0, 0, //
1345 0, 0, 0, 1, 0, //
1346 };
1347 const float blue_color_matrix[20] = {
1348 0, 0, 0, 0, 0, //
1349 0, 0, 0, 0, 0, //
1350 0, 0, 0, 0, 1, //
1351 0, 0, 0, 1, 0, //
1352 };
1353 auto green_color_filter =
1354 flutter::DlColorFilter::MakeMatrix(green_color_matrix);
1355 auto blue_color_filter =
1356 flutter::DlColorFilter::MakeMatrix(blue_color_matrix);
1357 auto blue_image_filter =
1358 flutter::DlImageFilter::MakeColorFilter(blue_color_filter);
1359
1360 flutter::DlPaint paint;
1362 paint.setColorFilter(green_color_filter);
1363 paint.setImageFilter(blue_image_filter);
1364 builder.DrawRect(DlRect::MakeLTRB(100, 100, 500, 500), paint);
1365 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1366}
1367
1368TEST_P(DisplayListTest, MaskBlursApplyCorrectlyToColorSources) {
1369 auto blur_filter = std::make_shared<flutter::DlBlurMaskFilter>(
1371
1373
1374 std::array<flutter::DlColor, 2> colors = {flutter::DlColor::kBlue(),
1376 std::array<float, 2> stops = {0, 1};
1377 auto texture = CreateTextureForFixture("airplane.jpg");
1378 auto matrix = flutter::DlMatrix::MakeTranslation({-300, -110});
1379 std::array<std::shared_ptr<flutter::DlColorSource>, 2> color_sources = {
1383 &matrix),
1385 flutter::DlPoint(0, 0), flutter::DlPoint(100, 50), 2, colors.data(),
1386 stops.data(), flutter::DlTileMode::kClamp),
1387 };
1388
1389 builder.Save();
1390 builder.Translate(0, 100);
1391 for (const auto& color_source : color_sources) {
1392 flutter::DlPaint paint;
1393 paint.setColorSource(color_source);
1394 paint.setMaskFilter(blur_filter);
1395
1396 builder.Save();
1397 builder.Translate(100, 0);
1399 builder.DrawRoundRect(
1400 DlRoundRect::MakeRectXY(DlRect::MakeWH(100, 50), 30, 30), paint);
1401
1403 paint.setStrokeWidth(10);
1404 builder.Translate(200, 0);
1405 builder.DrawRoundRect(
1406 DlRoundRect::MakeRectXY(DlRect::MakeWH(100, 50), 30, 30), paint);
1407
1408 builder.Restore();
1409 builder.Translate(0, 100);
1410 }
1411 builder.Restore();
1412
1413 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1414}
1415
1418 std::vector<flutter::DlStrokeJoin> joins = {
1422 };
1423 flutter::DlPaint paint = //
1424 flutter::DlPaint() //
1427 .setStrokeWidth(10);
1428 flutter::DlPaint stroke_paint = //
1429 flutter::DlPaint() //
1432 .setStrokeWidth(10);
1433 DlPath path = DlPath::MakeLine({150, 50}, {160, 50});
1434
1435 builder.Translate(300, 50);
1436 builder.Scale(0.8, 0.8);
1437 for (auto join : joins) {
1438 paint.setStrokeJoin(join);
1439 stroke_paint.setStrokeJoin(join);
1440 builder.DrawRect(DlRect::MakeXYWH(0, 0, 100, 100), paint);
1441 builder.DrawRect(DlRect::MakeXYWH(0, 150, 100, 100), stroke_paint);
1442 builder.DrawRoundRect(
1443 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(150, 0, 100, 100), 30, 30),
1444 paint);
1445 builder.DrawRoundRect(
1446 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(150, 150, 100, 100), 30, 30),
1447 stroke_paint);
1448 builder.DrawCircle(DlPoint(350, 50), 50, paint);
1449 builder.DrawCircle(DlPoint(350, 200), 50, stroke_paint);
1450 builder.Translate(0, 300);
1451 }
1452 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1453}
1454
1455TEST_P(DisplayListTest, DrawCirclesWithTransformations) {
1456 auto callback = [&]() {
1457 static float filled_radius = 100.0;
1458 static float filled_alpha = 255.0;
1459 static float filled_scale[2] = {1.0, 1.0};
1460 static float stroked_radius = 20.0;
1461 static float stroke_width = 10.0;
1462 static float stroke_width_fine = 0.0;
1463 static float stroked_alpha = 255.0;
1464 static float stroked_scale[2] = {1.0, 1.0};
1465
1466 if (IsPlaygroundEnabled()) {
1467 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1468 ImGui::SliderFloat("Filled Radius", &filled_radius, 0, 500);
1469 ImGui::SliderFloat("Filled Alpha", &filled_alpha, 0, 255);
1470 ImGui::SliderFloat2("Filled Scale", filled_scale, 0, 10.0);
1471 ImGui::SliderFloat("Stroked Radius", &stroked_radius, 0, 500);
1472 ImGui::SliderFloat("Stroked Width", &stroke_width, 0, 500);
1473 ImGui::SliderFloat("Stroked Width Fine", &stroke_width_fine, 0, 5);
1474 ImGui::SliderFloat("Stroked Alpha", &stroked_alpha, 0, 10.0);
1475 ImGui::SliderFloat2("Stroked Scale", stroked_scale, 0, 10.0);
1476 ImGui::End();
1477 }
1478
1480 flutter::DlPaint paint;
1481
1482 paint.setColor(flutter::DlColor::kBlue().withAlpha(filled_alpha));
1484 builder.Save();
1485 builder.Scale(filled_scale[0], filled_scale[1]);
1486 builder.DrawCircle(DlPoint(500, 750), filled_radius, paint);
1487 builder.Restore();
1488
1489 paint.setColor(flutter::DlColor::kRed().withAlpha(stroked_alpha));
1491 paint.setStrokeWidth(stroke_width + stroke_width_fine);
1492 builder.Save();
1493 builder.Scale(stroked_scale[0], stroked_scale[1]);
1494 builder.DrawCircle(DlPoint(1250, 750), stroked_radius, paint);
1495 builder.Restore();
1496 return builder.Build();
1497 };
1498
1499 ASSERT_TRUE(OpenPlaygroundHere(callback));
1500}
1501
1502TEST_P(DisplayListTest, ClipDrawRRectWithNonCircularRadii) {
1504
1505 flutter::DlPaint fill_paint = //
1506 flutter::DlPaint() //
1509 .setStrokeWidth(10);
1510 flutter::DlPaint stroke_paint = //
1511 flutter::DlPaint() //
1514 .setStrokeWidth(10);
1515
1516 builder.DrawRoundRect(
1517 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(500, 100, 300, 300), 120, 40),
1518 fill_paint);
1519 builder.DrawRoundRect(
1520 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(500, 100, 300, 300), 120, 40),
1521 stroke_paint);
1522
1523 builder.DrawRoundRect(
1524 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(100, 500, 300, 300), 40, 120),
1525 fill_paint);
1526 builder.DrawRoundRect(
1527 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(100, 500, 300, 300), 40, 120),
1528 stroke_paint);
1529
1530 flutter::DlPaint reference_paint = //
1531 flutter::DlPaint() //
1534 .setStrokeWidth(10);
1535
1536 builder.DrawRoundRect(
1537 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(500, 500, 300, 300), 40, 40),
1538 reference_paint);
1539 builder.DrawRoundRect(
1540 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(100, 100, 300, 300), 120, 120),
1541 reference_paint);
1542
1543 flutter::DlPaint clip_fill_paint = //
1544 flutter::DlPaint() //
1547 .setStrokeWidth(10);
1548
1549 builder.Save();
1550 builder.ClipRoundRect(
1551 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(900, 100, 300, 300), 120, 40));
1552 builder.DrawPaint(clip_fill_paint);
1553 builder.Restore();
1554
1555 builder.Save();
1556 builder.ClipRoundRect(
1557 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(100, 900, 300, 300), 40, 120));
1558 builder.DrawPaint(clip_fill_paint);
1559 builder.Restore();
1560
1561 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1562}
1563
1564TEST_P(DisplayListTest, DrawVerticesBlendModes) {
1565 std::vector<const char*> blend_mode_names;
1566 std::vector<flutter::DlBlendMode> blend_mode_values;
1567 {
1568 const std::vector<std::tuple<const char*, flutter::DlBlendMode>> blends = {
1569 // Pipeline blends (Porter-Duff alpha compositing)
1570 {"Clear", flutter::DlBlendMode::kClear},
1571 {"Source", flutter::DlBlendMode::kSrc},
1572 {"Destination", flutter::DlBlendMode::kDst},
1573 {"SourceOver", flutter::DlBlendMode::kSrcOver},
1574 {"DestinationOver", flutter::DlBlendMode::kDstOver},
1575 {"SourceIn", flutter::DlBlendMode::kSrcIn},
1576 {"DestinationIn", flutter::DlBlendMode::kDstIn},
1577 {"SourceOut", flutter::DlBlendMode::kSrcOut},
1578 {"DestinationOut", flutter::DlBlendMode::kDstOut},
1579 {"SourceATop", flutter::DlBlendMode::kSrcATop},
1580 {"DestinationATop", flutter::DlBlendMode::kDstATop},
1581 {"Xor", flutter::DlBlendMode::kXor},
1582 {"Plus", flutter::DlBlendMode::kPlus},
1583 {"Modulate", flutter::DlBlendMode::kModulate},
1584 // Advanced blends (color component blends)
1585 {"Screen", flutter::DlBlendMode::kScreen},
1586 {"Overlay", flutter::DlBlendMode::kOverlay},
1587 {"Darken", flutter::DlBlendMode::kDarken},
1588 {"Lighten", flutter::DlBlendMode::kLighten},
1589 {"ColorDodge", flutter::DlBlendMode::kColorDodge},
1590 {"ColorBurn", flutter::DlBlendMode::kColorBurn},
1591 {"HardLight", flutter::DlBlendMode::kHardLight},
1592 {"SoftLight", flutter::DlBlendMode::kSoftLight},
1593 {"Difference", flutter::DlBlendMode::kDifference},
1594 {"Exclusion", flutter::DlBlendMode::kExclusion},
1595 {"Multiply", flutter::DlBlendMode::kMultiply},
1596 {"Hue", flutter::DlBlendMode::kHue},
1597 {"Saturation", flutter::DlBlendMode::kSaturation},
1598 {"Color", flutter::DlBlendMode::kColor},
1599 {"Luminosity", flutter::DlBlendMode::kLuminosity},
1600 };
1601 assert(blends.size() ==
1602 static_cast<size_t>(flutter::DlBlendMode::kLastMode) + 1);
1603 for (const auto& [name, mode] : blends) {
1604 blend_mode_names.push_back(name);
1605 blend_mode_values.push_back(mode);
1606 }
1607 }
1608
1609 auto callback = [&]() {
1610 static int current_blend_index = 3;
1611 static float dst_alpha = 1;
1612 static float src_alpha = 1;
1613 static float color0[4] = {1.0f, 0.0f, 0.0f, 1.0f};
1614 static float color1[4] = {0.0f, 1.0f, 0.0f, 1.0f};
1615 static float color2[4] = {0.0f, 0.0f, 1.0f, 1.0f};
1616 static float src_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
1617
1618 if (IsPlaygroundEnabled()) {
1619 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1620 ImGui::ListBox("Blending mode", &current_blend_index,
1621 blend_mode_names.data(), blend_mode_names.size());
1622 ImGui::SliderFloat("Source alpha", &src_alpha, 0, 1);
1623 ImGui::ColorEdit4("Color A", color0);
1624 ImGui::ColorEdit4("Color B", color1);
1625 ImGui::ColorEdit4("Color C", color2);
1626 ImGui::ColorEdit4("Source Color", src_color);
1627 ImGui::SliderFloat("Destination alpha", &dst_alpha, 0, 1);
1628 ImGui::End();
1629 }
1630
1631 std::vector<DlPoint> positions = {DlPoint(100, 300), //
1632 DlPoint(200, 100), //
1633 DlPoint(300, 300)};
1634 std::vector<flutter::DlColor> colors = {
1635 toColor(color0).modulateOpacity(dst_alpha),
1636 toColor(color1).modulateOpacity(dst_alpha),
1637 toColor(color2).modulateOpacity(dst_alpha)};
1638
1639 auto vertices = flutter::DlVertices::Make(
1640 flutter::DlVertexMode::kTriangles, 3, positions.data(),
1641 /*texture_coordinates=*/nullptr, colors.data());
1642
1644 flutter::DlPaint paint;
1645
1646 paint.setColor(toColor(src_color).modulateOpacity(src_alpha));
1647 builder.DrawVertices(vertices, blend_mode_values[current_blend_index],
1648 paint);
1649 return builder.Build();
1650 };
1651
1652 ASSERT_TRUE(OpenPlaygroundHere(callback));
1653}
1654
1655TEST_P(DisplayListTest, DrawPaintIgnoresMaskFilter) {
1658
1660 builder.DrawCircle(DlPoint(300, 300), 200,
1661 flutter::DlPaint().setMaskFilter(&filter));
1662
1663 std::vector<flutter::DlColor> colors = {flutter::DlColor::kGreen(),
1665 const float stops[2] = {0.0, 1.0};
1667 {100.0, 100.0}, {300.0, 300.0}, 2, colors.data(), stops,
1669 flutter::DlPaint blend_paint =
1670 flutter::DlPaint() //
1671 .setColorSource(linear) //
1672 .setBlendMode(flutter::DlBlendMode::kScreen);
1673 builder.DrawPaint(blend_paint);
1674
1675 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1676}
1677
1678TEST_P(DisplayListTest, DrawMaskBlursThatMightUseSaveLayers) {
1680 builder.DrawColor(flutter::DlColor::kWhite(), flutter::DlBlendMode::kSrc);
1681 Vector2 scale = GetContentScale();
1682 builder.Scale(scale.x, scale.y);
1683
1684 builder.Save();
1685 // We need a small transform op to avoid a deferred save
1686 builder.Translate(1.0f, 1.0f);
1687 auto solid_filter =
1689 flutter::DlPaint solid_alpha_paint =
1690 flutter::DlPaint() //
1691 .setMaskFilter(solid_filter) //
1693 .setAlpha(0x7f);
1694 for (int x = 1; x <= 4; x++) {
1695 for (int y = 1; y <= 4; y++) {
1696 builder.DrawRect(DlRect::MakeXYWH(x * 100, y * 100, 80, 80),
1697 solid_alpha_paint);
1698 }
1699 }
1700 builder.Restore();
1701
1702 builder.Save();
1703 builder.Translate(500.0f, 0.0f);
1704 auto normal_filter =
1706 auto rotate_if = flutter::DlMatrixImageFilter::Make(
1708 flutter::DlPaint normal_if_paint =
1709 flutter::DlPaint() //
1710 .setMaskFilter(solid_filter) //
1711 .setImageFilter(rotate_if) //
1713 .setAlpha(0x7f);
1714 for (int x = 1; x <= 4; x++) {
1715 for (int y = 1; y <= 4; y++) {
1716 builder.DrawRect(DlRect::MakeXYWH(x * 100, y * 100, 80, 80),
1717 normal_if_paint);
1718 }
1719 }
1720 builder.Restore();
1721
1722 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1723}
1724
1725} // namespace testing
1726} // namespace impeller
void ClipRect(const DlRect &rect, DlClipOp clip_op=DlClipOp::kIntersect, bool is_aa=false) override
void DrawVertices(const std::shared_ptr< DlVertices > &vertices, DlBlendMode mode, const DlPaint &paint) override
void DrawImageNine(const sk_sp< DlImage > &image, const DlIRect &center, const DlRect &dst, DlFilterMode filter, const DlPaint *paint=nullptr) override
void DrawRoundRect(const DlRoundRect &rrect, const DlPaint &paint) override
void DrawArc(const DlRect &bounds, DlScalar start, DlScalar sweep, bool useCenter, const DlPaint &paint) override
void DrawShadow(const DlPath &path, const DlColor color, const DlScalar elevation, bool transparent_occluder, DlScalar dpr) override
Draws the shadow of the given |path| rendered in the provided |color| (which is only consulted for it...
void DrawImage(const sk_sp< DlImage > &image, const DlPoint &point, DlImageSampling sampling, const DlPaint *paint=nullptr) override
void DrawColor(DlColor color, DlBlendMode mode) override
void DrawCircle(const DlPoint &center, DlScalar radius, const DlPaint &paint) override
void SaveLayer(const std::optional< DlRect > &bounds, const DlPaint *paint=nullptr, const DlImageFilter *backdrop=nullptr, std::optional< int64_t > backdrop_id=std::nullopt) override
void DrawLine(const DlPoint &p0, const DlPoint &p1, const DlPaint &paint) override
void ClipRoundRect(const DlRoundRect &rrect, DlClipOp clip_op=DlClipOp::kIntersect, bool is_aa=false) override
void DrawText(const std::shared_ptr< DlText > &text, DlScalar x, DlScalar y, const DlPaint &paint) override
void Scale(DlScalar sx, DlScalar sy) override
void Translate(DlScalar tx, DlScalar ty) override
void DrawPaint(const DlPaint &paint) override
sk_sp< DisplayList > Build()
void DrawPath(const DlPath &path, const DlPaint &paint) override
void DrawPoints(DlPointMode mode, uint32_t count, const DlPoint pts[], const DlPaint &paint) override
void DrawDiffRoundRect(const DlRoundRect &outer, const DlRoundRect &inner, const DlPaint &paint) override
void Transform(const DlMatrix &matrix) override
void DrawRect(const DlRect &rect, const DlPaint &paint) override
std::shared_ptr< DlImageFilter > shared() const override
static std::shared_ptr< DlMaskFilter > Make(DlBlurStyle style, SkScalar sigma, bool respect_ctm=true)
static std::shared_ptr< const DlColorFilter > MakeBlend(DlColor color, DlBlendMode mode)
static std::shared_ptr< const DlColorFilter > MakeLinearToSrgbGamma()
static std::shared_ptr< const DlColorFilter > MakeMatrix(const float matrix[20])
static std::shared_ptr< const DlColorFilter > MakeSrgbToLinearGamma()
static std::shared_ptr< DlColorSource > MakeSweep(DlPoint center, DlScalar start, DlScalar end, uint32_t stop_count, const DlColor *colors, const float *stops, DlTileMode tile_mode, const DlMatrix *matrix=nullptr)
static std::shared_ptr< DlColorSource > MakeImage(const sk_sp< const DlImage > &image, DlTileMode horizontal_tile_mode, DlTileMode vertical_tile_mode, DlImageSampling sampling=DlImageSampling::kLinear, const DlMatrix *matrix=nullptr)
static std::shared_ptr< DlColorSource > MakeLinear(const DlPoint start_point, const DlPoint end_point, uint32_t stop_count, const DlColor *colors, const float *stops, DlTileMode tile_mode, const DlMatrix *matrix=nullptr)
static std::shared_ptr< DlColorSource > MakeRadial(DlPoint center, DlScalar radius, uint32_t stop_count, const DlColor *colors, const float *stops, DlTileMode tile_mode, const DlMatrix *matrix=nullptr)
static std::shared_ptr< DlImageFilter > MakeColorFilter(const std::shared_ptr< const DlColorFilter > &filter)
static std::shared_ptr< DlImageFilter > Make(const DlMatrix &matrix, DlImageSampling sampling)
DlPaint & setColor(DlColor color)
Definition dl_paint.h:70
DlPaint & setStrokeCap(DlStrokeCap cap)
Definition dl_paint.h:101
DlPaint & setStrokeWidth(float width)
Definition dl_paint.h:115
DlPaint & setAlpha(uint8_t alpha)
Definition dl_paint.h:76
DlPaint & setStrokeMiter(float miter)
Definition dl_paint.h:121
DlPaint & setBlendMode(DlBlendMode mode)
Definition dl_paint.h:85
DlPaint & setImageFilter(std::nullptr_t filter)
Definition dl_paint.h:167
DlPaint & setMaskFilter(std::nullptr_t filter)
Definition dl_paint.h:185
DlPaint & setDrawStyle(DlDrawStyle style)
Definition dl_paint.h:93
DlPaint & setStrokeJoin(DlStrokeJoin join)
Definition dl_paint.h:109
DlPaint & setColorFilter(std::nullptr_t filter)
Definition dl_paint.h:149
DlPaint & setColorSource(std::nullptr_t source)
Definition dl_paint.h:131
DlPathBuilder & LineTo(DlPoint p2)
Draw a line from the current point to the indicated point p2.
DlPathBuilder & MoveTo(DlPoint p2)
Start a new contour that will originate at the indicated point p2.
DlPathBuilder & SetFillType(DlPathFillType fill_type)
Set the fill type that should be used to determine the interior of this path to the indicated |fill_t...
const DlPath TakePath()
Returns the path constructed by this path builder and resets its internal state to the default state ...
DlPathBuilder & AddCircle(DlPoint center, DlScalar radius)
Append a closed circular contour to the path centered on the provided point at the provided radius.
DlPathBuilder & QuadraticCurveTo(DlPoint cp, DlPoint p2)
Draw a quadratic bezier curve from the current point to the indicated point p2, using the indicated p...
DlPathBuilder & CubicCurveTo(DlPoint cp1, DlPoint cp2, DlPoint p2)
Draw a cubic bezier curve from the current point to the indicated point p2, using the indicated point...
static DlPath MakeLine(const DlPoint a, const DlPoint b)
Definition dl_path.cc:89
static DlPath MakeCircle(const DlPoint center, DlScalar radius)
Definition dl_path.cc:68
static DlPath MakeRect(const DlRect &rect)
Definition dl_path.cc:39
static DlPath MakeRoundRectXY(const DlRect &rect, DlScalar x_radius, DlScalar y_radius, bool counter_clock_wise=false)
Definition dl_path.cc:76
static DlPath MakePoly(const DlPoint pts[], int count, bool close, DlPathFillType fill_type=DlPathFillType::kNonZero)
Definition dl_path.cc:93
static std::shared_ptr< DlTextImpeller > MakeFromBlob(const sk_sp< SkTextBlob > &blob)
static std::shared_ptr< DlVertices > Make(DlVertexMode mode, int vertex_count, const DlPoint vertices[], const DlPoint texture_coordinates[], const DlColor colors[], int index_count=0, const uint16_t indices[]=nullptr, const DlRect *bounds=nullptr)
Constructs a DlVector with compact inline storage for all of its required and optional lists of data.
double x() const
Definition geometry.h:22
double y() const
Definition geometry.h:23
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
int32_t x
FlutterVulkanImage * image
FlutterDesktopBinaryReply callback
std::u16string text
FlTexture * texture
double y
impeller::Scalar DlScalar
DlStrokeJoin
Definition dl_paint.h:37
@ kMiter
extends to miter limit
@ kBevel
connects outside edges
DlStrokeCap
Definition dl_paint.h:28
@ kRound
adds circle
@ kButt
no stroke extension
@ kSquare
adds square
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
@ 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
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switch_defs.h:52
DEF_SWITCHES_START aot vmservice shared library name
Definition switch_defs.h:27
@ kTriangles
The vertices are taken 3 at a time to form a triangle.
@ kStroke
strokes boundary of shapes
@ kFill
fills interior of shapes
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
static constexpr DlScalar kPi
@ kNormal
fuzzy inside and outside
@ kOuter
nothing inside, fuzzy outside
@ kSolid
solid inside, fuzzy outside
impeller::Point DlPoint
TEST_P(AiksTest, DrawAtlasNoColor)
flutter::DlColor toColor(const float *components)
Point DrawPlaygroundPoint(PlaygroundPoint &point)
Definition widgets.cc:11
std::tuple< Point, Point > DrawPlaygroundLine(PlaygroundPoint &point_a, PlaygroundPoint &point_b)
Definition widgets.cc:51
#define INSTANTIATE_PLAYGROUND_SUITE(playground)
static constexpr DlColor kWhite()
Definition dl_color.h:70
static constexpr DlColor kBlue()
Definition dl_color.h:73
static constexpr DlColor kBlack()
Definition dl_color.h:69
static constexpr DlColor kYellow()
Definition dl_color.h:76
static constexpr DlColor kMidGrey()
Definition dl_color.h:78
static constexpr DlColor kRed()
Definition dl_color.h:71
static constexpr DlColor kGreen()
Definition dl_color.h:72
static constexpr DlColor kCyan()
Definition dl_color.h:74
constexpr DlColor modulateOpacity(DlScalar opacity) const
Definition dl_color.h:150
static uint32_t ToIColor(Color color)
Convert this color to a 32-bit representation.
Definition color.h:159
static constexpr Color White()
Definition color.h:269
static constexpr Color Red()
Definition color.h:277
A 4x4 matrix using column-major storage.
Definition matrix.h:37
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition matrix.h:95
constexpr Matrix Translate(const Vector3 &t) const
Definition matrix.h:263
Matrix Invert() const
Definition matrix.cc:99
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
constexpr Matrix Scale(const Vector3 &s) const
Definition matrix.h:275
static Matrix MakeRotationZ(Radians r)
Definition matrix.h:223
static constexpr Matrix MakeScale(const Vector3 &s)
Definition matrix.h:104
static RoundRect MakeRectXY(const Rect &rect, Scalar x_radius, Scalar y_radius)
Definition round_rect.h:31
static constexpr TRect MakeWH(Type width, Type height)
Definition rect.h:140
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition rect.h:136
constexpr TRect Scale(Type scale) const
Definition rect.h:226
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129
std::vector< Point > points