Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
dl_golden_unittests.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <utility>
8
17#include "gtest/gtest.h"
18
19namespace flutter {
20namespace testing {
21
25using impeller::Point;
28
30
31TEST_P(DlGoldenTest, CanDrawPaint) {
32 auto draw = [](DlCanvas* canvas,
33 const std::vector<std::unique_ptr<DlImage>>& images) {
34 canvas->Scale(0.2, 0.2);
35 DlPaint paint;
36 paint.setColor(DlColor::kCyan());
37 canvas->DrawPaint(paint);
38 };
39
40 DisplayListBuilder builder;
41 draw(&builder, /*images=*/{});
42
43 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
44}
45
46TEST_P(DlGoldenTest, CanRenderImage) {
47 auto draw = [](DlCanvas* canvas, const std::vector<sk_sp<DlImage>>& images) {
48 FML_CHECK(images.size() >= 1);
49 DlPaint paint;
50 paint.setColor(DlColor::kRed());
51 canvas->DrawImage(images[0], DlPoint(100.0, 100.0),
53 };
54
55 DisplayListBuilder builder;
56 std::vector<sk_sp<DlImage>> images;
57 images.emplace_back(CreateDlImageForFixture("kalimba.jpg"));
58 draw(&builder, images);
59
60 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
61}
62
63// Asserts that subpass rendering of MatrixImageFilters works.
64// https://github.com/flutter/flutter/issues/147807
65TEST_P(DlGoldenTest, Bug147807) {
66 Point content_scale = GetContentScale();
67 auto draw = [content_scale](DlCanvas* canvas,
68 const std::vector<sk_sp<DlImage>>& images) {
69 canvas->Scale(content_scale.x, content_scale.y);
70 DlPaint paint;
71 paint.setColor(DlColor(0xfffef7ff));
72 canvas->DrawRect(DlRect::MakeLTRB(0, 0, 375, 667), paint);
73 paint.setColor(DlColor(0xffff9800));
74 canvas->DrawRect(DlRect::MakeLTRB(0, 0, 187.5, 333.5), paint);
75 paint.setColor(DlColor(0xff9c27b0));
76 canvas->DrawRect(DlRect::MakeLTRB(187.5, 0, 375, 333.5), paint);
77 paint.setColor(DlColor(0xff4caf50));
78 canvas->DrawRect(DlRect::MakeLTRB(0, 333.5, 187.5, 667), paint);
79 paint.setColor(DlColor(0xfff44336));
80 canvas->DrawRect(DlRect::MakeLTRB(187.5, 333.5, 375, 667), paint);
81
82 canvas->Save();
83 {
84 canvas->ClipRoundRect(
85 DlRoundRect::MakeOval(DlRect::MakeLTRB(201.25, 10, 361.25, 170)),
87 DlRect save_layer_bounds = DlRect::MakeLTRB(201.25, 10, 361.25, 170);
88 auto backdrop =
90 0, 3, 0.0, -920, //
91 0, 0, 1.0, 0.0, //
92 0, 0, 0.0, 1.0),
94 canvas->SaveLayer(save_layer_bounds, /*paint=*/nullptr, backdrop.get());
95 {
96 canvas->Translate(201.25, 10);
97 auto paint = DlPaint()
98 .setAntiAlias(true)
99 .setColor(DlColor(0xff2196f3))
102 canvas->DrawCircle(DlPoint(80, 80), 80, paint);
103 }
104 canvas->Restore();
105 }
106 canvas->Restore();
107 };
108
109 DisplayListBuilder builder;
110 std::vector<sk_sp<DlImage>> images;
111 draw(&builder, images);
112
113 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
114}
115
116TEST_P(DlGoldenTest, FractionalDilation) {
117 auto draw = [](DlCanvas* canvas) {
118 const DlRect rect = DlRect::MakeLTRB(32, 32, 382, 382);
119 DlPaint layer_paint;
120 layer_paint.setImageFilter(DlImageFilter::MakeDilate(3.95f, 3.95f));
121 canvas->SaveLayer(rect.Expand(8.0f), &layer_paint);
122 canvas->DrawRect(rect, DlPaint().setColor(DlColor::kRed()));
123 canvas->Restore();
124 canvas->DrawRect(rect, DlPaint().setColor(DlColor::kBlack()));
125 };
126
127 DisplayListBuilder builder;
128 builder.Scale(GetContentScale().x, GetContentScale().y);
129 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
130
131 draw(&builder);
132
133 builder.Translate(440, 0);
134 builder.Scale(1.3f, 1.3f);
135 draw(&builder);
136
137 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
138}
139
140namespace {
141void DrawBlurGrid(DlCanvas* canvas) {
142 DlPaint paint;
143 paint.setColor(DlColor(0xfffef7ff));
144 Scalar width = 150;
145 Scalar height = 150;
146 Scalar gap = 80;
147 std::vector<Scalar> blur_radii = {10, 30, 50};
148 for (size_t i = 0; i < blur_radii.size(); ++i) {
149 Scalar blur_radius = blur_radii[i];
150 auto blur_filter = std::make_shared<flutter::DlBlurMaskFilter>(
152 paint.setMaskFilter(blur_filter);
153 Scalar yval = gap + i * (gap + height);
154 canvas->DrawRoundRect(
156 10, 10, 10, 10),
157 paint);
158 canvas->DrawRoundRect(
160 DlRect::MakeXYWH(2.0 * gap + width, yval, width, height), //
161 9, 10, 10, 10),
162 paint);
163 }
164}
165} // namespace
166
167TEST_P(DlGoldenTest, GaussianVsRRectBlur) {
168 Point content_scale = GetContentScale();
169 auto draw = [content_scale](DlCanvas* canvas,
170 const std::vector<sk_sp<DlImage>>& images) {
171 canvas->Scale(content_scale.x, content_scale.y);
172 canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233)));
173 DrawBlurGrid(canvas);
174 };
175
176 DisplayListBuilder builder;
177 std::vector<sk_sp<DlImage>> images;
178 draw(&builder, images);
179
180 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
181}
182
183TEST_P(DlGoldenTest, GaussianVsRRectBlurScaled) {
184 Point content_scale = GetContentScale();
185 auto draw = [content_scale](DlCanvas* canvas,
186 const std::vector<sk_sp<DlImage>>& images) {
187 canvas->Scale(content_scale.x, content_scale.y);
188 canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233)));
189 canvas->Scale(0.33, 0.33);
190 DrawBlurGrid(canvas);
191 };
192
193 DisplayListBuilder builder;
194 std::vector<sk_sp<DlImage>> images;
195 draw(&builder, images);
196
197 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
198}
199
200TEST_P(DlGoldenTest, GaussianVsRRectBlurScaledRotated) {
201 Point content_scale = GetContentScale();
202 auto draw = [content_scale](DlCanvas* canvas,
203 const std::vector<sk_sp<DlImage>>& images) {
204 canvas->Scale(content_scale.x, content_scale.y);
205 canvas->Translate(200, 200);
206 canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233)));
207 canvas->Scale(0.33, 0.33);
208 canvas->Translate(300, 300);
209 canvas->Rotate(45);
210 canvas->Translate(-300, -300);
211 DrawBlurGrid(canvas);
212 };
213
214 DisplayListBuilder builder;
215 std::vector<sk_sp<DlImage>> images;
216 draw(&builder, images);
217
218 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
219}
220
221TEST_P(DlGoldenTest, FastVsGeneralGaussianMaskBlur) {
222 DisplayListBuilder builder;
223 builder.Scale(GetContentScale().x, GetContentScale().y);
224 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
225
226 auto blur_sigmas = std::array{5.0f, 10.0f, 20.0f};
227 auto blur_colors = std::array{
231 };
232
233 auto make_rrect_path = [](const DlRect& rect, DlScalar rx,
234 DlScalar ry) -> DlPath {
235 auto add_corner = [](DlPathBuilder& path_builder, DlPoint corner,
236 DlVector2 relative_from, DlVector2 relative_to,
237 bool first) {
238 static const auto magic = DlPathBuilder::kArcApproximationMagic;
239
240 if (first) {
241 path_builder.MoveTo(corner + relative_from);
242 } else {
243 path_builder.LineTo(corner + relative_from);
244 }
245 // These fractions should be (1 - magic) to make a proper rrect
246 // path, but historically these equations were as written here.
247 // On the plus side, they ensure that we will not optimize this
248 // path as "Hey, look, it's an RRect", but the DrawPath gaussians
249 // will otherwise not be identical to the versions drawn with
250 // DrawRoundRect
251 path_builder.CubicCurveTo(corner + relative_from * magic,
252 corner + relative_to * magic,
253 corner + relative_to);
254 };
255
256 DlPathBuilder path_builder;
257 add_corner(path_builder, rect.GetRightTop(), //
258 DlVector2(-rx, 0.0f), DlVector2(0.0f, ry), true);
259 add_corner(path_builder, rect.GetRightBottom(), //
260 DlVector2(0.0f, -ry), DlVector2(-rx, 0.0f), false);
261 add_corner(path_builder, rect.GetLeftBottom(), //
262 DlVector2(rx, 0.0f), DlVector2(0.0f, -ry), false);
263 add_corner(path_builder, rect.GetLeftTop(), //
264 DlVector2(0.0f, ry), DlVector2(rx, 0.0f), false);
265 return path_builder.TakePath();
266 };
267
268 for (size_t i = 0; i < blur_sigmas.size(); i++) {
269 auto rect = DlRect::MakeXYWH(i * 320.0f + 50.0f, 50.0f, 100.0f, 100.0f);
270 DlPaint paint = DlPaint() //
271 .setColor(blur_colors[i])
273 DlBlurStyle::kNormal, blur_sigmas[i]));
274
275 builder.DrawRoundRect(DlRoundRect::MakeRectXY(rect, 10.0f, 10.0f), paint);
276 rect = rect.Shift(150.0f, 0.0f);
277 builder.DrawPath(make_rrect_path(rect, 10.0f, 10.0f), paint);
278 rect = rect.Shift(-150.0f, 0.0f);
279
280 rect = rect.Shift(0.0f, 200.0f);
281 builder.DrawRoundRect(DlRoundRect::MakeRectXY(rect, 10.0f, 30.0f), paint);
282 rect = rect.Shift(150.0f, 0.0f);
283 builder.DrawPath(make_rrect_path(rect, 10.0f, 20.0f), paint);
284 rect = rect.Shift(-150.0f, 0.0f);
285
286 rect = rect.Shift(0.0f, 200.0f);
287 builder.DrawRoundRect(DlRoundRect::MakeRectXY(rect, 30.0f, 10.0f), paint);
288 rect = rect.Shift(150.0f, 0.0f);
289 builder.DrawPath(make_rrect_path(rect, 20.0f, 10.0f), paint);
290 rect = rect.Shift(-150.0f, 0.0f);
291 }
292
293 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
294}
295
296TEST_P(DlGoldenTest, DashedLinesTest) {
297 Point content_scale = GetContentScale();
298 auto draw = [content_scale](DlCanvas* canvas,
299 const std::vector<sk_sp<DlImage>>& images) {
300 canvas->Scale(content_scale.x, content_scale.y);
302
303 auto draw_one = [canvas](DlStrokeCap cap, Scalar x, Scalar y,
304 Scalar dash_on, Scalar dash_off) {
305 Point center = Point(x, y);
306 Scalar inner = 20.0f;
307 Scalar outer = 100.0f;
308 DlPaint thick_paint = DlPaint()
310 .setStrokeCap(cap)
311 .setStrokeWidth(8.0f);
312 DlPaint middle_paint = DlPaint()
314 .setStrokeCap(cap)
315 .setStrokeWidth(5.0f);
316 DlPaint thin_paint = DlPaint()
318 .setStrokeCap(cap)
319 .setStrokeWidth(2.0f);
320 for (int degrees = 0; degrees < 360; degrees += 30) {
321 Point delta = Point(1.0f, 0.0f).Rotate(Degrees(degrees));
322 canvas->DrawDashedLine(center + inner * delta, center + outer * delta,
323 dash_on, dash_off, thick_paint);
324 canvas->DrawDashedLine(center + inner * delta, center + outer * delta,
325 dash_on, dash_off, middle_paint);
326 canvas->DrawDashedLine(center + inner * delta, center + outer * delta,
327 dash_on, dash_off, thin_paint);
328 }
329 };
330
331 draw_one(DlStrokeCap::kButt, 150.0f, 150.0f, 15.0f, 10.0f);
332 draw_one(DlStrokeCap::kSquare, 400.0f, 150.0f, 15.0f, 10.0f);
333 draw_one(DlStrokeCap::kRound, 150.0f, 400.0f, 15.0f, 10.0f);
334 draw_one(DlStrokeCap::kRound, 400.0f, 400.0f, 0.0f, 11.0f);
335
336 // Make sure the rendering op responds appropriately to clipping
337 canvas->Save();
338 DlPathBuilder path_builder;
339 path_builder.MoveTo(DlPoint(275.0f, 225.0f));
340 path_builder.LineTo(DlPoint(325.0f, 275.0f));
341 path_builder.LineTo(DlPoint(275.0f, 325.0f));
342 path_builder.LineTo(DlPoint(225.0f, 275.0f));
343 canvas->ClipPath(path_builder.TakePath());
344 canvas->DrawColor(DlColor::kYellow());
345 draw_one(DlStrokeCap::kRound, 275.0f, 275.0f, 15.0f, 10.0f);
346 canvas->Restore();
347 };
348
349 DisplayListBuilder builder;
350 std::vector<sk_sp<DlImage>> images;
351 draw(&builder, images);
352
353 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
354}
355
356TEST_P(DlGoldenTest, SaveLayerAtFractionalValue) {
357 // Draws a stroked rounded rect at a fractional pixel value. The coverage must
358 // be adjusted so that we still have room to draw it, even though it lies on
359 // the fractional bounds of the saveLayer.
360 DisplayListBuilder builder;
361 builder.DrawPaint(DlPaint().setColor(DlColor::kWhite()));
362 auto save_paint = DlPaint().setAlpha(100);
363 builder.SaveLayer(std::nullopt, &save_paint);
364
366 DlRect::MakeLTRB(10.5, 10.5, 200.5, 200.5), 10),
367 DlPaint()
368 .setDrawStyle(DlDrawStyle::kStroke)
369 .setStrokeWidth(1.5)
370 .setColor(DlColor::kBlack()));
371 builder.DrawCircle(DlPoint::MakeXY(100, 100), 50.5,
372 DlPaint().setColor(DlColor::kAqua()));
373 builder.DrawCircle(DlPoint::MakeXY(110, 110), 50.5,
374 DlPaint().setColor(DlColor::kCyan()));
375
376 builder.Restore();
377
378 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
379}
380
381namespace {
382int32_t CalculateMaxY(const impeller::testing::Screenshot* img) {
383 const uint32_t* ptr = reinterpret_cast<const uint32_t*>(img->GetBytes());
384 int32_t max_y = 0;
385 for (uint32_t i = 0; i < img->GetHeight(); ++i) {
386 for (uint32_t j = 0; j < img->GetWidth(); ++j) {
387 uint32_t pixel = *ptr++;
388 if ((pixel & 0x00ffffff) != 0) {
389 max_y = std::max(max_y, static_cast<int32_t>(i));
390 }
391 }
392 }
393 return max_y;
394}
395
396std::optional<int32_t> CalculateSpaceBetweenUI(
398 int32_t y) {
399 if (y < 0 || std::cmp_greater_equal(y, img->GetHeight())) {
400 return {};
401 }
402 const uint32_t* ptr = reinterpret_cast<const uint32_t*>(img->GetBytes());
403 ptr += img->GetWidth() * y;
404 std::vector<size_t> boundaries;
405 uint32_t value = *ptr++;
406 for (size_t i = 1; i < img->GetWidth(); ++i) {
407 if (((*ptr & 0x00ffffff) != 0) != ((value & 0x00ffffff) != 0)) {
408 boundaries.push_back(i);
409 }
410 value = *ptr++;
411 }
412
413 if (boundaries.size() != 6) {
414 return {};
415 }
416 return boundaries[4] - boundaries[3];
417}
418} // namespace
419
420TEST_P(DlGoldenTest, BaselineHE) {
421 SetWindowSize(impeller::ISize(1024, 200));
423 auto callback = [&](const char* text,
424 impeller::Scalar scale) -> sk_sp<DisplayList> {
425 DisplayListBuilder builder;
426 DlPaint paint;
427 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
428 builder.DrawPaint(paint);
429 builder.Scale(scale, scale);
430 if (!RenderTextInCanvasSkia(&builder, text, "Roboto-Regular.ttf",
431 DlPoint::MakeXY(10, 300),
434 })
435 .ok()) {
436 return nullptr;
437 }
438 return builder.Build();
439 };
440
441 std::unique_ptr<impeller::testing::Screenshot> right =
442 MakeScreenshot(callback("h", 0.444));
443 if (!right) {
444 GTEST_SKIP() << "making screenshots not supported.";
445 }
446 std::unique_ptr<impeller::testing::Screenshot> left =
447 MakeScreenshot(callback("e", 0.444));
448
449 int32_t left_max_y = CalculateMaxY(left.get());
450 int32_t right_max_y = CalculateMaxY(right.get());
451 int32_t y_diff = std::abs(left_max_y - right_max_y);
452 EXPECT_TRUE(y_diff <= 2) << "y diff: " << y_diff;
453}
454
455TEST_P(DlGoldenTest, MaintainsSpace) {
456 SetWindowSize(impeller::ISize(1024, 200));
458
459 int32_t middle = 0;
460 std::optional<int32_t> last_space;
461 for (int i = 0; i <= 100; ++i) {
462 Scalar scale = 0.440 + i / 1000.0;
463 absl::StatusOr<DlRect> text_bounds_or;
464 sk_sp<DisplayList> display_list;
465 {
466 DisplayListBuilder builder;
467 DlPaint paint;
468 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
469 builder.DrawPaint(paint);
470 builder.Scale(scale, scale);
471 text_bounds_or = RenderTextInCanvasSkia(
472 &builder, "ui", "Roboto-Regular.ttf", DlPoint::MakeXY(10, 300),
475 });
476 display_list = builder.Build();
477 }
478 ASSERT_TRUE(text_bounds_or.ok());
479 ASSERT_TRUE(display_list);
480 std::unique_ptr<impeller::testing::Screenshot> right =
481 MakeScreenshot(display_list);
482 if (!right) {
483 GTEST_SKIP() << "making screenshots not supported.";
484 }
485 middle = std::rint(scale * text_bounds_or->GetCenter().y);
486
487 std::optional<int32_t> space = CalculateSpaceBetweenUI(right.get(), middle);
488 ASSERT_TRUE(space.has_value());
489 if (space.has_value() && last_space.has_value()) {
490 int32_t diff = abs(*space - *last_space);
491 EXPECT_TRUE(diff <= 1)
492 << "i:" << i << " space:" << *space << " last_space:" << *last_space;
493 }
494 last_space = space;
495 }
496}
497
498namespace {
499struct LeftmostIntensity {
500 int32_t x;
501 int32_t value;
502};
503
504/// Returns the highest value in the green channel for leftmost column that
505/// isn't all black.
506LeftmostIntensity CalculateLeftmostIntensity(
508 LeftmostIntensity result = {.x = static_cast<int32_t>(img->GetWidth()),
509 .value = 0};
510 const uint32_t* ptr = reinterpret_cast<const uint32_t*>(img->GetBytes());
511 for (size_t i = 0; i < img->GetHeight(); ++i) {
512 for (int32_t j = 0; j < static_cast<int32_t>(img->GetWidth()); ++j) {
513 if (((*ptr & 0x00ffffff) != 0)) {
514 if (j < result.x) {
515 result.x = j;
516 result.value = (*ptr & 0xff00) >> 8;
517 } else if (j == result.x) {
518 result.value =
519 std::max(static_cast<int32_t>(*ptr & 0xff), result.value);
520 }
521 }
522 ptr++;
523 }
524 }
525 return result;
526}
527} // namespace
528
529// Checks that the left most edge of the glyph is fading out as we push
530// it to the right by fractional pixels.
532 SetWindowSize(impeller::ISize(1024, 200));
534 auto callback = [&](Scalar offset_x) -> sk_sp<DisplayList> {
535 DisplayListBuilder builder;
536 DlPaint paint;
537 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
538 builder.DrawPaint(paint);
539 EXPECT_TRUE(RenderTextInCanvasSkia(&builder, "ui", "Roboto-Regular.ttf",
540 DlPoint::MakeXY(offset_x, 180),
543 .is_subpixel = true,
544 })
545 .ok());
546 return builder.Build();
547 };
548
549 LeftmostIntensity intensity[5];
550 for (int i = 0; i <= 4; ++i) {
551 Scalar offset = 10 + (i / 4.0);
552 std::unique_ptr<impeller::testing::Screenshot> right =
553 MakeScreenshot(callback(offset));
554 if (!right) {
555 GTEST_SKIP() << "making screenshots not supported.";
556 }
557 intensity[i] = CalculateLeftmostIntensity(right.get());
558 ASSERT_NE(intensity[i].value, 0);
559 }
560 for (int i = 1; i < 5; ++i) {
561 EXPECT_TRUE(intensity[i].x - intensity[i - 1].x == 1 ||
562 intensity[i].value < intensity[i - 1].value)
563 << i;
564 }
565 EXPECT_EQ(intensity[4].x - intensity[0].x, 1);
566}
567
568// Checks that the left most edge of the glyph is fading out as we push
569// it to the right by fractional pixels.
570TEST_P(DlGoldenTest, SubpixelScaled) {
571 SetWindowSize(impeller::ISize(1024, 200));
573 Scalar scalar = 0.75;
574 auto callback = [&](Scalar offset_x) -> sk_sp<DisplayList> {
575 DisplayListBuilder builder;
576 builder.Scale(scalar, scalar);
577 DlPaint paint;
578 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
579 builder.DrawPaint(paint);
580 EXPECT_TRUE(RenderTextInCanvasSkia(&builder, "ui", "Roboto-Regular.ttf",
581 DlPoint::MakeXY(offset_x, 180),
584 .is_subpixel = true,
585 })
586 .ok());
587 return builder.Build();
588 };
589
590 LeftmostIntensity intensity[5];
591 Scalar offset_fraction = 0.25 / scalar;
592 for (int i = 0; i <= 4; ++i) {
593 Scalar offset = 10 + (offset_fraction * i);
594 std::unique_ptr<impeller::testing::Screenshot> right =
595 MakeScreenshot(callback(offset));
596 if (!right) {
597 GTEST_SKIP() << "making screenshots not supported.";
598 }
599 intensity[i] = CalculateLeftmostIntensity(right.get());
600 ASSERT_NE(intensity[i].value, 0);
601 }
602 for (int i = 1; i < 5; ++i) {
603 EXPECT_TRUE(intensity[i].x - intensity[i - 1].x == 1 ||
604 intensity[i].value < intensity[i - 1].value)
605 << i;
606 }
607 EXPECT_EQ(intensity[4].x - intensity[0].x, 1);
608}
609
610// Checks that the left most edge of the glyph is fading out as we push
611// it to the right by fractional pixels.
612TEST_P(DlGoldenTest, SubpixelScaledTranslated) {
613 SetWindowSize(impeller::ISize(1024, 200));
615 Scalar scalar = 0.75;
616 auto callback = [&](Scalar offset_x) -> sk_sp<DisplayList> {
617 DisplayListBuilder builder;
618 builder.Scale(scalar, scalar);
619 DlPaint paint;
620 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
621 builder.DrawPaint(paint);
622 builder.Translate(offset_x, 180);
623 EXPECT_TRUE(RenderTextInCanvasSkia(&builder, "ui", "Roboto-Regular.ttf",
624 DlPoint::MakeXY(0, 0),
627 .is_subpixel = true,
628 })
629 .ok());
630 return builder.Build();
631 };
632
633 LeftmostIntensity intensity[5];
634 Scalar offset_fraction = 0.25 / scalar;
635 for (int i = 0; i <= 4; ++i) {
636 Scalar offset = 10 + (offset_fraction * i);
637 std::unique_ptr<impeller::testing::Screenshot> right =
638 MakeScreenshot(callback(offset));
639 if (!right) {
640 GTEST_SKIP() << "making screenshots not supported.";
641 }
642 intensity[i] = CalculateLeftmostIntensity(right.get());
643 ASSERT_NE(intensity[i].value, 0);
644 }
645 for (int i = 1; i < 5; ++i) {
646 EXPECT_TRUE(intensity[i].x - intensity[i - 1].x == 1 ||
647 intensity[i].value < intensity[i - 1].value)
648 << i;
649 }
650 EXPECT_EQ(intensity[4].x - intensity[0].x, 1);
651}
652
653} // namespace testing
654} // namespace flutter
void DrawRoundRect(const DlRoundRect &rrect, const DlPaint &paint) override
void DrawColor(DlColor color, DlBlendMode mode) override
void DrawCircle(const DlPoint &center, DlScalar radius, const DlPaint &paint) override
void SaveLayer(const std::optional< DlRect > &bounds, const DlPaint *paint=nullptr, const DlImageFilter *backdrop=nullptr, std::optional< int64_t > backdrop_id=std::nullopt) override
void Scale(DlScalar sx, DlScalar sy) override
void Translate(DlScalar tx, DlScalar ty) override
void DrawPaint(const DlPaint &paint) override
sk_sp< DisplayList > Build()
void DrawPath(const DlPath &path, const DlPaint &paint) override
static std::shared_ptr< DlMaskFilter > Make(DlBlurStyle style, SkScalar sigma, bool respect_ctm=true)
Developer-facing API for rendering anything within the engine.
Definition dl_canvas.h:32
virtual void DrawPaint(const DlPaint &paint)=0
virtual void DrawCircle(const DlPoint &center, DlScalar radius, const DlPaint &paint)=0
virtual void ClipRoundRect(const DlRoundRect &rrect, DlClipOp clip_op=DlClipOp::kIntersect, bool is_aa=false)=0
virtual void DrawRoundRect(const DlRoundRect &rrect, const DlPaint &paint)=0
virtual void SaveLayer(const std::optional< DlRect > &bounds, const DlPaint *paint=nullptr, const DlImageFilter *backdrop=nullptr, std::optional< int64_t > backdrop_id=std::nullopt)=0
virtual void DrawRect(const DlRect &rect, const DlPaint &paint)=0
virtual void DrawImage(const sk_sp< DlImage > &image, const DlPoint &point, DlImageSampling sampling, const DlPaint *paint=nullptr)=0
virtual void Translate(DlScalar tx, DlScalar ty)=0
virtual void DrawColor(DlColor color, DlBlendMode mode=DlBlendMode::kSrcOver)=0
virtual void Rotate(DlScalar degrees)=0
virtual void DrawDashedLine(const DlPoint &p0, const DlPoint &p1, DlScalar on_length, DlScalar off_length, const DlPaint &paint)=0
virtual void Restore()=0
virtual void ClipPath(const DlPath &path, DlClipOp clip_op=DlClipOp::kIntersect, bool is_aa=false)=0
virtual void Scale(DlScalar sx, DlScalar sy)=0
virtual void Save()=0
static std::shared_ptr< DlImageFilter > MakeDilate(DlScalar radius_x, DlScalar radius_y)
static std::shared_ptr< DlImageFilter > MakeMatrix(const DlMatrix &matrix, DlImageSampling sampling)
DlPaint & setColor(DlColor color)
Definition dl_paint.h:70
DlPaint & setAntiAlias(bool isAntiAlias)
Definition dl_paint.h:58
DlPaint & setStrokeCap(DlStrokeCap cap)
Definition dl_paint.h:101
DlPaint & setStrokeWidth(float width)
Definition dl_paint.h:115
DlPaint & setAlpha(uint8_t alpha)
Definition dl_paint.h:76
DlPaint & setImageFilter(std::nullptr_t filter)
Definition dl_paint.h:167
DlPaint & setMaskFilter(std::nullptr_t filter)
Definition dl_paint.h:185
DlPaint & setDrawStyle(DlDrawStyle style)
Definition dl_paint.h:93
DlPathBuilder & LineTo(DlPoint p2)
Draw a line from the current point to the indicated point p2.
static constexpr const DlScalar kArcApproximationMagic
DlPathBuilder & MoveTo(DlPoint p2)
Start a new contour that will originate at the indicated point p2.
const DlPath TakePath()
Returns the path constructed by this path builder and resets its internal state to the default state ...
DlPathBuilder & CubicCurveTo(DlPoint cp1, DlPoint cp2, DlPoint p2)
Draw a cubic bezier curve from the current point to the indicated point p2, using the indicated point...
double x() const
Definition geometry.h:22
double y() const
Definition geometry.h:23
virtual const uint8_t * GetBytes() const =0
Access raw data of the screenshot.
virtual size_t GetHeight() const =0
Returns the height of the image in pixels.
virtual size_t GetWidth() const =0
Returns the width of the image in pixels.
int32_t value
int32_t x
FlutterDesktopBinaryReply callback
#define FML_CHECK(condition)
Definition logging.h:104
Vector2 blur_radius
Blur radius in source pixels based on scaled_sigma.
std::u16string text
std::array< MockImage, 3 > images
double y
TEST_P(DlGoldenTest, TextBlurMaskFilterRespectCTM)
absl::StatusOr< DlRect > RenderTextInCanvasSkia(DlCanvas *canvas, const std::string &text, const std::string_view &font_fixture, DlPoint position, const TextRenderOptions &options)
impeller::Scalar DlScalar
DlStrokeCap
Definition dl_paint.h:28
@ kRound
adds circle
@ kButt
no stroke extension
@ kSquare
adds square
@ kStroke
strokes boundary of shapes
@ kNormal
fuzzy inside and outside
impeller::Point DlPoint
impeller::Vector2 DlVector2
float Scalar
Definition scalar.h:19
PlaygroundBackend
Definition playground.h:32
#define INSTANTIATE_PLAYGROUND_SUITE(playground)
int32_t height
int32_t width
static constexpr DlColor kMagenta()
Definition dl_color.h:75
static constexpr DlColor kWhite()
Definition dl_color.h:70
static constexpr DlColor kBlue()
Definition dl_color.h:73
static constexpr DlColor kBlack()
Definition dl_color.h:69
static constexpr DlColor kMaroon()
Definition dl_color.h:82
static constexpr DlColor ARGB(DlScalar a, DlScalar r, DlScalar g, DlScalar b)
Construct a 32 bit color from floating point A, R, G, and B color channels.
Definition dl_color.h:57
static constexpr DlColor kAqua()
Definition dl_color.h:86
static constexpr DlColor kYellow()
Definition dl_color.h:76
static constexpr DlColor kRed()
Definition dl_color.h:71
static constexpr DlColor kGreen()
Definition dl_color.h:72
static constexpr DlColor kCyan()
Definition dl_color.h:74
static constexpr Matrix MakeRow(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
Definition matrix.h:83
static RoundRect MakeRectRadius(const Rect &rect, Scalar radius)
Definition round_rect.h:27
static RoundRect MakeNinePatch(const Rect &rect, Scalar left, Scalar top, Scalar right, Scalar bottom)
Definition round_rect.h:42
static RoundRect MakeOval(const Rect &rect)
Definition round_rect.h:23
static RoundRect MakeRectXY(const Rect &rect, Scalar x_radius, Scalar y_radius)
Definition round_rect.h:31
static constexpr TPoint< Type > MakeXY(Type x, Type y)
Definition point.h:47
constexpr TPoint< T > GetLeftTop() const
Definition rect.h:393
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition rect.h:136
constexpr TPoint< T > GetRightBottom() const
Definition rect.h:405
constexpr TPoint< T > GetLeftBottom() const
Definition rect.h:401
constexpr TPoint< T > GetRightTop() const
Definition rect.h:397
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
Definition rect.h:652
constexpr TRect< T > Shift(T dx, T dy) const
Returns a new rectangle translated by the given offset.
Definition rect.h:636
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129
Scalar font_size