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