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;
2420 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
2421 actual_color = subpass->get()->GetClearColor();
2427 ASSERT_TRUE(actual_color.has_value());
2428 if (!actual_color) {
2431 ASSERT_EQ(actual_color.value(), Color::BlackTransparent());
2437 {.color = Color::Yellow(), .blend_mode = BlendMode::kSource});
2438 canvas.
SaveLayer({.blend_mode = BlendMode::kMultiply});
2439 canvas.
DrawPaint({.color = Color::CornflowerBlue().WithAlpha(0.75),
2440 .blend_mode = BlendMode::kSourceOver});
2449 {.color = Color::Yellow(), .blend_mode = BlendMode::kSource});
2451 ImageFilter::MakeBlur(
Sigma(20.0),
Sigma(20.0),
2452 FilterContents::BlurStyle::kNormal,
2453 Entity::TileMode::kDecal));
2455 {.color = Color::CornflowerBlue(), .blend_mode = BlendMode::kSourceOver});
2465 ColorFilter::MakeBlend(BlendMode::kColorDodge, Color::Red()),
2470 canvas.
DrawRect({100, 100, 200, 200}, {.color = Color::Blue()});
2480 ColorFilter::MakeMatrix({.array =
2485 1.0, 1.0, 1.0, 1.0, 0
2491 canvas.
DrawRect({100, 100, 200, 200}, {.color = Color::Blue()});
2500 .color_filter = ColorFilter::MakeLinearToSrgb(),
2505 canvas.
DrawRect({100, 100, 200, 200}, {.color = Color::Blue()});
2514 .color_filter = ColorFilter::MakeSrgbToLinear(),
2519 canvas.
DrawRect({100, 100, 200, 200}, {.color = Color::Blue()});
2525 const std::shared_ptr<Image>& src_image,
2526 const std::shared_ptr<Image>& dst_image) {
2527 Color destination_color = Color::CornflowerBlue().
WithAlpha(0.75);
2528 auto source_colors = std::vector<Color>({Color::White().WithAlpha(0.75),
2529 Color::LimeGreen().WithAlpha(0.75),
2530 Color::Black().WithAlpha(0.75)});
2534 canvas.
DrawPaint({.color = Color::Black()});
2541 for (
const auto& color : source_colors) {
2544 canvas.ClipRect(Rect::MakeXYWH(50, 50, 100, 100));
2548 canvas.SaveLayer({});
2550 canvas.DrawPaint({.color = destination_color});
2553 canvas.SaveLayer({.blend_mode = blend_mode});
2555 canvas.DrawRect({50, 50, 100, 100}, {.color = color});
2562 canvas.Translate(
Vector2(100, 0));
2564 canvas.RestoreToCount(0);
2571 canvas.Translate({0, 100});
2575 canvas.SaveLayer({});
2577 for (
const auto& color : source_colors) {
2579 canvas.DrawRect({50, 50, 100, 100},
2580 {.color = destination_color.
Blend(color, blend_mode),
2581 .blend_mode = BlendMode::kSourceOver});
2582 canvas.Translate(
Vector2(100, 0));
2584 canvas.RestoreToCount(0);
2595 canvas.SaveLayer({.blend_mode = BlendMode::kSourceOver});
2597 canvas.DrawImage(dst_image, {400, 50}, {.blend_mode = BlendMode::kSource});
2598 canvas.DrawImage(src_image, {400, 50}, {.blend_mode = blend_mode});
2600 canvas.RestoreToCount(0);
2602 return canvas.EndRecordingAsPicture();
2605 #define BLEND_MODE_TEST(blend_mode) \
2606 TEST_P(AiksTest, BlendMode##blend_mode) { \
2607 auto src_image = std::make_shared<Image>( \
2608 CreateTextureForFixture("blend_mode_src.png")); \
2609 auto dst_image = std::make_shared<Image>( \
2610 CreateTextureForFixture("blend_mode_dst.png")); \
2611 OpenPlaygroundHere( \
2612 BlendModeTest(BlendMode::k##blend_mode, src_image, dst_image)); \
2619 canvas.
DrawRect(Rect::MakeXYWH(100, 100, 300, 300), {.color = Color::Blue()});
2621 canvas.
SaveLayer({.color = Color::Black().WithAlpha(0.5)});
2622 canvas.
DrawRect(Rect::MakeXYWH(100, 500, 300, 300), {.color = Color::Blue()});
2631 canvas.
DrawRect(Rect::MakeXYWH(100, 100, 300, 300), {.color = Color::Blue()});
2634 .color = Color::Black().WithAlpha(0.5),
2636 ColorFilter::MakeBlend(BlendMode::kDestinationOver, Color::Red()),
2638 canvas.
DrawRect(Rect::MakeXYWH(100, 500, 300, 300), {.color = Color::Blue()});
2647 canvas.
DrawRect(Rect::MakeXYWH(100, 100, 300, 300), {.color = Color::Blue()});
2650 .color = Color::Black().WithAlpha(0.5),
2651 .image_filter = ImageFilter::MakeFromColorFilter(
2652 *ColorFilter::MakeBlend(BlendMode::kDestinationOver, Color::Red())),
2655 canvas.
DrawRect(Rect::MakeXYWH(100, 500, 300, 300), {.color = Color::Blue()});
2664 canvas.
DrawRect(Rect::MakeXYWH(100, 100, 300, 300), {.color = Color::Blue()});
2667 .color = Color::Black().WithAlpha(0.5),
2669 ColorFilter::MakeBlend(BlendMode::kDestinationOver, Color::Red()),
2672 canvas.
DrawRect(Rect::MakeXYWH(100, 500, 300, 300), {.color = Color::Blue()});
2681 auto image = std::make_shared<Image>(CreateTextureForFixture(
"airplane.jpg"));
2682 canvas.
DrawImage(image, {100, 100}, {});
2684 canvas.
SaveLayer({.color = Color::Black().WithAlpha(0.5)});
2685 canvas.
DrawImage(image, {100, 500}, {});
2694 auto image = std::make_shared<Image>(CreateTextureForFixture(
"airplane.jpg"));
2695 canvas.
DrawImage(image, {100, 100}, {});
2698 .color = Color::Black().WithAlpha(0.5),
2699 .color_filter = ColorFilter::MakeMatrix({.array =
2707 canvas.
DrawImage(image, {100, 500}, {});
2716 auto image = std::make_shared<Image>(CreateTextureForFixture(
"airplane.jpg"));
2717 canvas.
DrawImage(image, {100, 100}, {});
2720 .color = Color::Black().WithAlpha(0.5),
2721 .image_filter = ImageFilter::MakeFromColorFilter(
2722 *ColorFilter::MakeMatrix({.array =
2730 canvas.
DrawImage(image, {100, 500}, {});
2737 TranslucentSaveLayerWithColorFilterAndImageFilterDrawsCorrectly) {
2740 auto image = std::make_shared<Image>(CreateTextureForFixture(
"airplane.jpg"));
2741 canvas.
DrawImage(image, {100, 100}, {});
2744 .color = Color::Black().WithAlpha(0.5),
2745 .image_filter = ImageFilter::MakeFromColorFilter(
2746 *ColorFilter::MakeMatrix({.array =
2754 ColorFilter::MakeBlend(BlendMode::kModulate, Color::Green()),
2756 canvas.
DrawImage(image, {100, 500}, {});
2764 canvas.
DrawRect({0, 0, 400, 400}, {.color = Color::Red()});
2766 .color = Color::Black().WithAlpha(0.5),
2767 .blend_mode = BlendMode::kLighten,
2769 canvas.
DrawCircle({200, 200}, 100, {.color = Color::Green()});
2779 canvas.
DrawPaint({.color = Color::Red()});
2783 canvas.
DrawCircle({100, 100}, 0.1, {.color = Color::Yellow()});
2786 canvas.
DrawCircle({100, 100}, 0.1, {.color = Color::Yellow()});
2789 canvas.
DrawPaint({.color = Color::Green()});
2801 canvas.
DrawPaint({.color = Color::AntiqueWhite()});
2803 {.color = Color::CornflowerBlue().WithAlpha(0.75)});
2805 canvas.
SaveLayer({.blend_mode = BlendMode::kMultiply});
2808 {.color = Color::DarkBlue().WithAlpha(0.75)});
2810 {.color = Color::LightCoral().WithAlpha(0.75),
2811 .blend_mode = BlendMode::kLuminosity});
2823 .color = Color::CornflowerBlue(),
2824 .blend_mode = BlendMode::kSourceOver,
2830 std::shared_ptr<SolidColorContents> contents;
2831 picture.
pass->IterateAllEntities([&e = entity, &contents](
Entity& entity) {
2835 std::static_pointer_cast<SolidColorContents>(entity.
GetContents());
2841 ASSERT_TRUE(contents->IsOpaque());
2848 canvas.
DrawPaint({.color = Color::Red()});
2852 canvas.
SaveLayer({.blend_mode = BlendMode::kSource});
2853 canvas.
DrawCircle({300, 300}, 100, {.color = Color::Green()});
2862 {.color = Color::Green(),
2864 .
style = FilterContents::BlurStyle::kNormal,
2865 .sigma =
Sigma(99999),
2873 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
2875 Color::White(), Color::White());
2878 canvas.
DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
2879 canvas.
DrawCircle({300, 200}, 100, {.color = Color::GreenYellow()});
2880 canvas.
DrawCircle({140, 170}, 75, {.color = Color::DarkMagenta()});
2881 canvas.
DrawCircle({180, 120}, 100, {.color = Color::OrangeRed()});
2882 canvas.
ClipRRect(Rect::MakeLTRB(a.x, a.y, b.x, b.y), 20);
2883 canvas.
SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
2884 ImageFilter::MakeBlur(
Sigma(20.0),
Sigma(20.0),
2885 FilterContents::BlurStyle::kNormal,
2886 Entity::TileMode::kClamp));
2892 ASSERT_TRUE(OpenPlaygroundHere(callback));
2897 canvas.
DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
2898 canvas.
DrawCircle({300, 200}, 100, {.color = Color::GreenYellow()});
2899 canvas.
DrawCircle({140, 170}, 75, {.color = Color::DarkMagenta()});
2900 canvas.
DrawCircle({180, 120}, 100, {.color = Color::OrangeRed()});
2901 canvas.
ClipRRect(Rect::MakeLTRB(75, 50, 375, 275), 20);
2902 canvas.
SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
2903 ImageFilter::MakeBlur(
Sigma(30.0),
Sigma(30.0),
2904 FilterContents::BlurStyle::kNormal,
2905 Entity::TileMode::kClamp));
2913 canvas.
DrawCircle({400, 400}, 300, {.color = Color::Green()});
2914 canvas.
SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
2915 ImageFilter::MakeBlur(
Sigma(999999),
Sigma(999999),
2916 FilterContents::BlurStyle::kNormal,
2917 Entity::TileMode::kClamp));
2925 canvas.
ClipRect(Rect::MakeXYWH(100, 150, 400, 400));
2929 .color = Color::Green(),
2930 .image_filter = ImageFilter::MakeBlur(
2931 Sigma(20.0),
Sigma(20.0), FilterContents::BlurStyle::kNormal,
2932 Entity::TileMode::kClamp),
2943 canvas.
ClipRect(Rect::MakeXYWH(100, 150, 400, 400));
2946 .color = Color::White(),
2947 .color_filter = ColorFilter::MakeBlend(
2948 BlendMode::kSource, Color::Green()),
2949 .mask_blur_descriptor =
2951 .
style = FilterContents::BlurStyle::kNormal,
2964 canvas.
ClipRect(Rect::MakeXYWH(100, 150, 400, 400));
2967 .color = Color::Grey(),
2968 .color_filter = ColorFilter::MakeBlend(
2970 .mask_blur_descriptor =
2972 .
style = FilterContents::BlurStyle::kNormal,
2983 if (GetParam() != PlaygroundBackend::kMetal) {
2984 GTEST_SKIP_(
"This backend doesn't support runtime effects.");
2987 auto runtime_stage =
2988 OpenAssetAsRuntimeStage(
"runtime_stage_example.frag.iplr");
2989 ASSERT_TRUE(runtime_stage->IsDirty());
2991 struct FragUniforms {
2994 } frag_uniforms = {.iResolution =
Vector2(400, 400), .iTime = 100.0};
2995 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
2996 uniform_data->resize(
sizeof(FragUniforms));
2997 memcpy(uniform_data->data(), &frag_uniforms,
sizeof(FragUniforms));
2999 std::vector<RuntimeEffectContents::TextureInput> texture_inputs;
3003 runtime_stage, uniform_data, texture_inputs);
3008 Entity::ClipOperation::kIntersect);
3016 if (GetParam() != PlaygroundBackend::kMetal) {
3017 GTEST_SKIP_(
"This backend doesn't support runtime effects.");
3020 auto runtime_stage = OpenAssetAsRuntimeStage(
"gradient.frag.iplr");
3021 ASSERT_TRUE(runtime_stage->IsDirty());
3023 struct FragUniforms {
3025 } frag_uniforms = {.size = Size::MakeWH(400, 400)};
3026 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
3027 uniform_data->resize(
sizeof(FragUniforms));
3028 memcpy(uniform_data->data(), &frag_uniforms,
sizeof(FragUniforms));
3030 std::vector<RuntimeEffectContents::TextureInput> texture_inputs;
3034 runtime_stage, uniform_data, texture_inputs);
3038 canvas.
Scale(GetContentScale());
3046 std::vector<Point> points = {
3055 std::vector<PointStyle> caps = {
3057 PointStyle::kSquare,
3063 background.
color = Color::Black();
3068 canvas.
DrawPoints(points, 10, paint, PointStyle::kRound);
3070 canvas.
DrawPoints(points, 10, paint, PointStyle::kSquare);
3078 auto atlas = CreateTextureForFixture(
"bay_bridge.jpg");
3079 auto size = atlas->GetSize();
3080 auto image = std::make_shared<Image>(atlas);
3082 Scalar half_width = size.width / 2;
3083 Scalar half_height = size.height / 2;
3084 std::vector<Rect> texture_coordinates = {
3085 Rect::MakeLTRB(0, 0, half_width, half_height),
3086 Rect::MakeLTRB(half_width, 0, size.width, half_height),
3087 Rect::MakeLTRB(0, half_height, half_width, size.height),
3088 Rect::MakeLTRB(half_width, half_height, size.width, size.height)};
3090 std::vector<Matrix> transforms = {
3091 Matrix::MakeTranslation({0, 0, 0}),
3092 Matrix::MakeTranslation({half_width, 0, 0}),
3093 Matrix::MakeTranslation({0, half_height, 0}),
3094 Matrix::MakeTranslation({half_width, half_height, 0})};
3095 std::vector<Color> colors = {Color::Red(), Color::Green(), Color::Blue(),
3101 canvas.
Scale({0.25, 0.25, 1.0});
3102 canvas.
DrawAtlas(image, transforms, texture_coordinates, colors,
3103 BlendMode::kModulate, {}, std::nullopt, paint);
3111 auto atlas = CreateTextureForFixture(
"bay_bridge.jpg");
3112 auto size = atlas->GetSize();
3113 auto image = std::make_shared<Image>(atlas);
3115 Scalar half_width = size.width / 2;
3116 Scalar half_height = size.height / 2;
3117 std::vector<Rect> texture_coordinates = {
3118 Rect::MakeLTRB(0, 0, half_width, half_height),
3119 Rect::MakeLTRB(half_width, 0, size.width, half_height),
3120 Rect::MakeLTRB(0, half_height, half_width, size.height),
3121 Rect::MakeLTRB(half_width, half_height, size.width, size.height)};
3123 std::vector<Matrix> transforms = {
3124 Matrix::MakeTranslation({0, 0, 0}),
3125 Matrix::MakeTranslation({half_width, 0, 0}),
3126 Matrix::MakeTranslation({0, half_height, 0}),
3127 Matrix::MakeTranslation({half_width, half_height, 0})};
3132 canvas.
Scale({0.25, 0.25, 1.0});
3133 canvas.
DrawAtlas(image, transforms, texture_coordinates, {},
3134 BlendMode::kModulate, {}, std::nullopt, paint);
3140 auto texture = CreateTextureForFixture(
"table_mountain_nx.png",
3143 std::vector<Point> points = {
3152 std::vector<PointStyle> caps = {
3154 PointStyle::kSquare,
3157 paint.
color_source = ColorSource::MakeImage(texture, Entity::TileMode::kClamp,
3158 Entity::TileMode::kClamp, {}, {});
3162 canvas.DrawPoints(points, 100, paint, PointStyle::kRound);
3163 canvas.Translate({150, 0});
3164 canvas.DrawPoints(points, 100, paint, PointStyle::kSquare);
3166 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
3174 ASSERT_NE(mapping,
nullptr);
3177 SkFont sk_font(SkTypeface::MakeFromData(mapping), font_size);
3180 text_paint.
color = Color::Blue();
3182 std::vector<Color> colors = {
Color{0.9568, 0.2627, 0.2118, 1.0},
3183 Color{0.1294, 0.5882, 0.9529, 1.0}};
3184 std::vector<Scalar> stops = {
3188 text_paint.
color_source = ColorSource::MakeLinearGradient(
3189 {0, 0}, {100, 100}, std::move(colors), std::move(stops),
3190 Entity::TileMode::kRepeat, {});
3196 auto blob = SkTextBlob::MakeFromString(
"Hello", sk_font);
3197 ASSERT_NE(blob,
nullptr);
3199 canvas.DrawTextFrame(frame,
Point(), text_paint);
3201 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
3206 subcanvas.
DrawRect(Rect::MakeLTRB(-100, -50, 100, 50),
3207 {.color = Color::CornflowerBlue()});
3221 Rect::MakeLTRB(-100, -50, 100, 50),
3222 {.color = Color::CornflowerBlue(), .blend_mode = BlendMode::kColorDodge});
3226 canvas.
DrawPaint({.color = Color::Black()});
3227 canvas.
DrawCircle(Point::MakeXY(150, 150), 25, {.color = Color::Red()});
3236 ImageFilter::MakeBlur(
Sigma(20.0),
Sigma(20.0),
3237 FilterContents::BlurStyle::kNormal,
3238 Entity::TileMode::kDecal));
3239 auto image = std::make_shared<Image>(CreateTextureForFixture(
"kalimba.jpg"));
3242 subcanvas.
DrawImage(image, Point::MakeXY(100.0, 100.0), paint);
3247 canvas.
DrawPaint({.color = Color::Black()});
3248 canvas.
DrawCircle(Point::MakeXY(150, 150), 25, {.color = Color::Red()});
3257 GetContext(), subcanvas,
3258 "the quick brown fox jumped over the lazy dog!.?",
"Roboto-Regular.ttf"));
3262 GetContext(), subcanvas,
3263 "the quick brown fox jumped over the very big lazy dog!.?",
3264 "Roboto-Regular.ttf"));
3277 GetContext(), canvas,
3278 "the quick brown fox jumped over the smaller lazy dog!.?",
3279 "Roboto-Regular.ttf"));
3285 subcanvas.
ClipRRect(Rect::MakeLTRB(100, 100, 400, 400), 15);
3286 subcanvas.
DrawPaint({.color = Color::Red()});
3290 canvas.
DrawPaint({.color = Color::CornflowerBlue()});
3297 canvas.
ClipRRect(Rect::MakeLTRB(100, 100, 400, 400).Expand(20), 15);
3298 canvas.
DrawPaint({.color = Color::Green()});
3305 canvas.
DrawPaint({.color = Color::Black()});
3309 {.color = Color::Green().WithAlpha(0.5),
3310 .blend_mode = BlendMode::kPlus});
3313 canvas.
SaveLayer({.image_filter = ImageFilter::MakeMatrix(
3314 Matrix::MakeTranslation(
Vector2(1, 1) *
3316 Matrix::MakeScale(
Vector2(1, 1) * 0.5) *
3317 Matrix::MakeTranslation(
Vector2(-200, -200)),
3321 {.color = Color::Green().WithAlpha(0.5),
3322 .blend_mode = BlendMode::kPlus});
3332 canvas.
DrawPaint({.color = Color::Black()});
3336 {.color = Color::Green().WithAlpha(0.5),
3337 .blend_mode = BlendMode::kPlus});
3342 ImageFilter::MakeMatrix(
3344 Matrix::MakeScale(
Vector2(1, 1) * 0.5) *
3345 Matrix::MakeTranslation(
Vector2(-100, -100)),
3356 contents.SetColor(Color::CornflowerBlue().WithAlpha(0.75));
3357 auto result = contents.ApplyColorFilter([](
const Color& color) {
3358 return color.
Blend(Color::LimeGreen().WithAlpha(0.75), BlendMode::kScreen);
3360 ASSERT_TRUE(result);
3362 Color(0.433247, 0.879523, 0.825324, 0.75));
3365 #define APPLY_COLOR_FILTER_GRADIENT_TEST(name) \
3366 TEST_P(AiksTest, name##GradientApplyColorFilter) { \
3367 auto contents = name##GradientContents(); \
3368 contents.SetColors({Color::CornflowerBlue().WithAlpha(0.75)}); \
3369 auto result = contents.ApplyColorFilter([](const Color& color) { \
3370 return color.Blend(Color::LimeGreen().WithAlpha(0.75), \
3371 BlendMode::kScreen); \
3373 ASSERT_TRUE(result); \
3375 std::vector<Color> expected = {Color(0.433247, 0.879523, 0.825324, 0.75)}; \
3376 ASSERT_COLORS_NEAR(contents.GetColors(), expected); \
3388 2.000000, 0.000000, 0.000000, 0.000000,
3389 1.445767, 2.637070, -0.507928, 0.001524,
3390 -2.451887, -0.534662, 0.861399, -0.002584,
3391 1063.481934, 1025.951416, -48.300270, 1.144901
3396 "Roboto-Regular.ttf"));
3407 2.000000, 0.000000, 0.000000, 0.000000,
3408 1.445767, 2.637070, -0.507928, 0.001524,
3409 -2.451887, -0.534662, 0.861399, -0.002584,
3410 1063.481934, 1025.951416, -48.300270, 1.144901
3415 "Roboto-Regular.ttf"));
3429 .color = Color::Green(),
3430 .blend_mode = BlendMode::kSourceOver,
3431 .image_filter = ImageFilter::MakeFromColorFilter(
3432 *ColorFilter::MakeBlend(BlendMode::kDestination,
3442 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
3449 .
style = FilterContents::BlurStyle::kNormal,
3450 .sigma =
Radius{120 * 3},
3452 paint.
color = Color::Red();
3454 builder.
AddRect(Rect::MakeLTRB(0, 0, 800, 800));
3455 canvas.
DrawPath(builder.TakePath(), paint);
3458 ASSERT_TRUE(OpenPlaygroundHere(callback));
3466 .
style = FilterContents::BlurStyle::kNormal,
3467 .sigma =
Radius{120 * 3},
3469 paint.
color = Color::Red();
3471 builder.
AddRect(Rect::MakeLTRB(0, 0, 800, 800));
3472 canvas.
DrawPath(builder.TakePath(), paint);
3477 auto capture_context = CaptureContext::MakeAllowlist({
"TestDocument"});
3479 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
3482 capture_context.Rewind();
3483 auto document = capture_context.GetDocument(
"TestDocument");
3485 auto color = document.AddColor(
"Background color", Color::CornflowerBlue());
3488 ImGui::Begin(
"TestDocument",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
3489 document.GetElement()->properties.Iterate([](
CaptureProperty& property) {
3490 property.Invoke({.color = [](CaptureColorProperty& p) {
3491 ImGui::ColorEdit4(p.label.c_str(),
reinterpret_cast<float*
>(&p.value));
3498 OpenPlaygroundHere(callback);
3502 ASSERT_FALSE(GetContext()->capture.IsActive());
3507 auto context = GetContext();
3508 std::weak_ptr<Texture> weak_texture;
3511 auto texture = CreateTextureForFixture(
"table_mountain_nx.png");
3514 canvas.
Scale(GetContentScale());
3519 texture, Entity::TileMode::kClamp, Entity::TileMode::kClamp, {}, {});
3520 canvas.
DrawRect({0, 0, 600, 600}, paint);
3530 context->Shutdown();
3533 ASSERT_TRUE(weak_texture.expired()) <<
"When the texture is no longer in use "
3534 "by the backend, it should be "
3542 auto texture = CreateTextureForFixture(
"table_mountain_nx.png");
3544 paint.
color_source = ColorSource::MakeImage(texture, Entity::TileMode::kClamp,
3545 Entity::TileMode::kClamp, {}, {});
3547 auto vertices = {
Point(0, 0),
Point(texture->GetSize().width, 0),
3548 Point(0, texture->GetSize().height)};
3549 std::vector<uint16_t> indices = {0u, 1u, 2u};
3550 std::vector<Point> texture_coordinates = {};
3551 std::vector<Color> vertex_colors = {};
3552 auto geometry = std::make_shared<VerticesGeometry>(
3553 vertices, indices, texture_coordinates, vertex_colors,
3554 Rect::MakeLTRB(0, 0, 1, 1), VerticesGeometry::VertexMode::kTriangleStrip);
3556 canvas.
DrawVertices(geometry, BlendMode::kSourceOver, paint);
3563 white.
color = Color::Blue();
3564 canvas.
DrawRect(Rect::MakeXYWH(0, 0, 600.0, 600.0), white);
3569 .
style = FilterContents::BlurStyle::kNormal,
3573 canvas.
DrawCircle(Point::MakeXY(300.0, 300.0), 200.0, clear);
3581 white.
color = Color::Blue();
3582 canvas.
DrawRect(Rect::MakeXYWH(0, 0, 600.0, 600.0), white);
3587 canvas.
DrawCircle(Point::MakeXY(300.0, 300.0), 200.0, clear);
3592 canvas.
Scale(GetContentScale());
3593 auto image = std::make_shared<Image>(CreateTextureForFixture(
"airplane.jpg"));
3596 .image_filter = std::make_shared<MatrixImageFilter>(
3614 canvas.
Scale(GetContentScale());
3615 canvas.
DrawRect(Rect::MakeLTRB(200, 200, 300, 300), {.color = Color::Red()});
3617 .image_filter = std::make_shared<MatrixImageFilter>(
3622 canvas.
DrawRect(Rect::MakeLTRB(0, 0, 400, 400), {.color = Color::Green()});
3624 canvas.
DrawRect(Rect::MakeLTRB(0, 0, 800, 800), {.color = Color::Red()});