7 #include "display_list/dl_color.h"
8 #include "display_list/dl_paint.h"
9 #include "display_list/geometry/dl_geometry_types.h"
10 #include "display_list/geometry/dl_path_builder.h"
11 #include "flutter/display_list/dl_builder.h"
12 #include "flutter/impeller/display_list/testing/render_text_in_canvas.h"
13 #include "flutter/impeller/display_list/testing/rmse.h"
14 #include "flutter/testing/testing.h"
15 #include "gtest/gtest.h"
30 auto draw = [](DlCanvas* canvas,
31 const std::vector<std::unique_ptr<DlImage>>& images) {
32 canvas->Scale(0.2, 0.2);
34 paint.setColor(DlColor::kCyan());
35 canvas->DrawPaint(paint);
38 DisplayListBuilder builder;
41 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
45 auto draw = [](DlCanvas* canvas,
const std::vector<sk_sp<DlImage>>& images) {
46 FML_CHECK(images.size() >= 1);
48 paint.setColor(DlColor::kRed());
49 canvas->DrawImage(images[0],
DlPoint(100.0, 100.0),
50 DlImageSampling::kLinear, &paint);
53 DisplayListBuilder builder;
54 std::vector<sk_sp<DlImage>> images;
55 images.emplace_back(CreateDlImageForFixture(
"kalimba.jpg"));
56 draw(&builder, images);
58 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
64 Point content_scale = GetContentScale();
65 auto draw = [content_scale](DlCanvas* canvas,
66 const std::vector<sk_sp<DlImage>>& images) {
67 canvas->Scale(content_scale.x, content_scale.y);
69 paint.setColor(DlColor(0xfffef7ff));
70 canvas->DrawRect(DlRect::MakeLTRB(0, 0, 375, 667), paint);
71 paint.setColor(DlColor(0xffff9800));
72 canvas->DrawRect(DlRect::MakeLTRB(0, 0, 187.5, 333.5), paint);
73 paint.setColor(DlColor(0xff9c27b0));
74 canvas->DrawRect(DlRect::MakeLTRB(187.5, 0, 375, 333.5), paint);
75 paint.setColor(DlColor(0xff4caf50));
76 canvas->DrawRect(DlRect::MakeLTRB(0, 333.5, 187.5, 667), paint);
77 paint.setColor(DlColor(0xfff44336));
78 canvas->DrawRect(DlRect::MakeLTRB(187.5, 333.5, 375, 667), paint);
82 canvas->ClipRoundRect(
83 DlRoundRect::MakeOval(DlRect::MakeLTRB(201.25, 10, 361.25, 170)),
84 DlClipOp::kIntersect,
true);
85 DlRect save_layer_bounds = DlRect::MakeLTRB(201.25, 10, 361.25, 170);
87 DlImageFilter::MakeMatrix(DlMatrix::MakeRow(3, 0, 0.0, -280,
91 DlImageSampling::kLinear);
92 canvas->SaveLayer(save_layer_bounds,
nullptr, backdrop.get());
94 canvas->Translate(201.25, 10);
95 auto paint = DlPaint()
97 .setColor(DlColor(0xff2196f3))
99 .setDrawStyle(DlDrawStyle::kStroke);
100 canvas->DrawCircle(
DlPoint(80, 80), 80, paint);
107 DisplayListBuilder builder;
108 std::vector<sk_sp<DlImage>> images;
109 draw(&builder, images);
111 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
115 void DrawBlurGrid(DlCanvas* canvas) {
117 paint.setColor(DlColor(0xfffef7ff));
121 std::vector<Scalar> blur_radii = {10, 30, 50};
122 for (
size_t i = 0; i < blur_radii.size(); ++i) {
124 auto blur_filter = std::make_shared<flutter::DlBlurMaskFilter>(
126 paint.setMaskFilter(blur_filter);
127 Scalar yval = gap + i * (gap + height);
128 canvas->DrawRoundRect(
129 DlRoundRect::MakeNinePatch(DlRect::MakeXYWH(gap, yval, width, height),
132 canvas->DrawRoundRect(
133 DlRoundRect::MakeNinePatch(
134 DlRect::MakeXYWH(2.0 * gap + width, yval, width, height),
142 Point content_scale = GetContentScale();
143 auto draw = [content_scale](DlCanvas* canvas,
144 const std::vector<sk_sp<DlImage>>& images) {
145 canvas->Scale(content_scale.x, content_scale.y);
146 canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233)));
147 DrawBlurGrid(canvas);
150 DisplayListBuilder builder;
151 std::vector<sk_sp<DlImage>> images;
152 draw(&builder, images);
154 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
158 Point content_scale = GetContentScale();
159 auto draw = [content_scale](DlCanvas* canvas,
160 const std::vector<sk_sp<DlImage>>& images) {
161 canvas->Scale(content_scale.x, content_scale.y);
162 canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233)));
163 canvas->Scale(0.33, 0.33);
164 DrawBlurGrid(canvas);
167 DisplayListBuilder builder;
168 std::vector<sk_sp<DlImage>> images;
169 draw(&builder, images);
171 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
175 Point content_scale = GetContentScale();
176 auto draw = [content_scale](DlCanvas* canvas,
177 const std::vector<sk_sp<DlImage>>& images) {
178 canvas->Scale(content_scale.x, content_scale.y);
179 canvas->Translate(200, 200);
180 canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233)));
181 canvas->Scale(0.33, 0.33);
182 canvas->Translate(300, 300);
184 canvas->Translate(-300, -300);
185 DrawBlurGrid(canvas);
188 DisplayListBuilder builder;
189 std::vector<sk_sp<DlImage>> images;
190 draw(&builder, images);
192 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
196 DisplayListBuilder builder;
197 builder.Scale(GetContentScale().
x, GetContentScale().y);
198 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
200 auto blur_sigmas = std::array{5.0f, 10.0f, 20.0f};
201 auto blur_colors = std::array{
209 auto add_corner = [](DlPathBuilder& path_builder,
DlPoint corner,
210 DlVector2 relative_from, DlVector2 relative_to,
212 static const auto magic = DlPathBuilder::kArcApproximationMagic;
215 path_builder.MoveTo(corner + relative_from);
217 path_builder.LineTo(corner + relative_from);
225 path_builder.CubicCurveTo(corner + relative_from * magic,
226 corner + relative_to * magic,
227 corner + relative_to);
230 DlPathBuilder path_builder;
231 add_corner(path_builder, rect.GetRightTop(),
232 DlVector2(-rx, 0.0f), DlVector2(0.0f, ry),
true);
233 add_corner(path_builder, rect.GetRightBottom(),
234 DlVector2(0.0f, -ry), DlVector2(-rx, 0.0f),
false);
235 add_corner(path_builder, rect.GetLeftBottom(),
236 DlVector2(rx, 0.0f), DlVector2(0.0f, -ry),
false);
237 add_corner(path_builder, rect.GetLeftTop(),
238 DlVector2(0.0f, ry), DlVector2(rx, 0.0f),
false);
239 return path_builder.TakePath();
242 for (
size_t i = 0; i < blur_sigmas.size(); i++) {
243 auto rect = DlRect::MakeXYWH(i * 320.0f + 50.0f, 50.0f, 100.0f, 100.0f);
244 DlPaint paint = DlPaint()
245 .setColor(blur_colors[i])
246 .setMaskFilter(DlBlurMaskFilter::Make(
247 DlBlurStyle::kNormal, blur_sigmas[i]));
249 builder.DrawRoundRect(DlRoundRect::MakeRectXY(rect, 10.0f, 10.0f), paint);
250 rect = rect.Shift(150.0f, 0.0f);
251 builder.DrawPath(make_rrect_path(rect, 10.0f, 10.0f), paint);
252 rect = rect.Shift(-150.0f, 0.0f);
254 rect = rect.Shift(0.0f, 200.0f);
255 builder.DrawRoundRect(DlRoundRect::MakeRectXY(rect, 10.0f, 30.0f), paint);
256 rect = rect.Shift(150.0f, 0.0f);
257 builder.DrawPath(make_rrect_path(rect, 10.0f, 20.0f), paint);
258 rect = rect.Shift(-150.0f, 0.0f);
260 rect = rect.Shift(0.0f, 200.0f);
261 builder.DrawRoundRect(DlRoundRect::MakeRectXY(rect, 30.0f, 10.0f), paint);
262 rect = rect.Shift(150.0f, 0.0f);
263 builder.DrawPath(make_rrect_path(rect, 20.0f, 10.0f), paint);
264 rect = rect.Shift(-150.0f, 0.0f);
267 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
271 Point content_scale = GetContentScale();
272 auto draw = [content_scale](DlCanvas* canvas,
273 const std::vector<sk_sp<DlImage>>& images) {
274 canvas->Scale(content_scale.x, content_scale.y);
275 canvas->DrawPaint(DlPaint().setColor(DlColor::kWhite()));
277 auto draw_one = [canvas](DlStrokeCap cap,
Scalar x,
Scalar y,
282 DlPaint thick_paint = DlPaint()
283 .setColor(DlColor::kBlue())
285 .setStrokeWidth(8.0f);
286 DlPaint middle_paint = DlPaint()
287 .setColor(DlColor::kGreen())
289 .setStrokeWidth(5.0f);
290 DlPaint thin_paint = DlPaint()
291 .setColor(DlColor::kMagenta())
293 .setStrokeWidth(2.0f);
294 for (
int degrees = 0; degrees < 360; degrees += 30) {
296 canvas->DrawDashedLine(center + inner * delta, center + outer * delta,
297 dash_on, dash_off, thick_paint);
298 canvas->DrawDashedLine(center + inner * delta, center + outer * delta,
299 dash_on, dash_off, middle_paint);
300 canvas->DrawDashedLine(center + inner * delta, center + outer * delta,
301 dash_on, dash_off, thin_paint);
305 draw_one(DlStrokeCap::kButt, 150.0f, 150.0f, 15.0f, 10.0f);
306 draw_one(DlStrokeCap::kSquare, 400.0f, 150.0f, 15.0f, 10.0f);
307 draw_one(DlStrokeCap::kRound, 150.0f, 400.0f, 15.0f, 10.0f);
308 draw_one(DlStrokeCap::kRound, 400.0f, 400.0f, 0.0f, 11.0f);
312 DlPathBuilder path_builder;
313 path_builder.MoveTo(
DlPoint(275.0f, 225.0f));
314 path_builder.LineTo(
DlPoint(325.0f, 275.0f));
315 path_builder.LineTo(
DlPoint(275.0f, 325.0f));
316 path_builder.LineTo(
DlPoint(225.0f, 275.0f));
317 canvas->ClipPath(path_builder.TakePath());
318 canvas->DrawColor(DlColor::kYellow());
319 draw_one(DlStrokeCap::kRound, 275.0f, 275.0f, 15.0f, 10.0f);
323 DisplayListBuilder builder;
324 std::vector<sk_sp<DlImage>> images;
325 draw(&builder, images);
327 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
334 DisplayListBuilder builder;
335 builder.DrawPaint(DlPaint().setColor(DlColor::kWhite()));
336 auto save_paint = DlPaint().setAlpha(100);
337 builder.SaveLayer(std::nullopt, &save_paint);
339 builder.DrawRoundRect(DlRoundRect::MakeRectRadius(
340 DlRect::MakeLTRB(10.5, 10.5, 200.5, 200.5), 10),
342 .setDrawStyle(DlDrawStyle::kStroke)
344 .setColor(DlColor::kBlack()));
345 builder.DrawCircle(DlPoint::MakeXY(100, 100), 50.5,
346 DlPaint().setColor(DlColor::kAqua()));
347 builder.DrawCircle(DlPoint::MakeXY(110, 110), 50.5,
348 DlPaint().setColor(DlColor::kCyan()));
352 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
357 const uint32_t* ptr =
reinterpret_cast<const uint32_t*
>(img->
GetBytes());
359 for (uint32_t i = 0; i < img->
GetHeight(); ++i) {
360 for (uint32_t j = 0; j < img->
GetWidth(); ++j) {
361 uint32_t pixel = *ptr++;
362 if ((pixel & 0x00ffffff) != 0) {
363 max_y = std::max(max_y,
static_cast<int32_t
>(i));
371 const uint32_t* ptr =
reinterpret_cast<const uint32_t*
>(img->
GetBytes());
373 std::vector<size_t> boundaries;
374 uint32_t
value = *ptr++;
375 for (
size_t i = 1; i < img->
GetWidth(); ++i) {
376 if (((*ptr & 0x00ffffff) != 0) != ((
value & 0x00ffffff) != 0)) {
377 boundaries.push_back(i);
382 assert(boundaries.size() == 6);
383 return boundaries[4] - boundaries[3];
390 auto callback = [&](
const char* text,
392 DisplayListBuilder builder;
394 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
395 builder.DrawPaint(paint);
396 builder.Scale(scale, scale);
398 DlPoint::MakeXY(10, 300),
402 return builder.Build();
405 std::unique_ptr<impeller::testing::Screenshot> right =
406 MakeScreenshot(callback(
"h", 0.444));
408 GTEST_SKIP() <<
"making screenshots not supported.";
410 std::unique_ptr<impeller::testing::Screenshot> left =
411 MakeScreenshot(callback(
"e", 0.444));
413 int32_t left_max_y = CalculateMaxY(left.get());
414 int32_t right_max_y = CalculateMaxY(right.get());
415 int32_t y_diff = std::abs(left_max_y - right_max_y);
416 EXPECT_TRUE(y_diff <= 2) <<
"y diff: " << y_diff;
422 auto callback = [&](
const char* text,
424 DisplayListBuilder builder;
426 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
427 builder.DrawPaint(paint);
428 builder.Scale(scale, scale);
430 DlPoint::MakeXY(10, 300),
434 return builder.Build();
437 std::optional<int32_t> last_space;
438 for (
int i = 0; i <= 100; ++i) {
439 Scalar scale = 0.440 + i / 1000.0;
440 std::unique_ptr<impeller::testing::Screenshot> right =
441 MakeScreenshot(callback(
"ui", scale));
443 GTEST_SKIP() <<
"making screenshots not supported.";
446 int32_t space = CalculateSpaceBetweenUI(right.get());
447 if (last_space.has_value()) {
448 int32_t diff = abs(space - *last_space);
449 EXPECT_TRUE(diff <= 1)
450 <<
"i:" << i <<
" space:" << space <<
" last_space:" << *last_space;
457 struct LeftmostIntensity {
464 LeftmostIntensity CalculateLeftmostIntensity(
466 LeftmostIntensity result = {.x =
static_cast<int32_t
>(img->
GetWidth()),
468 const uint32_t* ptr =
reinterpret_cast<const uint32_t*
>(img->
GetBytes());
469 for (
size_t i = 0; i < img->
GetHeight(); ++i) {
470 for (int32_t j = 0; j < static_cast<int32_t>(img->
GetWidth()); ++j) {
471 if (((*ptr & 0x00ffffff) != 0)) {
474 result.value = (*ptr & 0xff00) >> 8;
475 }
else if (j == result.x) {
477 std::max(
static_cast<int32_t
>(*ptr & 0xff), result.value);
492 auto callback = [&](
Scalar offset_x) -> sk_sp<DisplayList> {
493 DisplayListBuilder builder;
495 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
496 builder.DrawPaint(paint);
498 DlPoint::MakeXY(offset_x, 180),
503 return builder.Build();
506 LeftmostIntensity intensity[5];
507 for (
int i = 0; i <= 4; ++i) {
508 Scalar offset = 10 + (i / 4.0);
509 std::unique_ptr<impeller::testing::Screenshot> right =
510 MakeScreenshot(callback(offset));
512 GTEST_SKIP() <<
"making screenshots not supported.";
514 intensity[i] = CalculateLeftmostIntensity(right.get());
515 ASSERT_NE(intensity[i].
value, 0);
517 for (
int i = 1; i < 5; ++i) {
518 EXPECT_TRUE(intensity[i].
x - intensity[i - 1].
x == 1 ||
522 EXPECT_EQ(intensity[4].
x - intensity[0].
x, 1);
531 auto callback = [&](
Scalar offset_x) -> sk_sp<DisplayList> {
532 DisplayListBuilder builder;
533 builder.Scale(scalar, scalar);
535 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
536 builder.DrawPaint(paint);
538 DlPoint::MakeXY(offset_x, 180),
543 return builder.Build();
546 LeftmostIntensity intensity[5];
547 Scalar offset_fraction = 0.25 / scalar;
548 for (
int i = 0; i <= 4; ++i) {
549 Scalar offset = 10 + (offset_fraction * i);
550 std::unique_ptr<impeller::testing::Screenshot> right =
551 MakeScreenshot(callback(offset));
553 GTEST_SKIP() <<
"making screenshots not supported.";
555 intensity[i] = CalculateLeftmostIntensity(right.get());
556 ASSERT_NE(intensity[i].
value, 0);
558 for (
int i = 1; i < 5; ++i) {
559 EXPECT_TRUE(intensity[i].
x - intensity[i - 1].
x == 1 ||
563 EXPECT_EQ(intensity[4].
x - intensity[0].
x, 1);
572 auto callback = [&](
Scalar offset_x) -> sk_sp<DisplayList> {
573 DisplayListBuilder builder;
574 builder.Scale(scalar, scalar);
576 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
577 builder.DrawPaint(paint);
578 builder.Translate(offset_x, 180);
580 DlPoint::MakeXY(0, 0),
585 return builder.Build();
588 LeftmostIntensity intensity[5];
589 Scalar offset_fraction = 0.25 / scalar;
590 for (
int i = 0; i <= 4; ++i) {
591 Scalar offset = 10 + (offset_fraction * i);
592 std::unique_ptr<impeller::testing::Screenshot> right =
593 MakeScreenshot(callback(offset));
595 GTEST_SKIP() <<
"making screenshots not supported.";
597 intensity[i] = CalculateLeftmostIntensity(right.get());
598 ASSERT_NE(intensity[i].
value, 0);
600 for (
int i = 1; i < 5; ++i) {
601 EXPECT_TRUE(intensity[i].
x - intensity[i - 1].
x == 1 ||
605 EXPECT_EQ(intensity[4].
x - intensity[0].
x, 1);
virtual size_t GetHeight() const =0
Returns the height of the image in pixels.
virtual const uint8_t * GetBytes() const =0
Access raw data of the screenshot.
virtual size_t GetWidth() const =0
Returns the width of the image in pixels.
Vector2 blur_radius
Blur radius in source pixels based on scaled_sigma.
TEST_P(DlGoldenTest, TextBlurMaskFilterRespectCTM)
INSTANTIATE_PLAYGROUND_SUITE(DlGoldenTest)
bool RenderTextInCanvasSkia(const std::shared_ptr< Context > &context, DisplayListBuilder &canvas, const std::string &text, const std::string_view &font_fixture, const TextRenderOptions &options={}, const std::optional< SkFont > &font=std::nullopt)
flutter::DlScalar DlScalar
constexpr TPoint Rotate(const Radians &angle) const