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 "flutter/display_list/dl_builder.h"
11 #include "flutter/impeller/display_list/testing/render_text_in_canvas.h"
12 #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], SkPoint::Make(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(SkRect::MakeLTRB(0, 0, 375, 667), paint);
71 paint.setColor(DlColor(0xffff9800));
72 canvas->DrawRect(SkRect::MakeLTRB(0, 0, 187.5, 333.5), paint);
73 paint.setColor(DlColor(0xff9c27b0));
74 canvas->DrawRect(SkRect::MakeLTRB(187.5, 0, 375, 333.5), paint);
75 paint.setColor(DlColor(0xff4caf50));
76 canvas->DrawRect(SkRect::MakeLTRB(0, 333.5, 187.5, 667), paint);
77 paint.setColor(DlColor(0xfff44336));
78 canvas->DrawRect(SkRect::MakeLTRB(187.5, 333.5, 375, 667), paint);
83 SkRRect::MakeOval(SkRect::MakeLTRB(201.25, 10, 361.25, 170)),
84 DlCanvas::ClipOp::kIntersect,
true);
85 SkRect save_layer_bounds = SkRect::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(SkPoint::Make(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);
128 Scalar yval = gap + i * (gap + height);
129 rrect.setNinePatch(SkRect::MakeXYWH(gap, yval, width, height), 10, 10, 10,
131 canvas->DrawRRect(rrect, paint);
132 rrect.setNinePatch(SkRect::MakeXYWH(2.0 * gap + width, yval, width, height),
134 canvas->DrawRRect(rrect, paint);
140 Point content_scale = GetContentScale();
141 auto draw = [content_scale](DlCanvas* canvas,
142 const std::vector<sk_sp<DlImage>>& images) {
143 canvas->Scale(content_scale.x, content_scale.y);
144 canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233)));
145 DrawBlurGrid(canvas);
148 DisplayListBuilder builder;
149 std::vector<sk_sp<DlImage>> images;
150 draw(&builder, images);
152 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
156 Point content_scale = GetContentScale();
157 auto draw = [content_scale](DlCanvas* canvas,
158 const std::vector<sk_sp<DlImage>>& images) {
159 canvas->Scale(content_scale.x, content_scale.y);
160 canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233)));
161 canvas->Scale(0.33, 0.33);
162 DrawBlurGrid(canvas);
165 DisplayListBuilder builder;
166 std::vector<sk_sp<DlImage>> images;
167 draw(&builder, images);
169 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
173 Point content_scale = GetContentScale();
174 auto draw = [content_scale](DlCanvas* canvas,
175 const std::vector<sk_sp<DlImage>>& images) {
176 canvas->Scale(content_scale.x, content_scale.y);
177 canvas->Translate(200, 200);
178 canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233)));
179 canvas->Scale(0.33, 0.33);
180 canvas->Translate(300, 300);
182 canvas->Translate(-300, -300);
183 DrawBlurGrid(canvas);
186 DisplayListBuilder builder;
187 std::vector<sk_sp<DlImage>> images;
188 draw(&builder, images);
190 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
194 DisplayListBuilder builder;
195 builder.Scale(GetContentScale().
x, GetContentScale().y);
196 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
198 auto blur_sigmas = std::array{5.0f, 10.0f, 20.0f};
199 auto blur_colors = std::array{
205 auto make_rrect_path = [](
const SkRect& rect,
DlScalar rx,
207 auto add_corner = [](SkPath& path, SkPoint rCorner, SkPoint rEnd) {
209 path.rCubicTo(rCorner.fX * (1.0f - magic), rCorner.fY * (1.0f - magic),
210 rCorner.fX + rEnd.fX * magic, rCorner.fY + rEnd.fY * magic,
211 rCorner.fX + rEnd.fX, rCorner.fY + rEnd.fY);
215 path.moveTo(rect.fRight - rx, rect.fTop);
216 add_corner(path, {rx, 0.0f}, {0.0f, ry});
217 path.lineTo(rect.fRight, rect.fBottom - ry);
218 add_corner(path, {0.0f, ry}, {-rx, 0.0f});
219 path.lineTo(rect.fLeft + rx, rect.fBottom);
220 add_corner(path, {-rx, 0.0f}, {0.0f, -ry});
221 path.lineTo(rect.fLeft, rect.fTop + ry);
222 add_corner(path, {0.0f, -ry}, {rx, 0.0f});
227 for (
size_t i = 0; i < blur_sigmas.size(); i++) {
228 auto rect = SkRect::MakeXYWH(i * 320.0f + 50.0f, 50.0f, 100.0f, 100.0f);
229 DlPaint paint = DlPaint()
230 .setColor(blur_colors[i])
231 .setMaskFilter(DlBlurMaskFilter::Make(
232 DlBlurStyle::kNormal, blur_sigmas[i]));
234 builder.DrawRRect(SkRRect::MakeRectXY(rect, 10.0f, 10.0f), paint);
235 rect = rect.makeOffset(150.0f, 0.0f);
236 builder.DrawPath(make_rrect_path(rect, 10.0f, 10.0f), paint);
237 rect = rect.makeOffset(-150.0f, 0.0f);
239 rect = rect.makeOffset(0.0f, 200.0f);
240 builder.DrawRRect(SkRRect::MakeRectXY(rect, 10.0f, 30.0f), paint);
241 rect = rect.makeOffset(150.0f, 0.0f);
242 builder.DrawPath(make_rrect_path(rect, 10.0f, 20.0f), paint);
243 rect = rect.makeOffset(-150.0f, 0.0f);
245 rect = rect.makeOffset(0.0f, 200.0f);
246 builder.DrawRRect(SkRRect::MakeRectXY(rect, 30.0f, 10.0f), paint);
247 rect = rect.makeOffset(150.0f, 0.0f);
248 builder.DrawPath(make_rrect_path(rect, 20.0f, 10.0f), paint);
249 rect = rect.makeOffset(-150.0f, 0.0f);
252 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
256 Point content_scale = GetContentScale();
257 auto draw = [content_scale](DlCanvas* canvas,
258 const std::vector<sk_sp<DlImage>>& images) {
259 canvas->Scale(content_scale.x, content_scale.y);
260 canvas->DrawPaint(DlPaint().setColor(DlColor::kWhite()));
262 auto draw_one = [canvas](DlStrokeCap cap,
Scalar x,
Scalar y,
267 DlPaint thick_paint = DlPaint()
268 .setColor(DlColor::kBlue())
270 .setStrokeWidth(8.0f);
271 DlPaint middle_paint = DlPaint()
272 .setColor(DlColor::kGreen())
274 .setStrokeWidth(5.0f);
275 DlPaint thin_paint = DlPaint()
276 .setColor(DlColor::kMagenta())
278 .setStrokeWidth(2.0f);
279 for (
int degrees = 0; degrees < 360; degrees += 30) {
281 canvas->DrawDashedLine(center + inner * delta, center + outer * delta,
282 dash_on, dash_off, thick_paint);
283 canvas->DrawDashedLine(center + inner * delta, center + outer * delta,
284 dash_on, dash_off, middle_paint);
285 canvas->DrawDashedLine(center + inner * delta, center + outer * delta,
286 dash_on, dash_off, thin_paint);
290 draw_one(DlStrokeCap::kButt, 150.0f, 150.0f, 15.0f, 10.0f);
291 draw_one(DlStrokeCap::kSquare, 400.0f, 150.0f, 15.0f, 10.0f);
292 draw_one(DlStrokeCap::kRound, 150.0f, 400.0f, 15.0f, 10.0f);
293 draw_one(DlStrokeCap::kRound, 400.0f, 400.0f, 0.0f, 11.0f);
297 SkPath clip_path = SkPath();
298 clip_path.moveTo(275.0f, 225.0f);
299 clip_path.lineTo(325.0f, 275.0f);
300 clip_path.lineTo(275.0f, 325.0f);
301 clip_path.lineTo(225.0f, 275.0f);
302 canvas->ClipPath(clip_path);
303 canvas->DrawColor(DlColor::kYellow());
304 draw_one(DlStrokeCap::kRound, 275.0f, 275.0f, 15.0f, 10.0f);
308 DisplayListBuilder builder;
309 std::vector<sk_sp<DlImage>> images;
310 draw(&builder, images);
312 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
319 DisplayListBuilder builder;
320 builder.DrawPaint(DlPaint().setColor(DlColor::kWhite()));
321 auto save_paint = DlPaint().setAlpha(100);
322 builder.SaveLayer(
nullptr, &save_paint);
324 builder.DrawRoundRect(DlRoundRect::MakeRectRadius(
325 DlRect::MakeLTRB(10.5, 10.5, 200.5, 200.5), 10),
327 .setDrawStyle(DlDrawStyle::kStroke)
329 .setColor(DlColor::kBlack()));
330 builder.DrawCircle(DlPoint::MakeXY(100, 100), 50.5,
331 DlPaint().setColor(DlColor::kAqua()));
332 builder.DrawCircle(DlPoint::MakeXY(110, 110), 50.5,
333 DlPaint().setColor(DlColor::kCyan()));
337 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
342 const uint32_t* ptr =
reinterpret_cast<const uint32_t*
>(img->
GetBytes());
344 for (uint32_t i = 0; i < img->
GetHeight(); ++i) {
345 for (uint32_t j = 0; j < img->
GetWidth(); ++j) {
346 uint32_t pixel = *ptr++;
347 if ((pixel & 0x00ffffff) != 0) {
348 max_y = std::max(max_y,
static_cast<int32_t
>(i));
356 const uint32_t* ptr =
reinterpret_cast<const uint32_t*
>(img->
GetBytes());
358 std::vector<size_t> boundaries;
359 uint32_t
value = *ptr++;
360 for (
size_t i = 1; i < img->
GetWidth(); ++i) {
361 if (((*ptr & 0x00ffffff) != 0) != ((
value & 0x00ffffff) != 0)) {
362 boundaries.push_back(i);
367 assert(boundaries.size() == 6);
368 return boundaries[4] - boundaries[3];
375 auto callback = [&](
const char* text,
377 DisplayListBuilder builder;
379 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
380 builder.DrawPaint(paint);
383 DlPoint::MakeXY(10, 300),
385 .font_size = font_size,
387 return builder.Build();
390 std::unique_ptr<impeller::testing::Screenshot> right =
391 MakeScreenshot(callback(
"h", 0.444));
393 GTEST_SKIP() <<
"making screenshots not supported.";
395 std::unique_ptr<impeller::testing::Screenshot> left =
396 MakeScreenshot(callback(
"e", 0.444));
398 int32_t left_max_y = CalculateMaxY(left.get());
399 int32_t right_max_y = CalculateMaxY(right.get());
400 int32_t y_diff = std::abs(left_max_y - right_max_y);
401 EXPECT_TRUE(y_diff <= 2) <<
"y diff: " << y_diff;
407 auto callback = [&](
const char* text,
409 DisplayListBuilder builder;
411 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
412 builder.DrawPaint(paint);
415 DlPoint::MakeXY(10, 300),
417 .font_size = font_size,
419 return builder.Build();
422 std::optional<int32_t> last_space;
423 for (
int i = 0; i <= 100; ++i) {
425 std::unique_ptr<impeller::testing::Screenshot> right =
426 MakeScreenshot(callback(
"ui",
scale));
428 GTEST_SKIP() <<
"making screenshots not supported.";
431 int32_t space = CalculateSpaceBetweenUI(right.get());
432 if (last_space.has_value()) {
433 int32_t diff = abs(space - *last_space);
434 EXPECT_TRUE(diff <= 1)
435 <<
"i:" << i <<
" space:" << space <<
" last_space:" << *last_space;
442 struct LeftmostIntensity {
449 LeftmostIntensity CalculateLeftmostIntensity(
451 LeftmostIntensity result = {.x =
static_cast<int32_t
>(img->
GetWidth()),
453 const uint32_t* ptr =
reinterpret_cast<const uint32_t*
>(img->
GetBytes());
454 for (
size_t i = 0; i < img->
GetHeight(); ++i) {
455 for (int32_t j = 0; j < static_cast<int32_t>(img->
GetWidth()); ++j) {
456 if (((*ptr & 0x00ffffff) != 0)) {
459 result.value = (*ptr & 0xff00) >> 8;
460 }
else if (j == result.x) {
462 std::max(
static_cast<int32_t
>(*ptr & 0xff), result.value);
477 auto callback = [&](
Scalar offset_x) -> sk_sp<DisplayList> {
478 DisplayListBuilder builder;
480 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
481 builder.DrawPaint(paint);
483 DlPoint::MakeXY(offset_x, 180),
485 .font_size = font_size,
488 return builder.Build();
491 LeftmostIntensity intensity[5];
492 for (
int i = 0; i <= 4; ++i) {
494 std::unique_ptr<impeller::testing::Screenshot> right =
495 MakeScreenshot(callback(
offset));
497 GTEST_SKIP() <<
"making screenshots not supported.";
499 intensity[i] = CalculateLeftmostIntensity(right.get());
500 ASSERT_NE(intensity[i].
value, 0);
502 for (
int i = 1; i < 5; ++i) {
503 EXPECT_TRUE(intensity[i].
x - intensity[i - 1].
x == 1 ||
507 EXPECT_EQ(intensity[4].
x - intensity[0].
x, 1);
516 auto callback = [&](
Scalar offset_x) -> sk_sp<DisplayList> {
517 DisplayListBuilder builder;
518 builder.Scale(scalar, scalar);
520 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
521 builder.DrawPaint(paint);
523 DlPoint::MakeXY(offset_x, 180),
525 .font_size = font_size,
528 return builder.Build();
531 LeftmostIntensity intensity[5];
532 Scalar offset_fraction = 0.25 / scalar;
533 for (
int i = 0; i <= 4; ++i) {
535 std::unique_ptr<impeller::testing::Screenshot> right =
536 MakeScreenshot(callback(
offset));
538 GTEST_SKIP() <<
"making screenshots not supported.";
540 intensity[i] = CalculateLeftmostIntensity(right.get());
541 ASSERT_NE(intensity[i].
value, 0);
543 for (
int i = 1; i < 5; ++i) {
544 EXPECT_TRUE(intensity[i].
x - intensity[i - 1].
x == 1 ||
548 EXPECT_EQ(intensity[4].
x - intensity[0].
x, 1);
557 auto callback = [&](
Scalar offset_x) -> sk_sp<DisplayList> {
558 DisplayListBuilder builder;
559 builder.Scale(scalar, scalar);
561 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
562 builder.DrawPaint(paint);
563 builder.Translate(offset_x, 180);
565 DlPoint::MakeXY(0, 0),
567 .font_size = font_size,
570 return builder.Build();
573 LeftmostIntensity intensity[5];
574 Scalar offset_fraction = 0.25 / scalar;
575 for (
int i = 0; i <= 4; ++i) {
577 std::unique_ptr<impeller::testing::Screenshot> right =
578 MakeScreenshot(callback(
offset));
580 GTEST_SKIP() <<
"making screenshots not supported.";
582 intensity[i] = CalculateLeftmostIntensity(right.get());
583 ASSERT_NE(intensity[i].
value, 0);
585 for (
int i = 1; i < 5; ++i) {
586 EXPECT_TRUE(intensity[i].
x - intensity[i - 1].
x == 1 ||
590 EXPECT_EQ(intensity[4].
x - intensity[0].
x, 1);
constexpr static const Scalar kArcApproximationMagic
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={})
flutter::DlScalar DlScalar
constexpr TPoint Rotate(const Radians &angle) const