15 #include "flutter/testing/testing.h"
21 #include "impeller/aiks/testing/context_spy.h"
38 #include "impeller/renderer/testing/mocks.h"
46 #include "third_party/imgui/imgui.h"
47 #include "third_party/skia/include/core/SkFontMgr.h"
48 #include "third_party/skia/include/core/SkTypeface.h"
49 #include "txt/platform.h"
68 ASSERT_EQ(canvas.
Restore(),
false);
95 auto image = std::make_shared<Image>(CreateTextureForFixture(
"kalimba.jpg"));
104 auto image = std::make_shared<Image>(CreateTextureForFixture(
"kalimba.jpg"));
139 bool GenerateMipmap(
const std::shared_ptr<Context>& context,
140 std::shared_ptr<Texture> texture,
143 auto buffer = context->CreateCommandBuffer();
147 auto pass = buffer->CreateBlitPass();
151 pass->GenerateMipmap(std::move(texture), std::move(label));
153 return buffer->EncodeAndSubmit(pass, context->GetResourceAllocator());
156 pass->EncodeCommands(context->GetResourceAllocator());
157 return buffer->SubmitCommands();
160 void CanRenderTiledTexture(
AiksTest* aiks_test,
162 bool async_submit =
false,
163 Matrix local_matrix = {}) {
164 auto context = aiks_test->GetContext();
165 ASSERT_TRUE(context);
166 auto texture = aiks_test->CreateTextureForFixture(
"table_mountain_nx.png",
168 GenerateMipmap(context, texture,
"table_mountain_nx", async_submit);
170 canvas.Scale(aiks_test->GetContentScale());
171 canvas.Translate({100.0f, 100.0f, 0});
175 paint.color = Color(1, 1, 1, 1);
179 constexpr
auto stroke_width = 64;
181 paint.stroke_width = stroke_width;
183 canvas.DrawRect(
Rect::MakeXYWH(stroke_width, stroke_width, 600, 600),
191 PathBuilder path_builder;
192 path_builder.AddCircle({150, 150}, 150);
193 path_builder.AddRoundedRect(
Rect::MakeLTRB(300, 300, 600, 600), 10);
195 canvas.DrawPath(path_builder.TakePath(), paint);
200 PathBuilder path_builder;
201 path_builder.AddCircle({150, 450}, 150);
204 canvas.DrawPath(path_builder.TakePath(), paint);
207 ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
239 auto image = std::make_shared<Image>(CreateTextureForFixture(
"kalimba.jpg"));
240 Size image_half_size =
Size(image->GetSize()) * 0.5;
244 source_rect = source_rect.Shift(
Point(image_half_size));
253 canvas.
Scale(GetContentScale());
298 std::vector<Color> gradient_colors = {
299 Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
300 Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
301 Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
302 Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
303 Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
304 Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
305 Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
306 std::vector<Scalar> stops = {
315 auto texture = CreateTextureForFixture(
"airplane.jpg",
319 {500, 600}, 75, std::move(gradient_colors), std::move(stops),
372 .HorizontalLineTo(-200)
374 .CubicCurveTo({0, -40}, {0, -80}, {200, -80})
412 for (
int i = 0; i < 15; i++) {
415 paint.
color = colors[i % colors.size()];
444 std::vector<Color> colors = {
Color{0.9568, 0.2627, 0.2118, 1.0},
445 Color{0.1294, 0.5882, 0.9529, 1.0}};
446 std::vector<Scalar> stops = {
452 {0, 0}, {100, 100}, std::move(colors), std::move(stops),
470 paint.
color =
Color{0.9568, 0.2627, 0.2118, 1.0};
472 paint.
color =
Color{0.1294, 0.5882, 0.9529, 1.0};
480 auto image = picture.
ToImage(renderer,
ISize{1000, 1000});
546 std::make_shared<Image>(CreateTextureForFixture(
"kalimba.jpg"));
630 CanPerformSaveLayerWithBoundsAndLargerIntermediateIsNotAllocated) {
672 canvas.
DrawPath(std::move(path), paint);
686 const std::string& text,
687 const std::string_view& font_fixture,
691 Rect::MakeXYWH(options.position.x - 50, options.position.y, 900, 10),
692 Paint{.color = Color::Aqua().WithAlpha(0.25)});
696 Paint{.color = Color::Red().WithAlpha(0.25)});
699 auto c_font_fixture = std::string(font_fixture);
700 auto mapping = flutter::testing::OpenFixtureAsSkData(c_font_fixture.c_str());
704 sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
705 SkFont sk_font(font_mgr->makeFromData(mapping), options.font_size);
706 auto blob = SkTextBlob::MakeFromString(text.c_str(), sk_font);
715 text_paint.color = options.color;
716 text_paint.mask_blur_descriptor = options.mask_blur_descriptor;
723 const std::string& text,
724 const std::string& font_fixture,
728 Rect::MakeXYWH(options.position.x - 50, options.position.y, 900, 10),
729 Paint{.color = Color::Aqua().WithAlpha(0.25)});
733 Paint{.color = Color::Red().WithAlpha(0.25)});
736 auto mapping = flutter::testing::OpenFixtureAsMapping(font_fixture.c_str());
740 auto typeface_stb = std::make_shared<TypefaceSTB>(std::move(mapping));
743 typeface_stb, Font::Metrics{.point_size = options.font_size}, text);
746 text_paint.color = options.color;
755 GetContext(), canvas,
"the quick brown fox jumped over the lazy dog!.?",
756 "Roboto-Regular.ttf"));
764 GetContext(), canvas,
"the quick brown fox jumped over the lazy dog!.?",
765 "Roboto-Regular.ttf"));
772 std::array<Scalar, 20> phase_offsets;
773 for (
Scalar& offset : phase_offsets) {
774 auto rand = std::rand();
775 offset = (
static_cast<float>(rand) /
static_cast<float>(RAND_MAX)) *
k2Pi;
778 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
779 static float font_size = 20;
780 static float phase_variation = 0.2;
781 static float speed = 0.5;
782 static float magnitude = 100;
783 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
784 ImGui::SliderFloat(
"Font size", &font_size, 5, 50);
785 ImGui::SliderFloat(
"Phase variation", &phase_variation, 0, 1);
786 ImGui::SliderFloat(
"Oscillation speed", &speed, 0, 2);
787 ImGui::SliderFloat(
"Oscillation magnitude", &magnitude, 0, 300);
791 canvas.
Scale(GetContentScale());
793 for (
size_t i = 0; i < phase_offsets.size(); i++) {
794 auto position =
Point(
795 200 + magnitude * std::sin((-phase_offsets[i] * phase_variation +
796 GetSecondsElapsed() * speed)),
797 200 + i * font_size * 1.1
800 GetContext(), canvas,
801 "the quick brown fox jumped over "
803 "Roboto-Regular.ttf",
804 {.font_size = font_size, .position = position})) {
811 ASSERT_TRUE(OpenPlaygroundHere(callback));
819 GetContext(), canvas,
"the quick brown fox jumped over the lazy dog!.?",
820 "HomemadeApple.ttf"));
826 "Apple Color Emoji.ttc";
828 "NotoColorEmoji.ttf";
836 GetContext(), canvas,
"😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊",
kFontFixture));
845 GetContext(), canvas,
"😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊",
kFontFixture,
849 .sigma =
Sigma(4)}}));
858 GetContext(), canvas,
"😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊",
kFontFixture,
873 GetContext(), canvas,
"the quick brown fox jumped over the lazy dog!.?",
874 "Roboto-Regular.ttf"));
879 GetContext(), canvas,
"the quick brown fox jumped over the lazy dog!.?",
880 "Roboto-Regular.ttf"));
890 auto mapping = flutter::testing::OpenFixtureAsSkData(
"wtf.otf");
891 ASSERT_NE(mapping,
nullptr);
894 sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
895 SkFont sk_font(font_mgr->makeFromData(mapping), font_size);
903 } text[] = {{
Point(0, 0),
"0F0F0F0"},
904 {
Point(1, 2),
"789"},
905 {
Point(1, 3),
"456"},
906 {
Point(1, 4),
"123"},
907 {
Point(0, 6),
"0F0F0F0"}};
908 for (
auto& t : text) {
910 canvas.
Translate(t.position *
Point(font_size * 2, font_size * 1.1));
912 auto blob = SkTextBlob::MakeFromString(t.text, sk_font);
913 ASSERT_NE(blob,
nullptr);
925 canvas.
Scale(GetContentScale());
933 GetContext(), canvas,
"the quick brown fox jumped over the lazy dog!.?",
934 "Roboto-Regular.ttf"));
950 canvas.
DrawPaint({.color = Color::Color::OrangeRed().WithAlpha(0.5)});
958 canvas.
DrawPaint({.color = Color::Color::OrangeRed().WithAlpha(0.5),
966 .mask_blur_descriptor =
981 std::vector<Color> colors = {
Color{0.9568, 0.2627, 0.2118, 1.0},
982 Color{0.1294, 0.5882, 0.9529, 1.0}};
983 std::vector<Scalar> stops = {0.0, 1.0};
987 {0, 0}, {100, 100}, std::move(colors), std::move(stops),
1000 #define BLEND_MODE_TUPLE(blend_mode) {#blend_mode, BlendMode::k##blend_mode},
1008 std::vector<const char*> blend_mode_names;
1009 std::vector<BlendMode> blend_mode_values;
1011 const std::vector<std::tuple<const char*, BlendMode>> blends = {
1013 assert(blends.size() ==
1015 for (
const auto& [name, mode] : blends) {
1016 blend_mode_names.push_back(name);
1017 blend_mode_values.push_back(mode);
1021 return {blend_mode_names, blend_mode_values};
1027 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
1029 static Color foreground = Color::Color::OrangeRed().
WithAlpha(0.5);
1030 static int current_blend_index = 3;
1032 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1034 ImGui::ColorEdit4(
"Background",
reinterpret_cast<float*
>(&background));
1035 ImGui::ColorEdit4(
"Foreground",
reinterpret_cast<float*
>(&foreground));
1036 ImGui::ListBox(
"Blend mode", ¤t_blend_index,
1037 modes.blend_mode_names.data(),
1038 modes.blend_mode_names.size());
1044 canvas.
DrawPaint({.color = background});
1046 {.color = foreground,
1047 .blend_mode =
static_cast<BlendMode>(current_blend_index)});
1050 ASSERT_TRUE(OpenPlaygroundHere(callback));
1077 auto draw_color_wheel = [](
Canvas& canvas) {
1080 auto color_wheel_sampler = [](
Radians r) {
1084 auto color_cycle = [](
Scalar x) {
1085 Scalar cycle = std::fmod(x, 6.0f);
1086 return std::max(0.0f, std::min(1.0f, 2 - std::abs(2 - cycle)));
1088 return Color(color_cycle(6 * x + 1),
1089 color_cycle(6 * x - 1),
1090 color_cycle(6 * x - 3),
1099 const int max_dist = 900;
1100 for (
int i = 0; i <= 900; i++) {
1103 Scalar normalized_distance =
static_cast<Scalar>(i) / max_dist;
1106 color_wheel_sampler(r).
WithAlpha(1.0f - normalized_distance);
1108 -distance * std::cos(r.
radians));
1110 canvas.
DrawCircle(position, 9 + normalized_distance * 3, paint);
1114 std::shared_ptr<Image> color_wheel_image;
1115 Matrix color_wheel_transform;
1117 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
1119 static bool cache_the_wheel =
true;
1120 static int current_blend_index = 3;
1121 static float dst_alpha = 1;
1122 static float src_alpha = 1;
1127 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1129 ImGui::Checkbox(
"Cache the wheel", &cache_the_wheel);
1130 ImGui::ListBox(
"Blending mode", ¤t_blend_index,
1133 ImGui::SliderFloat(
"Source alpha", &src_alpha, 0, 1);
1134 ImGui::ColorEdit4(
"Color A",
reinterpret_cast<float*
>(&color0));
1135 ImGui::ColorEdit4(
"Color B",
reinterpret_cast<float*
>(&color1));
1136 ImGui::ColorEdit4(
"Color C",
reinterpret_cast<float*
>(&color2));
1137 ImGui::SliderFloat(
"Destination alpha", &dst_alpha, 0, 1);
1141 static Point content_scale;
1142 Point new_content_scale = GetContentScale();
1144 if (!cache_the_wheel || new_content_scale != content_scale) {
1145 content_scale = new_content_scale;
1150 canvas.
Scale(content_scale);
1155 draw_color_wheel(canvas);
1157 auto snapshot = color_wheel_picture.
Snapshot(renderer);
1158 if (!snapshot.has_value() || !snapshot->texture) {
1159 return std::nullopt;
1161 color_wheel_image = std::make_shared<Image>(snapshot->texture);
1162 color_wheel_transform = snapshot->transform;
1174 canvas.
Transform(color_wheel_transform);
1180 canvas.
Scale(content_scale);
1193 paint.
color = color0;
1195 paint.
color = color1;
1197 paint.
color = color2;
1205 ASSERT_TRUE(OpenPlaygroundHere(callback));
1249 canvas.
Scale(GetContentScale());
1251 const int color_count = 3;
1252 Color colors[color_count] = {
1263 while (radius > 0) {
1264 paint.
color = colors[(c_index++) % color_count];
1273 std::vector<Color> gradient_colors = {
1274 Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
1275 Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
1276 Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
1277 Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
1278 Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
1279 Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
1280 Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
1281 std::vector<Scalar> stops = {
1290 auto texture = CreateTextureForFixture(
"airplane.jpg",
1294 {500, 600}, 75, std::move(gradient_colors), std::move(stops),
1308 canvas.
Scale(GetContentScale());
1310 const int color_count = 3;
1311 Color colors[color_count] = {
1322 auto draw = [&paint, &colors, &c_index](
Canvas& canvas,
Point center,
1324 for (
int i = 0; i < n; i++) {
1325 paint.
color = colors[(c_index++) % color_count];
1326 canvas.DrawCircle(center, r, paint);
1333 draw(canvas, {10, 10}, 2, 2, 14);
1335 draw(canvas, {10, 10}, 35, 10, 56);
1337 std::vector<Color> gradient_colors = {
1338 Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
1339 Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
1340 Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
1341 Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
1342 Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
1343 Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
1344 Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
1345 std::vector<Scalar> stops = {
1354 auto texture = CreateTextureForFixture(
"airplane.jpg",
1358 {500, 600}, 75, std::move(gradient_colors), std::move(stops),
1360 draw(canvas, {500, 600}, 5, 10, 10);
1365 draw(canvas, {800, 300}, 5, 10, 10);
1367 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
1372 canvas.
Scale(GetContentScale());
1374 const int color_count = 3;
1375 Color colors[color_count] = {
1385 int long_radius = 600;
1386 int short_radius = 600;
1387 while (long_radius > 0 && short_radius > 0) {
1388 paint.
color = colors[(c_index++) % color_count];
1390 long_radius * 2, short_radius * 2),
1393 short_radius * 2, long_radius * 2),
1395 if (short_radius > 30) {
1404 std::vector<Color> gradient_colors = {
1405 Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
1406 Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
1407 Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
1408 Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
1409 Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
1410 Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
1411 Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
1412 std::vector<Scalar> stops = {
1421 auto texture = CreateTextureForFixture(
"airplane.jpg",
1427 {300, 650}, 75, std::move(gradient_colors), std::move(stops),
1443 canvas.
Scale(GetContentScale());
1445 const int color_count = 3;
1446 Color colors[color_count] = {
1456 for (
int i = 0; i < 4; i++) {
1457 for (
int j = 0; j < 4; j++) {
1458 paint.
color = colors[(c_index++) % color_count];
1460 Size(i * 5 + 10, j * 5 + 10), paint);
1463 paint.
color = colors[(c_index++) % color_count];
1465 paint.
color = colors[(c_index++) % color_count];
1468 std::vector<Color> gradient_colors = {
1469 Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
1470 Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
1471 Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
1472 Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
1473 Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
1474 Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
1475 Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
1476 std::vector<Scalar> stops = {
1485 auto texture = CreateTextureForFixture(
"airplane.jpg",
1491 for (
int i = 1; i <= 10; i++) {
1494 550 + i * 20, 550 + j * 20),
1495 Size(i * 10, j * 10), paint);
1499 {200, 650}, 75, std::move(gradient_colors), std::move(stops),
1508 for (
int i = 1; i <= 10; i++) {
1511 720 + i * 20, 220 + j * 20),
1512 Size(i * 10, j * 10), paint);
1526 canvas.
Scale(GetContentScale());
1537 for (
int i = 0; i < 5; i++) {
1538 Scalar x = (i + 1) * 100;
1539 Scalar radius = x / 10.0f;
1541 radius, 60.0f - radius),
1547 for (
int i = 0; i < 5; i++) {
1548 Scalar x = (i + 1) * 100;
1549 Scalar radius = x / 10.0f;
1550 canvas.
DrawCircle({x + 25, y + 25}, radius, paint);
1555 for (
int i = 0; i < 5; i++) {
1556 Scalar x = (i + 1) * 100;
1557 Scalar radius = x / 10.0f;
1559 radius, 60.0f - radius),
1565 for (
int i = 0; i < 5; i++) {
1566 Scalar x = (i + 1) * 100;
1567 Scalar radius = x / 20.0f;
1575 for (
int i = 0; i < 5; i++) {
1576 Scalar x = (i + 1) * 100;
1577 Scalar radius = x / 20.0f;
1579 {radius, 5.0f}, paint);
1587 canvas.
Scale(GetContentScale());
1589 const int color_count = 3;
1590 Color colors[color_count] = {
1599 auto draw_rrect_as_path = [&canvas](
const Rect& rect,
const Size& radii,
1600 const Paint& paint) {
1607 for (
int i = 0; i < 4; i++) {
1608 for (
int j = 0; j < 4; j++) {
1609 paint.
color = colors[(c_index++) % color_count];
1610 draw_rrect_as_path(
Rect::MakeXYWH(i * 100 + 10, j * 100 + 20, 80, 80),
1611 Size(i * 5 + 10, j * 5 + 10), paint);
1614 paint.
color = colors[(c_index++) % color_count];
1616 paint.
color = colors[(c_index++) % color_count];
1619 std::vector<Color> gradient_colors = {
1620 Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
1621 Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
1622 Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
1623 Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
1624 Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
1625 Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
1626 Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
1627 std::vector<Scalar> stops = {
1636 auto texture = CreateTextureForFixture(
"airplane.jpg",
1642 for (
int i = 1; i <= 10; i++) {
1645 550 + i * 20, 550 + j * 20),
1646 Size(i * 10, j * 10), paint);
1650 {200, 650}, 75, std::move(gradient_colors), std::move(stops),
1659 for (
int i = 1; i <= 10; i++) {
1662 720 + i * 20, 220 + j * 20),
1663 Size(i * 10, j * 10), paint);
1676 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
1678 canvas.
Scale(GetContentScale());
1683 auto current =
Point{25, 25};
1684 const auto offset =
Point{25, 25};
1685 const auto size =
Size(100, 100);
1692 .stroke_width = 5.0f,
1709 ASSERT_TRUE(OpenPlaygroundHere(callback));
1795 canvas.
Scale(GetContentScale());
1798 auto texture = std::make_shared<Image>(CreateTextureForFixture(
"boston.jpg"));
1799 auto draw_image_layer = [&canvas, &texture](
const Paint& paint) {
1810 draw_image_layer(effect_paint);
1814 draw_image_layer(effect_paint);
1819 #if IMPELLER_ENABLE_3D
1823 flutter::testing::OpenFixtureAsMapping(
"flutter_logo_baked.glb.ipscene");
1824 ASSERT_NE(mapping,
nullptr);
1827 *mapping, *GetContext()->GetResourceAllocator());
1828 ASSERT_NE(gltf_scene,
nullptr);
1830 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
1833 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1834 static Scalar distance = 2;
1835 ImGui::SliderFloat(
"Distance", &distance, 0, 4);
1837 ImGui::SliderFloat(
"Y", &y_pos, -3, 3);
1839 ImGui::SliderFloat(
"FOV", &fov, 1, 180);
1842 Scalar angle = GetSecondsElapsed();
1843 auto camera_position =
1844 Vector3(distance * std::sin(angle), y_pos, -distance * std::cos(angle));
1853 canvas.Scale(GetContentScale());
1854 canvas.DrawPaint(paint);
1855 return canvas.EndRecordingAsPicture();
1858 ASSERT_TRUE(OpenPlaygroundHere(callback));
1860 #endif // IMPELLER_ENABLE_3D
1890 auto entity_pass = std::make_shared<EntityPass>();
1898 auto delegate = std::make_shared<OpacityPeepholePassDelegate>(paint);
1899 ASSERT_FALSE(delegate->CanCollapseIntoParentPass(entity_pass.get()));
1907 delegate = std::make_shared<OpacityPeepholePassDelegate>(paint);
1908 ASSERT_FALSE(delegate->CanCollapseIntoParentPass(entity_pass.get()));
1914 delegate = std::make_shared<OpacityPeepholePassDelegate>(paint);
1915 ASSERT_FALSE(delegate->CanCollapseIntoParentPass(entity_pass.get()));
1921 entity_pass->AddEntity(std::move(entity));
1924 delegate = std::make_shared<OpacityPeepholePassDelegate>(paint);
1925 ASSERT_TRUE(delegate->CanCollapseIntoParentPass(entity_pass.get()));
1937 ASSERT_EQ(picture.
pass->GetClearColor(), expected);
1939 std::shared_ptr<ContextSpy> spy = ContextSpy::Make();
1940 std::shared_ptr<Context> real_context = GetContext();
1941 std::shared_ptr<ContextMock> mock_context = spy->MakeContext(real_context);
1943 std::shared_ptr<Image> image = picture.
ToImage(renderer, {300, 300});
1945 ASSERT_EQ(spy->render_passes_.size(), 1llu);
1946 std::shared_ptr<RenderPass> render_pass = spy->render_passes_[0];
1947 ASSERT_EQ(render_pass->GetCommands().size(), 0llu);
1953 ParentSaveLayerCreatesRenderPassWhenChildBackdropFilterIsPresent) {
1963 std::shared_ptr<ContextSpy> spy = ContextSpy::Make();
1964 std::shared_ptr<Context> real_context = GetContext();
1965 std::shared_ptr<ContextMock> mock_context = spy->MakeContext(real_context);
1967 std::shared_ptr<Image> image = picture.
ToImage(renderer, {300, 300});
1969 ASSERT_EQ(spy->render_passes_.size(), 3llu);
1970 std::shared_ptr<RenderPass> render_pass = spy->render_passes_[0];
1971 ASSERT_EQ(render_pass->GetCommands().size(), 0llu);
1982 std::shared_ptr<ContextSpy> spy = ContextSpy::Make();
1984 std::shared_ptr<Context> real_context = GetContext();
1985 std::shared_ptr<ContextMock> mock_context = spy->MakeContext(real_context);
1987 std::shared_ptr<Image> image = picture.
ToImage(renderer, {300, 300});
1989 ASSERT_EQ(spy->render_passes_.size(), 1llu);
1990 std::shared_ptr<RenderPass> render_pass = spy->render_passes_[0];
1991 ASSERT_EQ(render_pass->GetCommands().size(), 0llu);
2002 std::shared_ptr<ContextSpy> spy = ContextSpy::Make();
2004 std::shared_ptr<Context> real_context = GetContext();
2005 std::shared_ptr<ContextMock> mock_context = spy->MakeContext(real_context);
2007 std::shared_ptr<Image> image = picture.
ToImage(renderer, {300, 300});
2009 ASSERT_EQ(spy->render_passes_.size(), 1llu);
2010 std::shared_ptr<RenderPass> render_pass = spy->render_passes_[0];
2011 ASSERT_EQ(render_pass->GetCommands().size(), 2llu);
2022 std::shared_ptr<ContextSpy> spy = ContextSpy::Make();
2024 std::shared_ptr<Context> real_context = GetContext();
2025 std::shared_ptr<ContextMock> mock_context = spy->MakeContext(real_context);
2027 std::shared_ptr<Image> image = picture.
ToImage(renderer, {300, 300});
2029 ASSERT_EQ(spy->render_passes_.size(), 1llu);
2030 std::shared_ptr<RenderPass> render_pass = spy->render_passes_[0];
2031 ASSERT_EQ(render_pass->GetCommands().size(), 1llu);
2042 std::shared_ptr<ContextSpy> spy = ContextSpy::Make();
2044 std::shared_ptr<Context> real_context = GetContext();
2045 std::shared_ptr<ContextMock> mock_context = spy->MakeContext(real_context);
2047 std::shared_ptr<Image> image = picture.
ToImage(renderer, {301, 301});
2049 ASSERT_EQ(spy->render_passes_.size(), 1llu);
2050 std::shared_ptr<RenderPass> render_pass = spy->render_passes_[0];
2051 ASSERT_EQ(render_pass->GetCommands().size(), 2llu);
2065 ASSERT_EQ(picture.
pass->GetClearColor(), expected);
2067 std::shared_ptr<ContextSpy> spy = ContextSpy::Make();
2068 std::shared_ptr<Context> real_context = GetContext();
2069 std::shared_ptr<ContextMock> mock_context = spy->MakeContext(real_context);
2071 std::shared_ptr<Image> image = picture.
ToImage(renderer, {300, 300});
2073 ASSERT_EQ(spy->render_passes_.size(), 1llu);
2074 std::shared_ptr<RenderPass> render_pass = spy->render_passes_[0];
2075 ASSERT_EQ(render_pass->GetCommands().size(), 0llu);
2091 std::optional<Color> actual_color;
2092 bool found_subpass =
false;
2094 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
2095 actual_color = subpass->get()->GetClearColor();
2096 found_subpass =
true;
2102 EXPECT_TRUE(found_subpass);
2103 EXPECT_FALSE(actual_color.has_value());
2157 1.0, 1.0, 1.0, 1.0, 0
2197 const std::shared_ptr<Image>& src_image,
2198 const std::shared_ptr<Image>& dst_image) {
2213 for (
const auto& color : source_colors) {
2220 canvas.SaveLayer({});
2222 canvas.DrawPaint({.color = destination_color});
2225 canvas.SaveLayer({.blend_mode = blend_mode});
2227 canvas.DrawRect(
Rect::MakeXYWH(50, 50, 100, 100), {.color = color});
2234 canvas.Translate(
Vector2(100, 0));
2236 canvas.RestoreToCount(0);
2243 canvas.Translate({0, 100});
2247 canvas.SaveLayer({});
2249 for (
const auto& color : source_colors) {
2252 {.color = destination_color.
Blend(color, blend_mode),
2254 canvas.Translate(
Vector2(100, 0));
2256 canvas.RestoreToCount(0);
2270 canvas.DrawImage(src_image, {400, 50}, {.blend_mode = blend_mode});
2272 canvas.RestoreToCount(0);
2274 return canvas.EndRecordingAsPicture();
2277 #define BLEND_MODE_TEST(blend_mode) \
2278 TEST_P(AiksTest, BlendMode##blend_mode) { \
2279 auto src_image = std::make_shared<Image>( \
2280 CreateTextureForFixture("blend_mode_src.png")); \
2281 auto dst_image = std::make_shared<Image>( \
2282 CreateTextureForFixture("blend_mode_dst.png")); \
2283 OpenPlaygroundHere( \
2284 BlendModeTest(BlendMode::k##blend_mode, src_image, dst_image)); \
2352 canvas.
Scale(GetContentScale());
2354 auto test = [&canvas](
const std::shared_ptr<ImageFilter>& filter) {
2355 auto DrawLine = [&canvas](
const Point& p0,
const Point& p1,
2363 canvas.
DrawPath(std::move(path), paint);
2371 canvas.
SaveLayer({.image_filter = filter},
2398 auto rotate_filter =
2403 test(rotate_filter);
2414 test(rgb_swap_filter);
2441 canvas.
Scale(GetContentScale());
2447 canvas.
SaveLayer({.image_filter = blur_filter}, std::nullopt);
2464 auto image = std::make_shared<Image>(CreateTextureForFixture(
"airplane.jpg"));
2465 canvas.
DrawImage(image, {100, 100}, {});
2468 canvas.
DrawImage(image, {100, 500}, {});
2477 auto image = std::make_shared<Image>(CreateTextureForFixture(
"airplane.jpg"));
2478 canvas.
DrawImage(image, {100, 100}, {});
2490 canvas.
DrawImage(image, {100, 500}, {});
2499 auto image = std::make_shared<Image>(CreateTextureForFixture(
"airplane.jpg"));
2500 canvas.
DrawImage(image, {100, 100}, {});
2513 canvas.
DrawImage(image, {100, 500}, {});
2520 TranslucentSaveLayerWithColorFilterAndImageFilterDrawsCorrectly) {
2523 auto image = std::make_shared<Image>(CreateTextureForFixture(
"airplane.jpg"));
2524 canvas.
DrawImage(image, {100, 100}, {});
2539 canvas.
DrawImage(image, {100, 500}, {});
2613 std::vector<Entity> entity;
2614 std::shared_ptr<SolidColorContents> contents;
2615 picture.
pass->IterateAllEntities([e = &entity, &contents](
Entity& entity) {
2618 std::static_pointer_cast<SolidColorContents>(entity.
GetContents());
2619 e->emplace_back(entity.
Clone());
2625 ASSERT_TRUE(entity.size() >= 1);
2626 ASSERT_TRUE(contents->IsOpaque());
2650 .sigma =
Sigma(99999),
2658 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
2677 ASSERT_TRUE(OpenPlaygroundHere(callback));
2734 .mask_blur_descriptor =
2755 .mask_blur_descriptor =
2768 if (!BackendSupportsFragmentProgram()) {
2769 GTEST_SKIP_(
"This backend doesn't support runtime effects.");
2772 auto runtime_stages =
2773 OpenAssetAsRuntimeStage(
"runtime_stage_example.frag.iplr");
2775 auto runtime_stage =
2777 ASSERT_TRUE(runtime_stage);
2778 ASSERT_TRUE(runtime_stage->IsDirty());
2780 struct FragUniforms {
2783 } frag_uniforms = {.iResolution =
Vector2(400, 400), .iTime = 100.0};
2784 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
2785 uniform_data->resize(
sizeof(FragUniforms));
2786 memcpy(uniform_data->data(), &frag_uniforms,
sizeof(FragUniforms));
2788 std::vector<RuntimeEffectContents::TextureInput> texture_inputs;
2792 runtime_stage, uniform_data, texture_inputs);
2805 if (!BackendSupportsFragmentProgram()) {
2806 GTEST_SKIP_(
"This backend doesn't support runtime effects.");
2809 auto runtime_stages = OpenAssetAsRuntimeStage(
"gradient.frag.iplr");
2811 ASSERT_TRUE(runtime_stage);
2812 ASSERT_TRUE(runtime_stage->IsDirty());
2814 struct FragUniforms {
2817 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
2818 uniform_data->resize(
sizeof(FragUniforms));
2819 memcpy(uniform_data->data(), &frag_uniforms,
sizeof(FragUniforms));
2821 std::vector<RuntimeEffectContents::TextureInput> texture_inputs;
2825 runtime_stage, uniform_data, texture_inputs);
2829 canvas.
Scale(GetContentScale());
2837 std::vector<Point> points = {
2846 std::vector<PointStyle> caps = {
2869 auto atlas = CreateTextureForFixture(
"bay_bridge.jpg");
2870 auto size = atlas->GetSize();
2871 auto image = std::make_shared<Image>(atlas);
2873 Scalar half_width = size.width / 2;
2874 Scalar half_height = size.height / 2;
2875 std::vector<Rect> texture_coordinates = {
2879 Rect::MakeLTRB(half_width, half_height, size.width, size.height)};
2881 std::vector<Matrix> transforms = {
2892 canvas.
Scale({0.25, 0.25, 1.0});
2893 canvas.
DrawAtlas(image, transforms, texture_coordinates, colors,
2902 auto atlas = CreateTextureForFixture(
"bay_bridge.jpg");
2903 auto size = atlas->GetSize();
2904 auto image = std::make_shared<Image>(atlas);
2906 Scalar half_width = size.width / 2;
2907 Scalar half_height = size.height / 2;
2908 std::vector<Rect> texture_coordinates = {
2912 Rect::MakeLTRB(half_width, half_height, size.width, size.height)};
2914 std::vector<Matrix> transforms = {
2923 canvas.
Scale({0.25, 0.25, 1.0});
2924 canvas.
DrawAtlas(image, transforms, texture_coordinates, {},
2931 auto texture = CreateTextureForFixture(
"table_mountain_nx.png",
2934 std::vector<Point> points = {
2943 std::vector<PointStyle> caps = {
2954 canvas.Translate({150, 0});
2957 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
2964 auto mapping = flutter::testing::OpenFixtureAsSkData(
"Roboto-Regular.ttf");
2965 ASSERT_NE(mapping,
nullptr);
2968 sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
2969 SkFont sk_font(font_mgr->makeFromData(mapping), font_size);
2974 std::vector<Color> colors = {
Color{0.9568, 0.2627, 0.2118, 1.0},
2975 Color{0.1294, 0.5882, 0.9529, 1.0}};
2976 std::vector<Scalar> stops = {
2981 {0, 0}, {100, 100}, std::move(colors), std::move(stops),
2988 auto blob = SkTextBlob::MakeFromString(
"Hello", sk_font);
2989 ASSERT_NE(blob,
nullptr);
2991 canvas.DrawTextFrame(frame,
Point(), text_paint);
2993 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
3031 auto image = std::make_shared<Image>(CreateTextureForFixture(
"kalimba.jpg"));
3049 GetContext(), subcanvas,
3050 "the quick brown fox jumped over the lazy dog!.?",
"Roboto-Regular.ttf"));
3054 GetContext(), subcanvas,
3055 "the quick brown fox jumped over the very big lazy dog!.?",
3056 "Roboto-Regular.ttf"));
3069 GetContext(), canvas,
3070 "the quick brown fox jumped over the smaller lazy dog!.?",
3071 "Roboto-Regular.ttf"));
3149 auto result = contents.ApplyColorFilter([](
const Color& color) {
3152 ASSERT_TRUE(result);
3154 Color(0.433247, 0.879523, 0.825324, 0.75));
3161 2.000000, 0.000000, 0.000000, 0.000000,
3162 1.445767, 2.637070, -0.507928, 0.001524,
3163 -2.451887, -0.534662, 0.861399, -0.002584,
3164 1063.481934, 1025.951416, -48.300270, 1.144901
3169 "Roboto-Regular.ttf"));
3180 2.000000, 0.000000, 0.000000, 0.000000,
3181 1.445767, 2.637070, -0.507928, 0.001524,
3182 -2.451887, -0.534662, 0.861399, -0.002584,
3183 1063.481934, 1025.951416, -48.300270, 1.144901
3188 "Roboto-Regular.ttf"));
3215 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
3223 .sigma =
Radius{120 * 3},
3228 canvas.
DrawPath(builder.TakePath(), paint);
3231 ASSERT_TRUE(OpenPlaygroundHere(callback));
3240 .sigma =
Radius{120 * 3},
3245 canvas.
DrawPath(builder.TakePath(), paint);
3252 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
3255 capture_context.Rewind();
3256 auto document = capture_context.GetDocument(
"TestDocument");
3261 ImGui::Begin(
"TestDocument",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
3262 document.GetElement()->properties.Iterate([](
CaptureProperty& property) {
3263 property.Invoke({.color = [](CaptureColorProperty& p) {
3264 ImGui::ColorEdit4(p.label.c_str(),
reinterpret_cast<float*
>(&p.value));
3271 OpenPlaygroundHere(callback);
3275 ASSERT_FALSE(GetContext()->capture.IsActive());
3280 auto context = GetContext();
3281 std::weak_ptr<Texture> weak_texture;
3284 auto texture = CreateTextureForFixture(
"table_mountain_nx.png");
3287 canvas.
Scale(GetContentScale());
3303 context->Shutdown();
3306 ASSERT_TRUE(weak_texture.expired()) <<
"When the texture is no longer in use "
3307 "by the backend, it should be "
3315 auto texture = CreateTextureForFixture(
"table_mountain_nx.png");
3320 auto vertices = {
Point(0, 0),
Point(texture->GetSize().width, 0),
3321 Point(0, texture->GetSize().height)};
3322 std::vector<uint16_t> indices = {0u, 1u, 2u};
3323 std::vector<Point> texture_coordinates = {};
3324 std::vector<Color> vertex_colors = {};
3325 auto geometry = std::make_shared<VerticesGeometry>(
3326 vertices, indices, texture_coordinates, vertex_colors,
3337 auto texture = CreateTextureForFixture(
"table_mountain_nx.png");
3343 auto vertices = {
Point(0, 0),
Point(texture->GetSize().width, 0),
3344 Point(0, texture->GetSize().height)};
3345 std::vector<uint16_t> indices = {0u, 1u, 2u};
3346 std::vector<Point> texture_coordinates = {};
3347 std::vector<Color> vertex_colors = {};
3348 auto geometry = std::make_shared<VerticesGeometry>(
3349 vertices, indices, texture_coordinates, vertex_colors,
3388 canvas.
Scale(GetContentScale());
3389 auto image = std::make_shared<Image>(CreateTextureForFixture(
"airplane.jpg"));
3392 .image_filter = std::make_shared<MatrixImageFilter>(
3405 canvas.
Scale(GetContentScale());
3410 .image_filter = std::make_shared<MatrixImageFilter>(
3421 MatrixImageFilterDoesntCullWhenScaledAndTranslatedFromOffscreen) {
3423 canvas.
Scale(GetContentScale());
3428 .image_filter = std::make_shared<MatrixImageFilter>(
3440 SetWindowSize({400, 400});
3442 canvas.
Scale(GetContentScale());
3445 .image_filter = std::make_shared<MatrixImageFilter>(
3455 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
3460 canvas.
Scale(GetContentScale());
3464 .mask_blur_descriptor =
3467 .sigma =
Sigma(47.6),
3476 canvas.
Scale(GetContentScale());
3486 canvas.
Scale(GetContentScale());
3487 auto image = std::make_shared<Image>(CreateTextureForFixture(
"airplane.jpg"));
3497 canvas.
Scale(GetContentScale());
3500 auto draw_line = [&canvas, &paint](
Point a,
Point b) {
3505 draw_line(
Point(dx + 100, dy + 100),
Point(dx + 200, dy + 200));
3506 draw_line(
Point(dx + 100, dy + 200),
Point(dx + 200, dy + 100));
3507 draw_line(
Point(dx + 150, dy + 100),
Point(dx + 200, dy + 150));
3508 draw_line(
Point(dx + 100, dy + 150),
Point(dx + 150, dy + 200));
3513 for (
int x = 0; x < 5; ++x) {
3514 for (
int y = 0; y < 5; ++y) {
3518 recorder_canvas.
DrawRect(rect, paint);
3522 std::shared_ptr<Texture> texture =
3523 picture.
ToImage(renderer,
ISize{100, 100})->GetTexture();
3540 paint_lines(300, 300,
3550 .mask_blur_descriptor =
3566 canvas.
Scale(GetContentScale());
3584 canvas.
Scale(GetContentScale());
3585 std::shared_ptr<Texture> boston = CreateTextureForFixture(
"boston.jpg");
3587 std::make_shared<Image>(boston),
3588 Rect::MakeXYWH(0, 0, boston->GetSize().width, boston->GetSize().height),
3601 #define FLT_FORWARD(mock, real, method) \
3602 EXPECT_CALL(*mock, method()) \
3603 .WillRepeatedly(::testing::Return(real->method()));
3608 "This backend doesn't yet support setting device capabilities.");
3610 if (!WillRenderSomething()) {
3614 GTEST_SKIP_(
"This test requires playgrounds.");
3617 std::shared_ptr<const Capabilities> old_capabilities =
3618 GetContext()->GetCapabilities();
3619 auto mock_capabilities = std::make_shared<MockCapabilities>();
3620 EXPECT_CALL(*mock_capabilities, SupportsDecalSamplerAddressMode())
3621 .Times(::testing::AtLeast(1))
3622 .WillRepeatedly(::testing::Return(
false));
3623 FLT_FORWARD(mock_capabilities, old_capabilities, GetDefaultColorFormat);
3624 FLT_FORWARD(mock_capabilities, old_capabilities, GetDefaultStencilFormat);
3625 FLT_FORWARD(mock_capabilities, old_capabilities, SupportsOffscreenMSAA);
3627 SupportsImplicitResolvingMSAA);
3628 FLT_FORWARD(mock_capabilities, old_capabilities, SupportsReadFromResolve);
3629 FLT_FORWARD(mock_capabilities, old_capabilities, SupportsFramebufferFetch);
3630 FLT_FORWARD(mock_capabilities, old_capabilities, SupportsSSBO);
3631 FLT_FORWARD(mock_capabilities, old_capabilities, SupportsCompute);
3633 SupportsTextureToTextureBlits);
3634 ASSERT_TRUE(SetCapabilities(mock_capabilities).ok());
3636 auto texture = std::make_shared<Image>(CreateTextureForFixture(
"boston.jpg"));
3638 canvas.
Scale(GetContentScale() * 0.5);
3641 texture,
Point(200, 200),
3653 canvas.
Scale(GetContentScale());
3654 canvas.
Scale({0.5, 0.5, 1.0});
3655 std::shared_ptr<Texture> boston = CreateTextureForFixture(
"boston.jpg");
3671 std::shared_ptr<Texture> boston = CreateTextureForFixture(
"boston.jpg");
3673 Rect::MakeXYWH(0, 0, boston->GetSize().width, boston->GetSize().height);
3679 Vector2 clip_size = {150, 75};
3681 canvas.
Scale(GetContentScale());
3685 canvas.
Scale({0.6, 0.6, 1});
3688 canvas.
DrawImageRect(std::make_shared<Image>(boston), bounds,
3689 bounds.
Shift(-image_center), paint);
3696 std::shared_ptr<Texture> boston = CreateTextureForFixture(
"boston.jpg");
3698 Rect::MakeXYWH(0, 0, boston->GetSize().width, boston->GetSize().height);
3704 Vector2 clip_size = {150, 75};
3706 canvas.
Scale(GetContentScale());
3710 canvas.
Scale({0.6, 0.6, 1});
3712 canvas.
DrawImageRect(std::make_shared<Image>(boston), bounds,
3713 bounds.
Shift(-image_center), paint);
3719 std::shared_ptr<Texture> boston = CreateTextureForFixture(
"boston.jpg");
3721 auto callback = [&](
AiksContext& renderer) -> std::optional<Picture> {
3722 const char* tile_mode_names[] = {
"Clamp",
"Repeat",
"Mirror",
"Decal"};
3727 static float rotation = 0;
3728 static float scale = 0.6;
3729 static int selected_tile_mode = 3;
3731 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
3733 ImGui::SliderFloat(
"Rotation (degrees)", &rotation, -180, 180);
3734 ImGui::SliderFloat(
"Scale", &scale, 0, 2.0);
3735 ImGui::Combo(
"Tile mode", &selected_tile_mode, tile_mode_names,
3736 sizeof(tile_mode_names) /
sizeof(
char*));
3742 Rect::MakeXYWH(0, 0, boston->GetSize().width, boston->GetSize().height);
3747 tile_modes[selected_tile_mode])};
3751 canvas.
Scale(GetContentScale());
3755 canvas.
Scale({scale, scale, 1});
3758 canvas.
DrawImageRect(std::make_shared<Image>(boston), bounds,
3759 bounds.
Shift(-image_center), paint);
3763 ASSERT_TRUE(OpenPlaygroundHere(callback));