13 #include "flutter/testing/testing.h"
19 #include "impeller/aiks/testing/context_spy.h"
43 #include "third_party/imgui/imgui.h"
44 #include "third_party/skia/include/core/SkData.h"
49 #ifdef IMPELLER_GOLDEN_TESTS
93 ASSERT_EQ(canvas.
Restore(),
false);
120 auto image = std::make_shared<Image>(CreateTextureForFixture(
"kalimba.jpg"));
129 auto image = std::make_shared<Image>(CreateTextureForFixture(
"kalimba.jpg"));
137 bool GenerateMipmap(
const std::shared_ptr<Context>& context,
138 std::shared_ptr<Texture> texture,
140 auto buffer = context->CreateCommandBuffer();
144 auto pass = buffer->CreateBlitPass();
148 pass->GenerateMipmap(std::move(texture), std::move(label));
149 pass->EncodeCommands(context->GetResourceAllocator());
150 return buffer->SubmitCommands();
153 void CanRenderTiledTexture(
AiksTest* aiks_test,
155 Matrix local_matrix = {}) {
156 auto context = aiks_test->GetContext();
157 ASSERT_TRUE(context);
158 auto texture = aiks_test->CreateTextureForFixture(
"table_mountain_nx.png",
160 GenerateMipmap(context, texture,
"table_mountain_nx");
162 canvas.Scale(aiks_test->GetContentScale());
163 canvas.Translate({100.0f, 100.0f, 0});
167 paint.color = Color(1, 1, 1, 1);
168 canvas.DrawRect({0, 0, 600, 600}, paint);
171 constexpr
auto stroke_width = 64;
173 paint.stroke_width = stroke_width;
175 canvas.DrawRect({stroke_width, stroke_width, 600, 600}, paint);
177 canvas.DrawRect({0, 0, 600, 600}, paint);
181 PathBuilder path_builder;
182 path_builder.AddCircle({150, 150}, 150);
183 path_builder.AddRoundedRect(
Rect::MakeLTRB(300, 300, 600, 600), 10);
185 canvas.DrawPath(path_builder.TakePath(), paint);
187 ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
215 auto image = std::make_shared<Image>(CreateTextureForFixture(
"kalimba.jpg"));
219 source_rect.size.width /= 2;
220 source_rect.size.height /= 2;
221 source_rect.origin.x += source_rect.size.width;
222 source_rect.origin.y += source_rect.size.height;
300 .HorizontalLineTo(-200)
302 .CubicCurveTo({0, -40}, {0, -80}, {200, -80})
340 for (
int i = 0; i < 15; i++) {
343 paint.
color = colors[i % colors.size()];
371 canvas.
Scale(aiks_test->GetContentScale());
375 std::vector<Color> colors = {Color{0.9568, 0.2627, 0.2118, 1.0},
376 Color{0.1294, 0.5882, 0.9529, 0.0}};
377 std::vector<Scalar> stops = {0.0, 1.0};
380 {0, 0}, {200, 200}, std::move(colors), std::move(stops), tile_mode, {});
382 paint.
color = Color(1.0, 1.0, 1.0, 1.0);
383 canvas.
DrawRect({0, 0, 600, 600}, paint);
403 canvas.
Scale(GetContentScale());
407 std::vector<Color> colors = {
Color{0.9568, 0.2627, 0.2118, 1.0},
408 Color{0.1294, 0.5882, 0.9529, 0.0}};
409 std::vector<Scalar> stops = {0.0, 1.0};
412 {0, 0}, {200, 200}, std::move(colors), std::move(stops),
421 canvas.
DrawRect({0, 0, 600, 600}, paint);
426 bool use_dithering) {
433 std::vector<Color> colors = {
Color{0.8, 0.8, 0.8, 1.0},
434 Color{0.2, 0.2, 0.2, 1.0}};
435 std::vector<Scalar> stops = {0.0, 1.0};
438 {0, 0}, {800, 500}, std::move(colors), std::move(stops),
440 paint.
dither = use_dithering;
441 canvas.
DrawRect({0, 0, 800, 500}, paint);
454 bool use_dithering) {
460 std::vector<Color> colors = {
Color{1.0, 1.0, 1.0, 1.0},
461 Color{0.0, 0.0, 0.0, 1.0}};
462 std::vector<Scalar> stops = {0.0, 1.0};
465 {600, 600}, 600, std::move(colors), std::move(stops),
467 paint.
dither = use_dithering;
468 canvas.
DrawRect({0, 0, 1200, 1200}, paint);
481 bool use_dithering) {
488 std::vector<Color> colors = {
Color{1.0, 1.0, 1.0, 1.0},
489 Color{0.0, 0.0, 0.0, 1.0}};
490 std::vector<Scalar> stops = {0.0, 1.0};
495 paint.
dither = use_dithering;
497 canvas.
DrawRect({0, 0, 600, 600}, paint);
510 bool use_dithering) {
517 std::vector<Color> colors = {
Color{1.0, 1.0, 1.0, 1.0},
518 Color{0.0, 0.0, 0.0, 1.0}};
519 std::vector<Scalar> stops = {0.0, 1.0};
522 {100, 100}, 100, std::move(colors), std::move(stops), {0, 1}, 0,
524 paint.
dither = use_dithering;
526 canvas.
DrawRect({0, 0, 600, 600}, paint);
539 void CanRenderLinearGradientWithOverlappingStops(
AiksTest* aiks_test,
545 std::vector<Color> colors = {
546 Color{0.9568, 0.2627, 0.2118, 1.0}, Color{0.9568, 0.2627, 0.2118, 1.0},
547 Color{0.1294, 0.5882, 0.9529, 1.0}, Color{0.1294, 0.5882, 0.9529, 1.0}};
548 std::vector<Scalar> stops = {0.0, 0.5, 0.5, 1.0};
551 {0, 0}, {500, 500}, std::move(colors), std::move(stops), tile_mode, {});
553 paint.
color = Color(1.0, 1.0, 1.0, 1.0);
554 canvas.
DrawRect({0, 0, 500, 500}, paint);
565 void CanRenderLinearGradientManyColors(
AiksTest* aiks_test,
568 canvas.
Scale(aiks_test->GetContentScale());
572 std::vector<Color> colors = {
573 Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
574 Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
575 Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
576 Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
577 Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
578 Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
579 Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
580 std::vector<Scalar> stops = {
591 {0, 0}, {200, 200}, std::move(colors), std::move(stops), tile_mode, {});
593 paint.
color = Color(1.0, 1.0, 1.0, 1.0);
594 canvas.
DrawRect({0, 0, 600, 600}, paint);
614 void CanRenderLinearGradientWayManyColors(
AiksTest* aiks_test,
619 auto color = Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0};
620 std::vector<Color> colors;
621 std::vector<Scalar> stops;
622 auto current_stop = 0.0;
623 for (
int i = 0; i < 2000; i++) {
624 colors.push_back(color);
625 stops.push_back(current_stop);
626 current_stop += 1 / 2000.0;
628 stops[2000 - 1] = 1.0;
631 {0, 0}, {200, 200}, std::move(colors), std::move(stops), tile_mode, {});
633 canvas.
DrawRect({0, 0, 600, 600}, paint);
644 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
645 const char* tile_mode_names[] = {
"Clamp",
"Repeat",
"Mirror",
"Decal"};
650 static int selected_tile_mode = 0;
651 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
652 ImGui::Combo(
"Tile mode", &selected_tile_mode, tile_mode_names,
653 sizeof(tile_mode_names) /
sizeof(
char*));
660 std::string label =
"##1";
661 for (
int i = 0; i < 4; i++) {
662 ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, &(matrix.
vec[i]),
663 4, NULL, NULL,
"%.2f", 0);
671 auto tile_mode = tile_modes[selected_tile_mode];
673 std::vector<Color> colors = {
674 Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
675 Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
676 Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
677 Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
678 Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
679 Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
680 Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
681 std::vector<Scalar> stops = {
682 0.0, 2.0 / 62.0, 4.0 / 62.0, 8.0 / 62.0, 16.0 / 62.0, 32.0 / 62.0, 1.0,
686 {0, 0}, {200, 200}, std::move(colors), std::move(stops), tile_mode, {});
688 canvas.
DrawRect({0, 0, 600, 600}, paint);
691 ASSERT_TRUE(OpenPlaygroundHere(callback));
700 {200, 200}, {400, 400},
704 {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0},
706 .mask_blur_descriptor =
720 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
721 const char* tile_mode_names[] = {
"Clamp",
"Repeat",
"Mirror",
"Decal"};
726 static int selected_tile_mode = 0;
727 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
728 ImGui::Combo(
"Tile mode", &selected_tile_mode, tile_mode_names,
729 sizeof(tile_mode_names) /
sizeof(
char*));
736 std::string label =
"##1";
737 for (
int i = 0; i < 4; i++) {
738 ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, &(matrix.
vec[i]),
739 4, NULL, NULL,
"%.2f", 0);
747 auto tile_mode = tile_modes[selected_tile_mode];
749 std::vector<Color> colors = {
Color{0.9568, 0.2627, 0.2118, 1.0},
750 Color{0.1294, 0.5882, 0.9529, 1.0}};
751 std::vector<Scalar> stops = {0.0, 1.0};
754 {100, 100}, 100, std::move(colors), std::move(stops), tile_mode, {});
756 canvas.
DrawRect({0, 0, 600, 600}, paint);
759 ASSERT_TRUE(OpenPlaygroundHere(callback));
763 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
764 const char* tile_mode_names[] = {
"Clamp",
"Repeat",
"Mirror",
"Decal"};
769 static int selected_tile_mode = 0;
770 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
771 ImGui::Combo(
"Tile mode", &selected_tile_mode, tile_mode_names,
772 sizeof(tile_mode_names) /
sizeof(
char*));
779 std::string label =
"##1";
780 for (
int i = 0; i < 4; i++) {
781 ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, &(matrix.
vec[i]),
782 4, NULL, NULL,
"%.2f", 0);
790 auto tile_mode = tile_modes[selected_tile_mode];
792 std::vector<Color> colors = {
793 Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
794 Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
795 Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
796 Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
797 Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
798 Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
799 Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
800 std::vector<Scalar> stops = {
811 {100, 100}, 100, std::move(colors), std::move(stops), tile_mode, {});
813 canvas.
DrawRect({0, 0, 600, 600}, paint);
816 ASSERT_TRUE(OpenPlaygroundHere(callback));
822 canvas.
Scale(aiks_test->GetContentScale());
826 std::vector<Color> colors = {Color{0.9568, 0.2627, 0.2118, 1.0},
827 Color{0.1294, 0.5882, 0.9529, 1.0}};
828 std::vector<Scalar> stops = {0.0, 1.0};
831 {100, 100}, Degrees(45), Degrees(135), std::move(colors),
832 std::move(stops), tile_mode, {});
834 canvas.
DrawRect({0, 0, 600, 600}, paint);
853 void CanRenderSweepGradientManyColors(
AiksTest* aiks_test,
859 std::vector<Color> colors = {
860 Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
861 Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
862 Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
863 Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
864 Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
865 Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
866 Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
867 std::vector<Scalar> stops = {
878 {100, 100}, Degrees(45), Degrees(135), std::move(colors),
879 std::move(stops), tile_mode, {});
881 canvas.
DrawRect({0, 0, 600, 600}, paint);
904 canvas.
DrawRect({0, 0, size * 3, size * 3}, paint);
909 std::vector<Scalar> stops = {0.0, 1.f / 3.f, 2.f / 3.f, 1.0};
910 std::array<std::tuple<Point, float, Point, float>, 8> array{
911 std::make_tuple(
Point{size / 2.f, size / 2.f}, 0.f,
912 Point{size / 2.f, size / 2.f}, size / 2.f),
913 std::make_tuple(
Point{size / 2.f, size / 2.f}, size / 4.f,
914 Point{size / 2.f, size / 2.f}, size / 2.f),
915 std::make_tuple(
Point{size / 4.f, size / 4.f}, 0.f,
916 Point{size / 2.f, size / 2.f}, size / 2.f),
917 std::make_tuple(
Point{size / 4.f, size / 4.f}, size / 2.f,
918 Point{size / 2.f, size / 2.f}, 0),
919 std::make_tuple(
Point{size / 4.f, size / 4.f}, size / 4.f,
920 Point{size / 2.f, size / 2.f}, size / 2.f),
921 std::make_tuple(
Point{size / 4.f, size / 4.f}, size / 16.f,
922 Point{size / 2.f, size / 2.f}, size / 8.f),
923 std::make_tuple(
Point{size / 4.f, size / 4.f}, size / 8.f,
924 Point{size / 2.f, size / 2.f}, size / 16.f),
925 std::make_tuple(
Point{size / 8.f, size / 8.f}, size / 8.f,
926 Point{size / 2.f, size / 2.f}, size / 8.f),
928 for (
int i = 0; i < 8; i++) {
930 canvas.
Translate({(i % 3) * size, i / 3 * size, 0});
932 std::get<0>(array[i]), std::get<1>(array[i]), colors, stops,
935 canvas.
DrawRect({0, 0, size, size}, paint);
946 std::vector<Scalar> stops = {0.0, 1.f / 3.f, 2.f / 3.f, 1.0};
948 std::array<ColorSource, 3> color_sources = {
962 for (
int i = 0; i < 3; i++) {
976 std::vector<Color> colors = {
Color{0.9568, 0.2627, 0.2118, 1.0},
977 Color{0.1294, 0.5882, 0.9529, 1.0}};
978 std::vector<Scalar> stops = {
984 {0, 0}, {100, 100}, std::move(colors), std::move(stops),
989 canvas.
DrawRect({0, 0, 200, 200}, paint);
1002 paint.
color =
Color{0.9568, 0.2627, 0.2118, 1.0};
1003 recorder_canvas.
DrawRect({100.0, 100.0, 600, 600}, paint);
1004 paint.
color =
Color{0.1294, 0.5882, 0.9529, 1.0};
1005 recorder_canvas.
DrawRect({200.0, 200.0, 600, 600}, paint);
1012 auto image = picture.
ToImage(renderer,
ISize{1000, 1000});
1033 canvas.
DrawRect({100, 100, 400, 400}, paint);
1039 canvas.
DrawRect({200, 200, 200, 200}, paint);
1062 canvas.
DrawRect({000, 000, 100, 100}, red);
1063 canvas.
DrawRect({020, 020, 100, 100}, green);
1064 canvas.
DrawRect({040, 040, 100, 100}, blue);
1078 std::make_shared<Image>(CreateTextureForFixture(
"kalimba.jpg"));
1102 canvas.
DrawRect({000, 000, 100, 100}, red);
1103 canvas.
DrawRect({020, 020, 100, 100}, green);
1104 canvas.
DrawRect({040, 040, 100, 100}, blue);
1152 canvas.
DrawRect({0, 0, 100, 100}, red);
1153 canvas.
DrawRect({10, 10, 100, 100}, green);
1154 canvas.
DrawRect({20, 20, 100, 100}, blue);
1162 CanPerformSaveLayerWithBoundsAndLargerIntermediateIsNotAllocated) {
1179 canvas.
DrawRect({0, 0, 100, 100}, red);
1180 canvas.
DrawRect({10, 10, 100, 100}, green);
1181 canvas.
DrawRect({20, 20, 100, 100}, blue);
1227 std::make_shared<Image>(CreateTextureForFixture(
"boston.jpg")), {10, 10},
1245 builder.
MoveTo({50, 50});
1246 builder.
LineTo({50, 100});
1247 builder.
LineTo({100, 100});
1248 builder.
LineTo({100, 50});
1266 builder.
MoveTo({50, 50});
1267 builder.
LineTo({520, 120});
1268 builder.
LineTo({300, 310});
1269 builder.
LineTo({100, 50});
1283 auto mapping = flutter::testing::OpenFixtureAsMapping(fixture_name);
1287 auto data = SkData::MakeWithProc(
1288 mapping->GetMapping(), mapping->GetSize(),
1289 [](
const void* ptr,
void* context) {
1290 delete reinterpret_cast<fml::Mapping*>(context);
1305 const std::string& text,
1306 const std::string& font_fixture,
1309 canvas.
DrawRect({options.position.x - 50, options.position.y, 900, 10},
1321 SkFont sk_font(SkTypeface::MakeFromData(mapping), options.font_size);
1322 auto blob = SkTextBlob::MakeFromString(text.c_str(), sk_font);
1338 const std::string& text,
1339 const std::string& font_fixture,
1342 canvas.
DrawRect({options.position.x - 50, options.position.y, 900, 10},
1350 auto mapping = flutter::testing::OpenFixtureAsMapping(font_fixture.c_str());
1354 auto typeface_stb = std::make_shared<TypefaceSTB>(std::move(mapping));
1357 typeface_stb, Font::Metrics{.point_size = options.font_size}, text);
1369 GetContext(), canvas,
"the quick brown fox jumped over the lazy dog!.?",
1370 "Roboto-Regular.ttf"));
1378 GetContext(), canvas,
"the quick brown fox jumped over the lazy dog!.?",
1379 "Roboto-Regular.ttf"));
1381 SetTypographerContext(TypographerContextSTB::Make());
1386 std::array<Scalar, 20> phase_offsets;
1387 for (
Scalar& offset : phase_offsets) {
1388 auto rand = std::rand();
1389 offset = (
static_cast<float>(rand) /
static_cast<float>(RAND_MAX)) *
k2Pi;
1392 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
1393 static float font_size = 20;
1394 static float phase_variation = 0.2;
1395 static float speed = 0.5;
1396 static float magnitude = 100;
1397 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1398 ImGui::SliderFloat(
"Font size", &font_size, 5, 50);
1399 ImGui::SliderFloat(
"Phase variation", &phase_variation, 0, 1);
1400 ImGui::SliderFloat(
"Oscillation speed", &speed, 0, 2);
1401 ImGui::SliderFloat(
"Oscillation magnitude", &magnitude, 0, 300);
1405 canvas.
Scale(GetContentScale());
1407 for (
size_t i = 0; i < phase_offsets.size(); i++) {
1408 auto position =
Point(
1409 200 + magnitude * std::sin((-phase_offsets[i] * phase_variation +
1410 GetSecondsElapsed() * speed)),
1411 200 + i * font_size * 1.1
1414 GetContext(), canvas,
1415 "the quick brown fox jumped over "
1417 "Roboto-Regular.ttf",
1418 {.font_size = font_size, .position = position})) {
1419 return std::nullopt;
1425 ASSERT_TRUE(OpenPlaygroundHere(callback));
1433 GetContext(), canvas,
"the quick brown fox jumped over the lazy dog!.?",
1434 "HomemadeApple.ttf"));
1443 "😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊",
1445 "Apple Color Emoji.ttc"));
1447 "NotoColorEmoji.ttf"));
1457 "😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊",
1459 "Apple Color Emoji.ttc", { .alpha = 0.5 }
1461 "NotoColorEmoji.ttf", {.alpha = 0.5}
1475 canvas.
SaveLayer({.blend_mode = BlendMode::kClear});
1477 GetContext(), canvas,
"the quick brown fox jumped over the lazy dog!.?",
1478 "Roboto-Regular.ttf"));
1483 GetContext(), canvas,
"the quick brown fox jumped over the lazy dog!.?",
1484 "Roboto-Regular.ttf"));
1495 ASSERT_NE(mapping,
nullptr);
1498 SkFont sk_font(SkTypeface::MakeFromData(mapping), font_size);
1506 } text[] = {{
Point(0, 0),
"0F0F0F0"},
1507 {
Point(1, 2),
"789"},
1508 {
Point(1, 3),
"456"},
1509 {
Point(1, 4),
"123"},
1510 {
Point(0, 6),
"0F0F0F0"}};
1511 for (
auto& t : text) {
1513 canvas.
Translate(t.position *
Point(font_size * 2, font_size * 1.1));
1515 auto blob = SkTextBlob::MakeFromString(t.text, sk_font);
1516 ASSERT_NE(blob,
nullptr);
1528 canvas.
Scale(GetContentScale());
1536 GetContext(), canvas,
"the quick brown fox jumped over the lazy dog!.?",
1537 "Roboto-Regular.ttf"));
1545 canvas.
DrawPaint({.color = Color::MediumTurquoise()});
1552 canvas.
DrawPaint({.color = Color::MediumTurquoise()});
1553 canvas.
DrawPaint({.color = Color::Color::OrangeRed().WithAlpha(0.5)});
1560 canvas.
DrawPaint({.color = Color::MediumTurquoise()});
1561 canvas.
DrawPaint({.color = Color::Color::OrangeRed().WithAlpha(0.5),
1562 .blend_mode = BlendMode::kHue});
1568 .
color = Color::Black(),
1569 .mask_blur_descriptor =
1571 .
style = FilterContents::BlurStyle::kNormal,
1577 canvas.
DrawPaint({.color = Color::White()});
1578 canvas.
DrawCircle({300, 300}, 200, filtered);
1579 canvas.
DrawPaint({.color = Color::Green(), .blend_mode = BlendMode::kScreen});
1584 std::vector<Color> colors = {
Color{0.9568, 0.2627, 0.2118, 1.0},
1585 Color{0.1294, 0.5882, 0.9529, 1.0}};
1586 std::vector<Scalar> stops = {0.0, 1.0};
1590 {0, 0}, {100, 100}, std::move(colors), std::move(stops),
1591 Entity::TileMode::kRepeat, Matrix::MakeScale(
Vector3(0.3, 0.3, 0.3))),
1592 .blend_mode = BlendMode::kLighten,
1596 canvas.
DrawPaint({.color = Color::Blue()});
1598 canvas.
ClipRect(Rect::MakeLTRB(0, 0, 200, 200));
1603 #define BLEND_MODE_TUPLE(blend_mode) {#blend_mode, BlendMode::k##blend_mode},
1611 std::vector<const char*> blend_mode_names;
1612 std::vector<BlendMode> blend_mode_values;
1614 const std::vector<std::tuple<const char*, BlendMode>> blends = {
1616 assert(blends.size() ==
1617 static_cast<size_t>(Entity::kLastAdvancedBlendMode) + 1);
1618 for (
const auto& [name, mode] : blends) {
1619 blend_mode_names.push_back(name);
1620 blend_mode_values.push_back(mode);
1624 return {blend_mode_names, blend_mode_values};
1630 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
1631 static Color background = Color::MediumTurquoise();
1632 static Color foreground = Color::Color::OrangeRed().
WithAlpha(0.5);
1633 static int current_blend_index = 3;
1635 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1637 ImGui::ColorEdit4(
"Background",
reinterpret_cast<float*
>(&background));
1638 ImGui::ColorEdit4(
"Foreground",
reinterpret_cast<float*
>(&foreground));
1639 ImGui::ListBox(
"Blend mode", ¤t_blend_index,
1640 modes.blend_mode_names.data(),
1641 modes.blend_mode_names.size());
1647 canvas.
DrawPaint({.color = background});
1649 {.color = foreground,
1650 .blend_mode =
static_cast<BlendMode>(current_blend_index)});
1653 ASSERT_TRUE(OpenPlaygroundHere(callback));
1666 paint.
color = Color::Red();
1668 paint.
color = Color::Green();
1670 paint.
color = Color::Blue();
1680 auto draw_color_wheel = [](
Canvas& canvas) {
1683 auto color_wheel_sampler = [](
Radians r) {
1687 auto color_cycle = [](
Scalar x) {
1688 Scalar cycle = std::fmod(x, 6.0f);
1689 return std::max(0.0f, std::min(1.0f, 2 - std::abs(2 - cycle)));
1691 return Color(color_cycle(6 * x + 1),
1692 color_cycle(6 * x - 1),
1693 color_cycle(6 * x - 3),
1702 const int max_dist = 900;
1703 for (
int i = 0; i <= 900; i++) {
1706 Scalar normalized_distance =
static_cast<Scalar>(i) / max_dist;
1709 color_wheel_sampler(r).
WithAlpha(1.0f - normalized_distance);
1711 -distance * std::cos(r.
radians));
1713 canvas.
DrawCircle(position, 9 + normalized_distance * 3, paint);
1717 std::shared_ptr<Image> color_wheel_image;
1718 Matrix color_wheel_transform;
1720 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
1722 static bool cache_the_wheel =
true;
1723 static int current_blend_index = 3;
1724 static float dst_alpha = 1;
1725 static float src_alpha = 1;
1726 static Color color0 = Color::Red();
1727 static Color color1 = Color::Green();
1728 static Color color2 = Color::Blue();
1730 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1732 ImGui::Checkbox(
"Cache the wheel", &cache_the_wheel);
1733 ImGui::ListBox(
"Blending mode", ¤t_blend_index,
1736 ImGui::SliderFloat(
"Source alpha", &src_alpha, 0, 1);
1737 ImGui::ColorEdit4(
"Color A",
reinterpret_cast<float*
>(&color0));
1738 ImGui::ColorEdit4(
"Color B",
reinterpret_cast<float*
>(&color1));
1739 ImGui::ColorEdit4(
"Color C",
reinterpret_cast<float*
>(&color2));
1740 ImGui::SliderFloat(
"Destination alpha", &dst_alpha, 0, 1);
1744 static Point content_scale;
1745 Point new_content_scale = GetContentScale();
1747 if (!cache_the_wheel || new_content_scale != content_scale) {
1748 content_scale = new_content_scale;
1753 canvas.
Scale(content_scale);
1758 draw_color_wheel(canvas);
1760 auto snapshot = color_wheel_picture.
Snapshot(renderer);
1761 if (!snapshot.has_value() || !snapshot->texture) {
1762 return std::nullopt;
1764 color_wheel_image = std::make_shared<Image>(snapshot->texture);
1765 color_wheel_transform = snapshot->transform;
1771 canvas.
SaveLayer({.color = Color::White().WithAlpha(dst_alpha),
1772 .blend_mode = BlendMode::kSource});
1774 canvas.
DrawPaint({.color = Color::White()});
1777 canvas.
Transform(color_wheel_transform);
1783 canvas.
Scale(content_scale);
1789 {.color = Color::White().WithAlpha(src_alpha),
1796 paint.
color = color0;
1798 paint.
color = color1;
1800 paint.
color = color2;
1808 ASSERT_TRUE(OpenPlaygroundHere(callback));
1852 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
1854 static float scale = 3;
1855 static bool add_circle_clip =
true;
1857 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1858 ImGui::ColorEdit4(
"Color",
reinterpret_cast<float*
>(&color));
1859 ImGui::SliderFloat(
"Scale", &scale, 0, 6);
1860 ImGui::Checkbox(
"Circle clip", &add_circle_clip);
1864 canvas.
Scale(GetContentScale());
1867 paint.
color = Color::White();
1870 paint.
color = color;
1871 paint.
style = Paint::Style::kStroke;
1876 .QuadraticCurveTo({60, 20}, {60, 60})
1879 .QuadraticCurveTo({60, 60}, {20, 60})
1884 if (add_circle_clip) {
1886 Point(60, 300),
Point(600, 300), 20, Color::Red(), Color::Red());
1889 Point point_a = screen_to_canvas * handle_a * GetContentScale();
1890 Point point_b = screen_to_canvas * handle_b * GetContentScale();
1892 Point middle = (point_a + point_b) / 2;
1897 for (
auto join : {Join::kBevel, Join::kRound, Join::kMiter}) {
1899 for (
auto cap : {Cap::kButt, Cap::kSquare, Cap::kRound}) {
1910 ASSERT_TRUE(OpenPlaygroundHere(callback));
1915 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
1916 static float scale = 3;
1917 static bool add_circle_clip =
true;
1918 const char* tile_mode_names[] = {
"Clamp",
"Repeat",
"Mirror",
"Decal"};
1920 Entity::TileMode::kClamp, Entity::TileMode::kRepeat,
1921 Entity::TileMode::kMirror, Entity::TileMode::kDecal};
1922 static int selected_tile_mode = 0;
1923 static float alpha = 1;
1925 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1926 ImGui::SliderFloat(
"Scale", &scale, 0, 6);
1927 ImGui::Checkbox(
"Circle clip", &add_circle_clip);
1928 ImGui::SliderFloat(
"Alpha", &alpha, 0, 1);
1929 ImGui::Combo(
"Tile mode", &selected_tile_mode, tile_mode_names,
1930 sizeof(tile_mode_names) /
sizeof(
char*));
1934 canvas.
Scale(GetContentScale());
1936 paint.
color = Color::White();
1939 paint.
style = Paint::Style::kStroke;
1942 auto tile_mode = tile_modes[selected_tile_mode];
1944 std::vector<Color> colors = {
Color{0.9568, 0.2627, 0.2118, 1.0},
1945 Color{0.1294, 0.5882, 0.9529, 1.0}};
1946 std::vector<Scalar> stops = {0.0, 1.0};
1949 {0, 0}, {50, 50}, std::move(colors), std::move(stops), tile_mode, {});
1953 .QuadraticCurveTo({60, 20}, {60, 60})
1956 .QuadraticCurveTo({60, 60}, {20, 60})
1961 if (add_circle_clip) {
1963 Point(60, 300),
Point(600, 300), 20, Color::Red(), Color::Red());
1966 Point point_a = screen_to_canvas * handle_a * GetContentScale();
1967 Point point_b = screen_to_canvas * handle_b * GetContentScale();
1969 Point middle = (point_a + point_b) / 2;
1974 for (
auto join : {Join::kBevel, Join::kRound, Join::kMiter}) {
1976 for (
auto cap : {Cap::kButt, Cap::kSquare, Cap::kRound}) {
1987 ASSERT_TRUE(OpenPlaygroundHere(callback));
1991 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
1993 canvas.
Scale(GetContentScale());
1998 auto current =
Point{25, 25};
1999 const auto offset =
Point{25, 25};
2000 const auto size =
Size(100, 100);
2003 Color::White(), Color::White());
2004 auto bounds = Rect::MakeLTRB(b0.x, b0.y, b1.x, b1.y);
2007 .stroke_width = 5.0f,
2008 .style = Paint::Style::kStroke});
2021 ASSERT_TRUE(OpenPlaygroundHere(callback));
2027 paint.
color = Color::Red();
2028 paint.
style = Paint::Style::kStroke;
2044 paint.
color = Color::Black();
2045 Rect rect(25, 25, 25, 25);
2051 paint.
color = Color::Green();
2057 paint.
color = Color::Red();
2066 Rect rect(0, 0, 1000, 1000);
2070 canvas.
SaveLayer({}, Rect::MakeXYWH(25, 25, 25, 25));
2071 paint.
color = Color::Black();
2077 canvas.
SaveLayer({}, Rect::MakeXYWH(35, 35, 25, 25));
2078 paint.
color = Color::Green();
2084 canvas.
SaveLayer({}, Rect::MakeXYWH(45, 45, 25, 25));
2085 paint.
color = Color::Red();
2096 canvas.
DrawPaint({.color = Color::White()});
2103 canvas.
SaveLayer({}, Rect::MakeXYWH(50, 50, 100, 100));
2106 canvas.
DrawRect(Rect::MakeSize(
Size{400, 400}), {.color = Color::White()});
2113 Rect::MakeSize(
Size{400, 400}),
2114 {.color = Color::Green(), .blend_mode = BlendMode::kHardLight});
2122 canvas.
Scale(GetContentScale());
2125 auto texture = std::make_shared<Image>(CreateTextureForFixture(
"boston.jpg"));
2126 auto draw_image_layer = [&canvas, &texture](
const Paint& paint) {
2134 .
style = FilterContents::BlurStyle::kNormal,
2137 draw_image_layer(effect_paint);
2141 draw_image_layer(effect_paint);
2146 #if IMPELLER_ENABLE_3D
2150 flutter::testing::OpenFixtureAsMapping(
"flutter_logo_baked.glb.ipscene");
2151 ASSERT_NE(mapping,
nullptr);
2153 std::shared_ptr<scene::Node> gltf_scene = scene::Node::MakeFromFlatbuffer(
2154 *mapping, *GetContext()->GetResourceAllocator());
2155 ASSERT_NE(gltf_scene,
nullptr);
2157 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
2160 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
2161 static Scalar distance = 2;
2162 ImGui::SliderFloat(
"Distance", &distance, 0, 4);
2164 ImGui::SliderFloat(
"Y", &y_pos, -3, 3);
2166 ImGui::SliderFloat(
"FOV", &fov, 1, 180);
2169 Scalar angle = GetSecondsElapsed();
2170 auto camera_position =
2171 Vector3(distance * std::sin(angle), y_pos, -distance * std::cos(angle));
2175 Matrix::MakePerspective(
Degrees(fov), GetWindowSize(), 0.1, 1000) *
2176 Matrix::MakeLookAt(camera_position, {0, 0, 0}, {0, 1, 0}));
2179 canvas.
DrawPaint(Paint{.color = Color::MakeRGBA8(0xf9, 0xf9, 0xf9, 0xff)});
2180 canvas.Scale(GetContentScale());
2181 canvas.DrawPaint(paint);
2182 return canvas.EndRecordingAsPicture();
2185 ASSERT_TRUE(OpenPlaygroundHere(callback));
2187 #endif // IMPELLER_ENABLE_3D
2197 ColorFilter::MakeBlend(BlendMode::kSourceOver, Color::Blue());
2202 FilterContents::BlurStyle::kNormal,
2203 Entity::TileMode::kClamp);
2217 auto entity_pass = std::make_shared<EntityPass>();
2218 auto rect = Rect::MakeLTRB(0, 0, 100, 100);
2222 ColorFilter::MakeBlend(BlendMode::kSourceOver, Color::Blue());
2225 auto delegate = std::make_shared<OpacityPeepholePassDelegate>(paint);
2226 ASSERT_FALSE(delegate->CanCollapseIntoParentPass(entity_pass.get()));
2230 FilterContents::BlurStyle::kNormal,
2231 Entity::TileMode::kClamp);
2234 delegate = std::make_shared<OpacityPeepholePassDelegate>(paint);
2235 ASSERT_FALSE(delegate->CanCollapseIntoParentPass(entity_pass.get()));
2238 paint.
color = Color::Red();
2241 delegate = std::make_shared<OpacityPeepholePassDelegate>(paint);
2242 ASSERT_FALSE(delegate->CanCollapseIntoParentPass(entity_pass.get()));
2248 entity_pass->AddEntity(entity);
2251 delegate = std::make_shared<OpacityPeepholePassDelegate>(paint);
2252 ASSERT_TRUE(delegate->CanCollapseIntoParentPass(entity_pass.get()));
2257 canvas.
DrawPaint({.color = Color::Red(), .blend_mode = BlendMode::kSource});
2258 canvas.
DrawPaint({.color = Color::CornflowerBlue().WithAlpha(0.75),
2259 .blend_mode = BlendMode::kSourceOver});
2262 auto expected = Color::Red().Blend(Color::CornflowerBlue().WithAlpha(0.75),
2263 BlendMode::kSourceOver);
2264 ASSERT_EQ(picture.
pass->GetClearColor(), expected);
2266 std::shared_ptr<ContextSpy> spy = ContextSpy::Make();
2267 std::shared_ptr<Context> real_context = GetContext();
2268 std::shared_ptr<ContextMock> mock_context = spy->MakeContext(real_context);
2270 std::shared_ptr<Image> image = picture.
ToImage(renderer, {300, 300});
2272 ASSERT_EQ(spy->render_passes_.size(), 1llu);
2273 std::shared_ptr<RenderPass> render_pass = spy->render_passes_[0];
2274 ASSERT_EQ(render_pass->GetCommands().size(), 0llu);
2280 ParentSaveLayerCreatesRenderPassWhenChildBackdropFilterIsPresent) {
2282 canvas.
SaveLayer({}, std::nullopt, ImageFilter::MakeMatrix(
Matrix(), {}));
2283 canvas.
DrawPaint({.color = Color::Red(), .blend_mode = BlendMode::kSource});
2284 canvas.
DrawPaint({.color = Color::CornflowerBlue().WithAlpha(0.75),
2285 .blend_mode = BlendMode::kSourceOver});
2290 std::shared_ptr<ContextSpy> spy = ContextSpy::Make();
2291 std::shared_ptr<Context> real_context = GetContext();
2292 std::shared_ptr<ContextMock> mock_context = spy->MakeContext(real_context);
2294 std::shared_ptr<Image> image = picture.
ToImage(renderer, {300, 300});
2296 ASSERT_EQ(spy->render_passes_.size(), 3llu);
2297 std::shared_ptr<RenderPass> render_pass = spy->render_passes_[0];
2298 ASSERT_EQ(render_pass->GetCommands().size(), 0llu);
2304 {.color = Color::Red(), .blend_mode = BlendMode::kSource});
2306 {.color = Color::CornflowerBlue().WithAlpha(0.75),
2307 .blend_mode = BlendMode::kSourceOver});
2309 std::shared_ptr<ContextSpy> spy = ContextSpy::Make();
2311 std::shared_ptr<Context> real_context = GetContext();
2312 std::shared_ptr<ContextMock> mock_context = spy->MakeContext(real_context);
2314 std::shared_ptr<Image> image = picture.
ToImage(renderer, {300, 300});
2316 ASSERT_EQ(spy->render_passes_.size(), 1llu);
2317 std::shared_ptr<RenderPass> render_pass = spy->render_passes_[0];
2318 ASSERT_EQ(render_pass->GetCommands().size(), 0llu);
2324 {.color = Color::Red(), .blend_mode = BlendMode::kSource});
2326 {.color = Color::CornflowerBlue().WithAlpha(0.75),
2327 .blend_mode = BlendMode::kSourceOver});
2329 std::shared_ptr<ContextSpy> spy = ContextSpy::Make();
2331 std::shared_ptr<Context> real_context = GetContext();
2332 std::shared_ptr<ContextMock> mock_context = spy->MakeContext(real_context);
2334 std::shared_ptr<Image> image = picture.
ToImage(renderer, {300, 300});
2336 ASSERT_EQ(spy->render_passes_.size(), 1llu);
2337 std::shared_ptr<RenderPass> render_pass = spy->render_passes_[0];
2338 ASSERT_EQ(render_pass->GetCommands().size(), 2llu);
2347 {.color = Color::Red(), .blend_mode = BlendMode::kSource});
2349 std::shared_ptr<ContextSpy> spy = ContextSpy::Make();
2351 std::shared_ptr<Context> real_context = GetContext();
2352 std::shared_ptr<ContextMock> mock_context = spy->MakeContext(real_context);
2354 std::shared_ptr<Image> image = picture.
ToImage(renderer, {300, 300});
2356 ASSERT_EQ(spy->render_passes_.size(), 1llu);
2357 std::shared_ptr<RenderPass> render_pass = spy->render_passes_[0];
2358 ASSERT_EQ(render_pass->GetCommands().size(), 1llu);
2364 {.color = Color::Red(), .blend_mode = BlendMode::kSource});
2366 {.color = Color::CornflowerBlue().WithAlpha(0.75),
2367 .blend_mode = BlendMode::kSourceOver});
2369 std::shared_ptr<ContextSpy> spy = ContextSpy::Make();
2371 std::shared_ptr<Context> real_context = GetContext();
2372 std::shared_ptr<ContextMock> mock_context = spy->MakeContext(real_context);
2374 std::shared_ptr<Image> image = picture.
ToImage(renderer, {301, 301});
2376 ASSERT_EQ(spy->render_passes_.size(), 1llu);
2377 std::shared_ptr<RenderPass> render_pass = spy->render_passes_[0];
2378 ASSERT_EQ(render_pass->GetCommands().size(), 2llu);
2385 canvas.
DrawPaint({.color = Color::Red(), .blend_mode = BlendMode::kSource});
2386 canvas.
DrawPaint({.color = Color::CornflowerBlue().WithAlpha(0.75),
2387 .blend_mode = BlendMode::kSourceOver});
2390 auto expected = Color::Red().Blend(Color::CornflowerBlue().WithAlpha(0.75),
2391 BlendMode::kSourceOver);
2392 ASSERT_EQ(picture.
pass->GetClearColor(), expected);
2394 std::shared_ptr<ContextSpy> spy = ContextSpy::Make();
2395 std::shared_ptr<Context> real_context = GetContext();
2396 std::shared_ptr<ContextMock> mock_context = spy->MakeContext(real_context);
2398 std::shared_ptr<Image> image = picture.
ToImage(renderer, {300, 300});
2400 ASSERT_EQ(spy->render_passes_.size(), 1llu);
2401 std::shared_ptr<RenderPass> render_pass = spy->render_passes_[0];
2402 ASSERT_EQ(render_pass->GetCommands().size(), 0llu);
2409 FilterContents::BlurStyle::kNormal,
2410 Entity::TileMode::kClamp));
2411 canvas.
DrawPaint({.color = Color::Red(), .blend_mode = BlendMode::kSource});
2412 canvas.
DrawPaint({.color = Color::CornflowerBlue().WithAlpha(0.75),
2413 .blend_mode = BlendMode::kSourceOver});
2418 std::optional<Color> actual_color;
2419 bool found_subpass =
false;
2421 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
2422 actual_color = subpass->get()->GetClearColor();
2423 found_subpass =
true;
2429 EXPECT_TRUE(found_subpass);
2430 EXPECT_FALSE(actual_color.has_value());
2436 {.color = Color::Yellow(), .blend_mode = BlendMode::kSource});
2437 canvas.
SaveLayer({.blend_mode = BlendMode::kMultiply});
2438 canvas.
DrawPaint({.color = Color::CornflowerBlue().WithAlpha(0.75),
2439 .blend_mode = BlendMode::kSourceOver});
2448 {.color = Color::Yellow(), .blend_mode = BlendMode::kSource});
2450 ImageFilter::MakeBlur(
Sigma(20.0),
Sigma(20.0),
2451 FilterContents::BlurStyle::kNormal,
2452 Entity::TileMode::kDecal));
2454 {.color = Color::CornflowerBlue(), .blend_mode = BlendMode::kSourceOver});
2464 ColorFilter::MakeBlend(BlendMode::kColorDodge, Color::Red()),
2469 canvas.
DrawRect({100, 100, 200, 200}, {.color = Color::Blue()});
2479 ColorFilter::MakeMatrix({.array =
2484 1.0, 1.0, 1.0, 1.0, 0
2490 canvas.
DrawRect({100, 100, 200, 200}, {.color = Color::Blue()});
2499 .color_filter = ColorFilter::MakeLinearToSrgb(),
2504 canvas.
DrawRect({100, 100, 200, 200}, {.color = Color::Blue()});
2513 .color_filter = ColorFilter::MakeSrgbToLinear(),
2518 canvas.
DrawRect({100, 100, 200, 200}, {.color = Color::Blue()});
2524 const std::shared_ptr<Image>& src_image,
2525 const std::shared_ptr<Image>& dst_image) {
2526 Color destination_color = Color::CornflowerBlue().
WithAlpha(0.75);
2527 auto source_colors = std::vector<Color>({Color::White().WithAlpha(0.75),
2528 Color::LimeGreen().WithAlpha(0.75),
2529 Color::Black().WithAlpha(0.75)});
2533 canvas.
DrawPaint({.color = Color::Black()});
2540 for (
const auto& color : source_colors) {
2543 canvas.ClipRect(Rect::MakeXYWH(50, 50, 100, 100));
2547 canvas.SaveLayer({});
2549 canvas.DrawPaint({.color = destination_color});
2552 canvas.SaveLayer({.blend_mode = blend_mode});
2554 canvas.DrawRect({50, 50, 100, 100}, {.color = color});
2561 canvas.Translate(
Vector2(100, 0));
2563 canvas.RestoreToCount(0);
2570 canvas.Translate({0, 100});
2574 canvas.SaveLayer({});
2576 for (
const auto& color : source_colors) {
2578 canvas.DrawRect({50, 50, 100, 100},
2579 {.color = destination_color.
Blend(color, blend_mode),
2580 .blend_mode = BlendMode::kSourceOver});
2581 canvas.Translate(
Vector2(100, 0));
2583 canvas.RestoreToCount(0);
2594 canvas.SaveLayer({.blend_mode = BlendMode::kSourceOver});
2596 canvas.DrawImage(dst_image, {400, 50}, {.blend_mode = BlendMode::kSource});
2597 canvas.DrawImage(src_image, {400, 50}, {.blend_mode = blend_mode});
2599 canvas.RestoreToCount(0);
2601 return canvas.EndRecordingAsPicture();
2604 #define BLEND_MODE_TEST(blend_mode) \
2605 TEST_P(AiksTest, BlendMode##blend_mode) { \
2606 auto src_image = std::make_shared<Image>( \
2607 CreateTextureForFixture("blend_mode_src.png")); \
2608 auto dst_image = std::make_shared<Image>( \
2609 CreateTextureForFixture("blend_mode_dst.png")); \
2610 OpenPlaygroundHere( \
2611 BlendModeTest(BlendMode::k##blend_mode, src_image, dst_image)); \
2618 canvas.
DrawRect(Rect::MakeXYWH(100, 100, 300, 300), {.color = Color::Blue()});
2620 canvas.
SaveLayer({.color = Color::Black().WithAlpha(0.5)});
2621 canvas.
DrawRect(Rect::MakeXYWH(100, 500, 300, 300), {.color = Color::Blue()});
2630 canvas.
DrawRect(Rect::MakeXYWH(100, 100, 300, 300), {.color = Color::Blue()});
2633 .color = Color::Black().WithAlpha(0.5),
2635 ColorFilter::MakeBlend(BlendMode::kDestinationOver, Color::Red()),
2637 canvas.
DrawRect(Rect::MakeXYWH(100, 500, 300, 300), {.color = Color::Blue()});
2646 canvas.
DrawRect(Rect::MakeXYWH(100, 100, 300, 300), {.color = Color::Blue()});
2649 .color = Color::Black().WithAlpha(0.5),
2650 .image_filter = ImageFilter::MakeFromColorFilter(
2651 *ColorFilter::MakeBlend(BlendMode::kDestinationOver, Color::Red())),
2654 canvas.
DrawRect(Rect::MakeXYWH(100, 500, 300, 300), {.color = Color::Blue()});
2663 canvas.
DrawRect(Rect::MakeXYWH(100, 100, 300, 300), {.color = Color::Blue()});
2666 .color = Color::Black().WithAlpha(0.5),
2668 ColorFilter::MakeBlend(BlendMode::kDestinationOver, Color::Red()),
2671 canvas.
DrawRect(Rect::MakeXYWH(100, 500, 300, 300), {.color = Color::Blue()});
2680 auto image = std::make_shared<Image>(CreateTextureForFixture(
"airplane.jpg"));
2681 canvas.
DrawImage(image, {100, 100}, {});
2683 canvas.
SaveLayer({.color = Color::Black().WithAlpha(0.5)});
2684 canvas.
DrawImage(image, {100, 500}, {});
2693 auto image = std::make_shared<Image>(CreateTextureForFixture(
"airplane.jpg"));
2694 canvas.
DrawImage(image, {100, 100}, {});
2697 .color = Color::Black().WithAlpha(0.5),
2698 .color_filter = ColorFilter::MakeMatrix({.array =
2706 canvas.
DrawImage(image, {100, 500}, {});
2715 auto image = std::make_shared<Image>(CreateTextureForFixture(
"airplane.jpg"));
2716 canvas.
DrawImage(image, {100, 100}, {});
2719 .color = Color::Black().WithAlpha(0.5),
2720 .image_filter = ImageFilter::MakeFromColorFilter(
2721 *ColorFilter::MakeMatrix({.array =
2729 canvas.
DrawImage(image, {100, 500}, {});
2736 TranslucentSaveLayerWithColorFilterAndImageFilterDrawsCorrectly) {
2739 auto image = std::make_shared<Image>(CreateTextureForFixture(
"airplane.jpg"));
2740 canvas.
DrawImage(image, {100, 100}, {});
2743 .color = Color::Black().WithAlpha(0.5),
2744 .image_filter = ImageFilter::MakeFromColorFilter(
2745 *ColorFilter::MakeMatrix({.array =
2753 ColorFilter::MakeBlend(BlendMode::kModulate, Color::Green()),
2755 canvas.
DrawImage(image, {100, 500}, {});
2763 canvas.
DrawRect({0, 0, 400, 400}, {.color = Color::Red()});
2765 .color = Color::Black().WithAlpha(0.5),
2766 .blend_mode = BlendMode::kLighten,
2768 canvas.
DrawCircle({200, 200}, 100, {.color = Color::Green()});
2778 canvas.
DrawPaint({.color = Color::Red()});
2782 canvas.
DrawCircle({100, 100}, 0.1, {.color = Color::Yellow()});
2785 canvas.
DrawCircle({100, 100}, 0.1, {.color = Color::Yellow()});
2788 canvas.
DrawPaint({.color = Color::Green()});
2800 canvas.
DrawPaint({.color = Color::AntiqueWhite()});
2802 {.color = Color::CornflowerBlue().WithAlpha(0.75)});
2804 canvas.
SaveLayer({.blend_mode = BlendMode::kMultiply});
2807 {.color = Color::DarkBlue().WithAlpha(0.75)});
2809 {.color = Color::LightCoral().WithAlpha(0.75),
2810 .blend_mode = BlendMode::kLuminosity});
2822 .color = Color::CornflowerBlue(),
2823 .blend_mode = BlendMode::kSourceOver,
2829 std::shared_ptr<SolidColorContents> contents;
2830 picture.
pass->IterateAllEntities([&e = entity, &contents](
Entity& entity) {
2834 std::static_pointer_cast<SolidColorContents>(entity.
GetContents());
2840 ASSERT_TRUE(contents->IsOpaque());
2847 canvas.
DrawPaint({.color = Color::Red()});
2851 canvas.
SaveLayer({.blend_mode = BlendMode::kSource});
2852 canvas.
DrawCircle({300, 300}, 100, {.color = Color::Green()});
2861 {.color = Color::Green(),
2863 .
style = FilterContents::BlurStyle::kNormal,
2864 .sigma =
Sigma(99999),
2872 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
2874 Color::White(), Color::White());
2877 canvas.
DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
2878 canvas.
DrawCircle({300, 200}, 100, {.color = Color::GreenYellow()});
2879 canvas.
DrawCircle({140, 170}, 75, {.color = Color::DarkMagenta()});
2880 canvas.
DrawCircle({180, 120}, 100, {.color = Color::OrangeRed()});
2881 canvas.
ClipRRect(Rect::MakeLTRB(a.x, a.y, b.x, b.y), 20);
2882 canvas.
SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
2883 ImageFilter::MakeBlur(
Sigma(20.0),
Sigma(20.0),
2884 FilterContents::BlurStyle::kNormal,
2885 Entity::TileMode::kClamp));
2891 ASSERT_TRUE(OpenPlaygroundHere(callback));
2896 canvas.
DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
2897 canvas.
DrawCircle({300, 200}, 100, {.color = Color::GreenYellow()});
2898 canvas.
DrawCircle({140, 170}, 75, {.color = Color::DarkMagenta()});
2899 canvas.
DrawCircle({180, 120}, 100, {.color = Color::OrangeRed()});
2900 canvas.
ClipRRect(Rect::MakeLTRB(75, 50, 375, 275), 20);
2901 canvas.
SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
2902 ImageFilter::MakeBlur(
Sigma(30.0),
Sigma(30.0),
2903 FilterContents::BlurStyle::kNormal,
2904 Entity::TileMode::kClamp));
2912 canvas.
DrawCircle({400, 400}, 300, {.color = Color::Green()});
2913 canvas.
SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
2914 ImageFilter::MakeBlur(
Sigma(999999),
Sigma(999999),
2915 FilterContents::BlurStyle::kNormal,
2916 Entity::TileMode::kClamp));
2924 canvas.
ClipRect(Rect::MakeXYWH(100, 150, 400, 400));
2928 .color = Color::Green(),
2929 .image_filter = ImageFilter::MakeBlur(
2930 Sigma(20.0),
Sigma(20.0), FilterContents::BlurStyle::kNormal,
2931 Entity::TileMode::kClamp),
2942 canvas.
ClipRect(Rect::MakeXYWH(100, 150, 400, 400));
2945 .color = Color::White(),
2946 .color_filter = ColorFilter::MakeBlend(
2947 BlendMode::kSource, Color::Green()),
2948 .mask_blur_descriptor =
2950 .
style = FilterContents::BlurStyle::kNormal,
2963 canvas.
ClipRect(Rect::MakeXYWH(100, 150, 400, 400));
2966 .color = Color::Grey(),
2967 .color_filter = ColorFilter::MakeBlend(
2969 .mask_blur_descriptor =
2971 .
style = FilterContents::BlurStyle::kNormal,
2982 if (GetParam() != PlaygroundBackend::kMetal) {
2983 GTEST_SKIP_(
"This backend doesn't support runtime effects.");
2986 auto runtime_stage =
2987 OpenAssetAsRuntimeStage(
"runtime_stage_example.frag.iplr");
2988 ASSERT_TRUE(runtime_stage->IsDirty());
2990 struct FragUniforms {
2993 } frag_uniforms = {.iResolution =
Vector2(400, 400), .iTime = 100.0};
2994 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
2995 uniform_data->resize(
sizeof(FragUniforms));
2996 memcpy(uniform_data->data(), &frag_uniforms,
sizeof(FragUniforms));
2998 std::vector<RuntimeEffectContents::TextureInput> texture_inputs;
3002 runtime_stage, uniform_data, texture_inputs);
3007 Entity::ClipOperation::kIntersect);
3015 if (GetParam() != PlaygroundBackend::kMetal) {
3016 GTEST_SKIP_(
"This backend doesn't support runtime effects.");
3019 auto runtime_stage = OpenAssetAsRuntimeStage(
"gradient.frag.iplr");
3020 ASSERT_TRUE(runtime_stage->IsDirty());
3022 struct FragUniforms {
3024 } frag_uniforms = {.size = Size::MakeWH(400, 400)};
3025 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
3026 uniform_data->resize(
sizeof(FragUniforms));
3027 memcpy(uniform_data->data(), &frag_uniforms,
sizeof(FragUniforms));
3029 std::vector<RuntimeEffectContents::TextureInput> texture_inputs;
3033 runtime_stage, uniform_data, texture_inputs);
3037 canvas.
Scale(GetContentScale());
3045 std::vector<Point> points = {
3054 std::vector<PointStyle> caps = {
3056 PointStyle::kSquare,
3062 background.
color = Color::Black();
3067 canvas.
DrawPoints(points, 10, paint, PointStyle::kRound);
3069 canvas.
DrawPoints(points, 10, paint, PointStyle::kSquare);
3077 auto atlas = CreateTextureForFixture(
"bay_bridge.jpg");
3078 auto size = atlas->GetSize();
3079 auto image = std::make_shared<Image>(atlas);
3081 Scalar half_width = size.width / 2;
3082 Scalar half_height = size.height / 2;
3083 std::vector<Rect> texture_coordinates = {
3084 Rect::MakeLTRB(0, 0, half_width, half_height),
3085 Rect::MakeLTRB(half_width, 0, size.width, half_height),
3086 Rect::MakeLTRB(0, half_height, half_width, size.height),
3087 Rect::MakeLTRB(half_width, half_height, size.width, size.height)};
3089 std::vector<Matrix> transforms = {
3090 Matrix::MakeTranslation({0, 0, 0}),
3091 Matrix::MakeTranslation({half_width, 0, 0}),
3092 Matrix::MakeTranslation({0, half_height, 0}),
3093 Matrix::MakeTranslation({half_width, half_height, 0})};
3094 std::vector<Color> colors = {Color::Red(), Color::Green(), Color::Blue(),
3100 canvas.
Scale({0.25, 0.25, 1.0});
3101 canvas.
DrawAtlas(image, transforms, texture_coordinates, colors,
3102 BlendMode::kModulate, {}, std::nullopt, paint);
3110 auto atlas = CreateTextureForFixture(
"bay_bridge.jpg");
3111 auto size = atlas->GetSize();
3112 auto image = std::make_shared<Image>(atlas);
3114 Scalar half_width = size.width / 2;
3115 Scalar half_height = size.height / 2;
3116 std::vector<Rect> texture_coordinates = {
3117 Rect::MakeLTRB(0, 0, half_width, half_height),
3118 Rect::MakeLTRB(half_width, 0, size.width, half_height),
3119 Rect::MakeLTRB(0, half_height, half_width, size.height),
3120 Rect::MakeLTRB(half_width, half_height, size.width, size.height)};
3122 std::vector<Matrix> transforms = {
3123 Matrix::MakeTranslation({0, 0, 0}),
3124 Matrix::MakeTranslation({half_width, 0, 0}),
3125 Matrix::MakeTranslation({0, half_height, 0}),
3126 Matrix::MakeTranslation({half_width, half_height, 0})};
3131 canvas.
Scale({0.25, 0.25, 1.0});
3132 canvas.
DrawAtlas(image, transforms, texture_coordinates, {},
3133 BlendMode::kModulate, {}, std::nullopt, paint);
3139 auto texture = CreateTextureForFixture(
"table_mountain_nx.png",
3142 std::vector<Point> points = {
3151 std::vector<PointStyle> caps = {
3153 PointStyle::kSquare,
3156 paint.
color_source = ColorSource::MakeImage(texture, Entity::TileMode::kClamp,
3157 Entity::TileMode::kClamp, {}, {});
3161 canvas.DrawPoints(points, 100, paint, PointStyle::kRound);
3162 canvas.Translate({150, 0});
3163 canvas.DrawPoints(points, 100, paint, PointStyle::kSquare);
3165 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
3173 ASSERT_NE(mapping,
nullptr);
3176 SkFont sk_font(SkTypeface::MakeFromData(mapping), font_size);
3179 text_paint.
color = Color::Blue();
3181 std::vector<Color> colors = {
Color{0.9568, 0.2627, 0.2118, 1.0},
3182 Color{0.1294, 0.5882, 0.9529, 1.0}};
3183 std::vector<Scalar> stops = {
3187 text_paint.
color_source = ColorSource::MakeLinearGradient(
3188 {0, 0}, {100, 100}, std::move(colors), std::move(stops),
3189 Entity::TileMode::kRepeat, {});
3195 auto blob = SkTextBlob::MakeFromString(
"Hello", sk_font);
3196 ASSERT_NE(blob,
nullptr);
3198 canvas.DrawTextFrame(frame,
Point(), text_paint);
3200 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
3205 subcanvas.
DrawRect(Rect::MakeLTRB(-100, -50, 100, 50),
3206 {.color = Color::CornflowerBlue()});
3220 Rect::MakeLTRB(-100, -50, 100, 50),
3221 {.color = Color::CornflowerBlue(), .blend_mode = BlendMode::kColorDodge});
3225 canvas.
DrawPaint({.color = Color::Black()});
3226 canvas.
DrawCircle(Point::MakeXY(150, 150), 25, {.color = Color::Red()});
3235 ImageFilter::MakeBlur(
Sigma(20.0),
Sigma(20.0),
3236 FilterContents::BlurStyle::kNormal,
3237 Entity::TileMode::kDecal));
3238 auto image = std::make_shared<Image>(CreateTextureForFixture(
"kalimba.jpg"));
3241 subcanvas.
DrawImage(image, Point::MakeXY(100.0, 100.0), paint);
3246 canvas.
DrawPaint({.color = Color::Black()});
3247 canvas.
DrawCircle(Point::MakeXY(150, 150), 25, {.color = Color::Red()});
3256 GetContext(), subcanvas,
3257 "the quick brown fox jumped over the lazy dog!.?",
"Roboto-Regular.ttf"));
3261 GetContext(), subcanvas,
3262 "the quick brown fox jumped over the very big lazy dog!.?",
3263 "Roboto-Regular.ttf"));
3276 GetContext(), canvas,
3277 "the quick brown fox jumped over the smaller lazy dog!.?",
3278 "Roboto-Regular.ttf"));
3284 subcanvas.
ClipRRect(Rect::MakeLTRB(100, 100, 400, 400), 15);
3285 subcanvas.
DrawPaint({.color = Color::Red()});
3289 canvas.
DrawPaint({.color = Color::CornflowerBlue()});
3296 canvas.
ClipRRect(Rect::MakeLTRB(100, 100, 400, 400).Expand(20), 15);
3297 canvas.
DrawPaint({.color = Color::Green()});
3304 canvas.
DrawPaint({.color = Color::Black()});
3308 {.color = Color::Green().WithAlpha(0.5),
3309 .blend_mode = BlendMode::kPlus});
3312 canvas.
SaveLayer({.image_filter = ImageFilter::MakeMatrix(
3313 Matrix::MakeTranslation(
Vector2(1, 1) *
3315 Matrix::MakeScale(
Vector2(1, 1) * 0.5) *
3316 Matrix::MakeTranslation(
Vector2(-200, -200)),
3320 {.color = Color::Green().WithAlpha(0.5),
3321 .blend_mode = BlendMode::kPlus});
3331 canvas.
DrawPaint({.color = Color::Black()});
3335 {.color = Color::Green().WithAlpha(0.5),
3336 .blend_mode = BlendMode::kPlus});
3341 ImageFilter::MakeMatrix(
3343 Matrix::MakeScale(
Vector2(1, 1) * 0.5) *
3344 Matrix::MakeTranslation(
Vector2(-100, -100)),
3355 contents.SetColor(Color::CornflowerBlue().WithAlpha(0.75));
3356 auto result = contents.ApplyColorFilter([](
const Color& color) {
3357 return color.
Blend(Color::LimeGreen().WithAlpha(0.75), BlendMode::kScreen);
3359 ASSERT_TRUE(result);
3361 Color(0.433247, 0.879523, 0.825324, 0.75));
3364 #define APPLY_COLOR_FILTER_GRADIENT_TEST(name) \
3365 TEST_P(AiksTest, name##GradientApplyColorFilter) { \
3366 auto contents = name##GradientContents(); \
3367 contents.SetColors({Color::CornflowerBlue().WithAlpha(0.75)}); \
3368 auto result = contents.ApplyColorFilter([](const Color& color) { \
3369 return color.Blend(Color::LimeGreen().WithAlpha(0.75), \
3370 BlendMode::kScreen); \
3372 ASSERT_TRUE(result); \
3374 std::vector<Color> expected = {Color(0.433247, 0.879523, 0.825324, 0.75)}; \
3375 ASSERT_COLORS_NEAR(contents.GetColors(), expected); \
3387 2.000000, 0.000000, 0.000000, 0.000000,
3388 1.445767, 2.637070, -0.507928, 0.001524,
3389 -2.451887, -0.534662, 0.861399, -0.002584,
3390 1063.481934, 1025.951416, -48.300270, 1.144901
3395 "Roboto-Regular.ttf"));
3406 2.000000, 0.000000, 0.000000, 0.000000,
3407 1.445767, 2.637070, -0.507928, 0.001524,
3408 -2.451887, -0.534662, 0.861399, -0.002584,
3409 1063.481934, 1025.951416, -48.300270, 1.144901
3414 "Roboto-Regular.ttf"));
3428 .color = Color::Green(),
3429 .blend_mode = BlendMode::kSourceOver,
3430 .image_filter = ImageFilter::MakeFromColorFilter(
3431 *ColorFilter::MakeBlend(BlendMode::kDestination,
3441 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
3448 .
style = FilterContents::BlurStyle::kNormal,
3449 .sigma =
Radius{120 * 3},
3451 paint.
color = Color::Red();
3453 builder.
AddRect(Rect::MakeLTRB(0, 0, 800, 800));
3454 canvas.
DrawPath(builder.TakePath(), paint);
3457 ASSERT_TRUE(OpenPlaygroundHere(callback));
3465 .
style = FilterContents::BlurStyle::kNormal,
3466 .sigma =
Radius{120 * 3},
3468 paint.
color = Color::Red();
3470 builder.
AddRect(Rect::MakeLTRB(0, 0, 800, 800));
3471 canvas.
DrawPath(builder.TakePath(), paint);
3476 auto capture_context = CaptureContext::MakeAllowlist({
"TestDocument"});
3478 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
3481 capture_context.Rewind();
3482 auto document = capture_context.GetDocument(
"TestDocument");
3484 auto color = document.AddColor(
"Background color", Color::CornflowerBlue());
3487 ImGui::Begin(
"TestDocument",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
3488 document.GetElement()->properties.Iterate([](
CaptureProperty& property) {
3489 property.Invoke({.color = [](CaptureColorProperty& p) {
3490 ImGui::ColorEdit4(p.label.c_str(),
reinterpret_cast<float*
>(&p.value));
3497 OpenPlaygroundHere(callback);
3501 ASSERT_FALSE(GetContext()->capture.IsActive());
3506 auto context = GetContext();
3507 std::weak_ptr<Texture> weak_texture;
3510 auto texture = CreateTextureForFixture(
"table_mountain_nx.png");
3513 canvas.
Scale(GetContentScale());
3518 texture, Entity::TileMode::kClamp, Entity::TileMode::kClamp, {}, {});
3519 canvas.
DrawRect({0, 0, 600, 600}, paint);
3529 context->Shutdown();
3532 ASSERT_TRUE(weak_texture.expired()) <<
"When the texture is no longer in use "
3533 "by the backend, it should be "
3541 auto texture = CreateTextureForFixture(
"table_mountain_nx.png");
3543 paint.
color_source = ColorSource::MakeImage(texture, Entity::TileMode::kClamp,
3544 Entity::TileMode::kClamp, {}, {});
3546 auto vertices = {
Point(0, 0),
Point(texture->GetSize().width, 0),
3547 Point(0, texture->GetSize().height)};
3548 std::vector<uint16_t> indices = {0u, 1u, 2u};
3549 std::vector<Point> texture_coordinates = {};
3550 std::vector<Color> vertex_colors = {};
3551 auto geometry = std::make_shared<VerticesGeometry>(
3552 vertices, indices, texture_coordinates, vertex_colors,
3553 Rect::MakeLTRB(0, 0, 1, 1), VerticesGeometry::VertexMode::kTriangleStrip);
3555 canvas.
DrawVertices(geometry, BlendMode::kSourceOver, paint);
3562 white.
color = Color::Blue();
3563 canvas.
DrawRect(Rect::MakeXYWH(0, 0, 600.0, 600.0), white);
3568 .
style = FilterContents::BlurStyle::kNormal,
3572 canvas.
DrawCircle(Point::MakeXY(300.0, 300.0), 200.0, clear);
3580 white.
color = Color::Blue();
3581 canvas.
DrawRect(Rect::MakeXYWH(0, 0, 600.0, 600.0), white);
3586 canvas.
DrawCircle(Point::MakeXY(300.0, 300.0), 200.0, clear);
3591 canvas.
Scale(GetContentScale());
3592 auto image = std::make_shared<Image>(CreateTextureForFixture(
"airplane.jpg"));
3595 .image_filter = std::make_shared<MatrixImageFilter>(
3613 canvas.
Scale(GetContentScale());
3614 canvas.
DrawRect(Rect::MakeLTRB(200, 200, 300, 300), {.color = Color::Red()});
3616 .image_filter = std::make_shared<MatrixImageFilter>(
3621 canvas.
DrawRect(Rect::MakeLTRB(0, 0, 400, 400), {.color = Color::Green()});
3623 canvas.
DrawRect(Rect::MakeLTRB(0, 0, 800, 800), {.color = Color::Red()});
3633 .
color = Color::White(),
3634 .mask_blur_descriptor =
3636 .
style = FilterContents::BlurStyle::kNormal,
3642 canvas.
DrawRect(Rect::MakeLTRB(100, 300, 500, 600), paint);
3653 {.color = Color::Blue().WithAlpha(0.5), .blend_mode = BlendMode::kSource},
3654 Rect::MakeLTRB(0, 0, 200, 200));
3656 {.color = Color::BlackTransparent(), .blend_mode = BlendMode::kSource});
3660 {.color = Color::Blue(), .blend_mode = BlendMode::kDestinationOver});