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
15#include "gtest/gtest.h"
16
17namespace flutter {
18namespace testing {
19
23using impeller::Point;
26
28
29TEST_P(DlGoldenTest, CanDrawPaint) {
30 auto draw = [](DlCanvas* canvas,
31 const std::vector<std::unique_ptr<DlImage>>& images) {
32 canvas->Scale(0.2, 0.2);
33 DlPaint paint;
34 paint.setColor(DlColor::kCyan());
35 canvas->DrawPaint(paint);
36 };
37
38 DisplayListBuilder builder;
39 draw(&builder, /*images=*/{});
40
41 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
42}
43
44TEST_P(DlGoldenTest, CanRenderImage) {
45 auto draw = [](DlCanvas* canvas, const std::vector<sk_sp<DlImage>>& images) {
46 FML_CHECK(images.size() >= 1);
47 DlPaint paint;
48 paint.setColor(DlColor::kRed());
49 canvas->DrawImage(images[0], DlPoint(100.0, 100.0),
51 };
52
53 DisplayListBuilder builder;
54 std::vector<sk_sp<DlImage>> images;
55 images.emplace_back(CreateDlImageForFixture("kalimba.jpg"));
56 draw(&builder, images);
57
58 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
59}
60
61// Asserts that subpass rendering of MatrixImageFilters works.
62// https://github.com/flutter/flutter/issues/147807
63TEST_P(DlGoldenTest, Bug147807) {
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);
68 DlPaint paint;
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);
79
80 canvas->Save();
81 {
82 canvas->ClipRoundRect(
83 DlRoundRect::MakeOval(DlRect::MakeLTRB(201.25, 10, 361.25, 170)),
85 DlRect save_layer_bounds = DlRect::MakeLTRB(201.25, 10, 361.25, 170);
86 auto backdrop =
88 0, 3, 0.0, -920, //
89 0, 0, 1.0, 0.0, //
90 0, 0, 0.0, 1.0),
92 canvas->SaveLayer(save_layer_bounds, /*paint=*/nullptr, backdrop.get());
93 {
94 canvas->Translate(201.25, 10);
95 auto paint = DlPaint()
96 .setAntiAlias(true)
97 .setColor(DlColor(0xff2196f3))
100 canvas->DrawCircle(DlPoint(80, 80), 80, paint);
101 }
102 canvas->Restore();
103 }
104 canvas->Restore();
105 };
106
107 DisplayListBuilder builder;
108 std::vector<sk_sp<DlImage>> images;
109 draw(&builder, images);
110
111 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
112}
113
114TEST_P(DlGoldenTest, FractionalDilation) {
115 auto draw = [](DlCanvas* canvas) {
116 const DlRect rect = DlRect::MakeLTRB(32, 32, 382, 382);
117 DlPaint layer_paint;
118 layer_paint.setImageFilter(DlImageFilter::MakeDilate(3.95f, 3.95f));
119 canvas->SaveLayer(rect.Expand(8.0f), &layer_paint);
120 canvas->DrawRect(rect, DlPaint().setColor(DlColor::kRed()));
121 canvas->Restore();
122 canvas->DrawRect(rect, DlPaint().setColor(DlColor::kBlack()));
123 };
124
125 DisplayListBuilder builder;
126 builder.Scale(GetContentScale().x, GetContentScale().y);
127 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
128
129 draw(&builder);
130
131 builder.Translate(440, 0);
132 builder.Scale(1.3f, 1.3f);
133 draw(&builder);
134
135 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
136}
137
138namespace {
139void DrawBlurGrid(DlCanvas* canvas) {
140 DlPaint paint;
141 paint.setColor(DlColor(0xfffef7ff));
142 Scalar width = 150;
143 Scalar height = 150;
144 Scalar gap = 80;
145 std::vector<Scalar> blur_radii = {10, 30, 50};
146 for (size_t i = 0; i < blur_radii.size(); ++i) {
147 Scalar blur_radius = blur_radii[i];
148 auto blur_filter = std::make_shared<flutter::DlBlurMaskFilter>(
150 paint.setMaskFilter(blur_filter);
151 Scalar yval = gap + i * (gap + height);
152 canvas->DrawRoundRect(
154 10, 10, 10, 10),
155 paint);
156 canvas->DrawRoundRect(
158 DlRect::MakeXYWH(2.0 * gap + width, yval, width, height), //
159 9, 10, 10, 10),
160 paint);
161 }
162}
163} // namespace
164
165TEST_P(DlGoldenTest, GaussianVsRRectBlur) {
166 Point content_scale = GetContentScale();
167 auto draw = [content_scale](DlCanvas* canvas,
168 const std::vector<sk_sp<DlImage>>& images) {
169 canvas->Scale(content_scale.x, content_scale.y);
170 canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233)));
171 DrawBlurGrid(canvas);
172 };
173
174 DisplayListBuilder builder;
175 std::vector<sk_sp<DlImage>> images;
176 draw(&builder, images);
177
178 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
179}
180
181TEST_P(DlGoldenTest, GaussianVsRRectBlurScaled) {
182 Point content_scale = GetContentScale();
183 auto draw = [content_scale](DlCanvas* canvas,
184 const std::vector<sk_sp<DlImage>>& images) {
185 canvas->Scale(content_scale.x, content_scale.y);
186 canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233)));
187 canvas->Scale(0.33, 0.33);
188 DrawBlurGrid(canvas);
189 };
190
191 DisplayListBuilder builder;
192 std::vector<sk_sp<DlImage>> images;
193 draw(&builder, images);
194
195 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
196}
197
198TEST_P(DlGoldenTest, GaussianVsRRectBlurScaledRotated) {
199 Point content_scale = GetContentScale();
200 auto draw = [content_scale](DlCanvas* canvas,
201 const std::vector<sk_sp<DlImage>>& images) {
202 canvas->Scale(content_scale.x, content_scale.y);
203 canvas->Translate(200, 200);
204 canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233)));
205 canvas->Scale(0.33, 0.33);
206 canvas->Translate(300, 300);
207 canvas->Rotate(45);
208 canvas->Translate(-300, -300);
209 DrawBlurGrid(canvas);
210 };
211
212 DisplayListBuilder builder;
213 std::vector<sk_sp<DlImage>> images;
214 draw(&builder, images);
215
216 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
217}
218
219TEST_P(DlGoldenTest, FastVsGeneralGaussianMaskBlur) {
220 DisplayListBuilder builder;
221 builder.Scale(GetContentScale().x, GetContentScale().y);
222 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
223
224 auto blur_sigmas = std::array{5.0f, 10.0f, 20.0f};
225 auto blur_colors = std::array{
229 };
230
231 auto make_rrect_path = [](const DlRect& rect, DlScalar rx,
232 DlScalar ry) -> DlPath {
233 auto add_corner = [](DlPathBuilder& path_builder, DlPoint corner,
234 DlVector2 relative_from, DlVector2 relative_to,
235 bool first) {
236 static const auto magic = DlPathBuilder::kArcApproximationMagic;
237
238 if (first) {
239 path_builder.MoveTo(corner + relative_from);
240 } else {
241 path_builder.LineTo(corner + relative_from);
242 }
243 // These fractions should be (1 - magic) to make a proper rrect
244 // path, but historically these equations were as written here.
245 // On the plus side, they ensure that we will not optimize this
246 // path as "Hey, look, it's an RRect", but the DrawPath gaussians
247 // will otherwise not be identical to the versions drawn with
248 // DrawRoundRect
249 path_builder.CubicCurveTo(corner + relative_from * magic,
250 corner + relative_to * magic,
251 corner + relative_to);
252 };
253
254 DlPathBuilder path_builder;
255 add_corner(path_builder, rect.GetRightTop(), //
256 DlVector2(-rx, 0.0f), DlVector2(0.0f, ry), true);
257 add_corner(path_builder, rect.GetRightBottom(), //
258 DlVector2(0.0f, -ry), DlVector2(-rx, 0.0f), false);
259 add_corner(path_builder, rect.GetLeftBottom(), //
260 DlVector2(rx, 0.0f), DlVector2(0.0f, -ry), false);
261 add_corner(path_builder, rect.GetLeftTop(), //
262 DlVector2(0.0f, ry), DlVector2(rx, 0.0f), false);
263 return path_builder.TakePath();
264 };
265
266 for (size_t i = 0; i < blur_sigmas.size(); i++) {
267 auto rect = DlRect::MakeXYWH(i * 320.0f + 50.0f, 50.0f, 100.0f, 100.0f);
268 DlPaint paint = DlPaint() //
269 .setColor(blur_colors[i])
271 DlBlurStyle::kNormal, blur_sigmas[i]));
272
273 builder.DrawRoundRect(DlRoundRect::MakeRectXY(rect, 10.0f, 10.0f), paint);
274 rect = rect.Shift(150.0f, 0.0f);
275 builder.DrawPath(make_rrect_path(rect, 10.0f, 10.0f), paint);
276 rect = rect.Shift(-150.0f, 0.0f);
277
278 rect = rect.Shift(0.0f, 200.0f);
279 builder.DrawRoundRect(DlRoundRect::MakeRectXY(rect, 10.0f, 30.0f), paint);
280 rect = rect.Shift(150.0f, 0.0f);
281 builder.DrawPath(make_rrect_path(rect, 10.0f, 20.0f), paint);
282 rect = rect.Shift(-150.0f, 0.0f);
283
284 rect = rect.Shift(0.0f, 200.0f);
285 builder.DrawRoundRect(DlRoundRect::MakeRectXY(rect, 30.0f, 10.0f), paint);
286 rect = rect.Shift(150.0f, 0.0f);
287 builder.DrawPath(make_rrect_path(rect, 20.0f, 10.0f), paint);
288 rect = rect.Shift(-150.0f, 0.0f);
289 }
290
291 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
292}
293
294TEST_P(DlGoldenTest, DashedLinesTest) {
295 Point content_scale = GetContentScale();
296 auto draw = [content_scale](DlCanvas* canvas,
297 const std::vector<sk_sp<DlImage>>& images) {
298 canvas->Scale(content_scale.x, content_scale.y);
300
301 auto draw_one = [canvas](DlStrokeCap cap, Scalar x, Scalar y,
302 Scalar dash_on, Scalar dash_off) {
303 Point center = Point(x, y);
304 Scalar inner = 20.0f;
305 Scalar outer = 100.0f;
306 DlPaint thick_paint = DlPaint()
308 .setStrokeCap(cap)
309 .setStrokeWidth(8.0f);
310 DlPaint middle_paint = DlPaint()
312 .setStrokeCap(cap)
313 .setStrokeWidth(5.0f);
314 DlPaint thin_paint = DlPaint()
316 .setStrokeCap(cap)
317 .setStrokeWidth(2.0f);
318 for (int degrees = 0; degrees < 360; degrees += 30) {
319 Point delta = Point(1.0f, 0.0f).Rotate(Degrees(degrees));
320 canvas->DrawDashedLine(center + inner * delta, center + outer * delta,
321 dash_on, dash_off, thick_paint);
322 canvas->DrawDashedLine(center + inner * delta, center + outer * delta,
323 dash_on, dash_off, middle_paint);
324 canvas->DrawDashedLine(center + inner * delta, center + outer * delta,
325 dash_on, dash_off, thin_paint);
326 }
327 };
328
329 draw_one(DlStrokeCap::kButt, 150.0f, 150.0f, 15.0f, 10.0f);
330 draw_one(DlStrokeCap::kSquare, 400.0f, 150.0f, 15.0f, 10.0f);
331 draw_one(DlStrokeCap::kRound, 150.0f, 400.0f, 15.0f, 10.0f);
332 draw_one(DlStrokeCap::kRound, 400.0f, 400.0f, 0.0f, 11.0f);
333
334 // Make sure the rendering op responds appropriately to clipping
335 canvas->Save();
336 DlPathBuilder path_builder;
337 path_builder.MoveTo(DlPoint(275.0f, 225.0f));
338 path_builder.LineTo(DlPoint(325.0f, 275.0f));
339 path_builder.LineTo(DlPoint(275.0f, 325.0f));
340 path_builder.LineTo(DlPoint(225.0f, 275.0f));
341 canvas->ClipPath(path_builder.TakePath());
342 canvas->DrawColor(DlColor::kYellow());
343 draw_one(DlStrokeCap::kRound, 275.0f, 275.0f, 15.0f, 10.0f);
344 canvas->Restore();
345 };
346
347 DisplayListBuilder builder;
348 std::vector<sk_sp<DlImage>> images;
349 draw(&builder, images);
350
351 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
352}
353
354TEST_P(DlGoldenTest, SaveLayerAtFractionalValue) {
355 // Draws a stroked rounded rect at a fractional pixel value. The coverage must
356 // be adjusted so that we still have room to draw it, even though it lies on
357 // the fractional bounds of the saveLayer.
358 DisplayListBuilder builder;
359 builder.DrawPaint(DlPaint().setColor(DlColor::kWhite()));
360 auto save_paint = DlPaint().setAlpha(100);
361 builder.SaveLayer(std::nullopt, &save_paint);
362
364 DlRect::MakeLTRB(10.5, 10.5, 200.5, 200.5), 10),
365 DlPaint()
366 .setDrawStyle(DlDrawStyle::kStroke)
367 .setStrokeWidth(1.5)
368 .setColor(DlColor::kBlack()));
369 builder.DrawCircle(DlPoint::MakeXY(100, 100), 50.5,
370 DlPaint().setColor(DlColor::kAqua()));
371 builder.DrawCircle(DlPoint::MakeXY(110, 110), 50.5,
372 DlPaint().setColor(DlColor::kCyan()));
373
374 builder.Restore();
375
376 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
377}
378
379namespace {
380int32_t CalculateMaxY(const impeller::testing::Screenshot* img) {
381 const uint32_t* ptr = reinterpret_cast<const uint32_t*>(img->GetBytes());
382 int32_t max_y = 0;
383 for (uint32_t i = 0; i < img->GetHeight(); ++i) {
384 for (uint32_t j = 0; j < img->GetWidth(); ++j) {
385 uint32_t pixel = *ptr++;
386 if ((pixel & 0x00ffffff) != 0) {
387 max_y = std::max(max_y, static_cast<int32_t>(i));
388 }
389 }
390 }
391 return max_y;
392}
393
394int32_t CalculateSpaceBetweenUI(const impeller::testing::Screenshot* img) {
395 const uint32_t* ptr = reinterpret_cast<const uint32_t*>(img->GetBytes());
396 ptr += img->GetWidth() * static_cast<int32_t>(img->GetHeight() / 2.0);
397 std::vector<size_t> boundaries;
398 uint32_t value = *ptr++;
399 for (size_t i = 1; i < img->GetWidth(); ++i) {
400 if (((*ptr & 0x00ffffff) != 0) != ((value & 0x00ffffff) != 0)) {
401 boundaries.push_back(i);
402 }
403 value = *ptr++;
404 }
405
406 assert(boundaries.size() == 6);
407 return boundaries[4] - boundaries[3];
408}
409} // namespace
410
411TEST_P(DlGoldenTest, BaselineHE) {
412 SetWindowSize(impeller::ISize(1024, 200));
414 auto callback = [&](const char* text,
415 impeller::Scalar scale) -> sk_sp<DisplayList> {
416 DisplayListBuilder builder;
417 DlPaint paint;
418 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
419 builder.DrawPaint(paint);
420 builder.Scale(scale, scale);
421 RenderTextInCanvasSkia(&builder, text, "Roboto-Regular.ttf",
422 DlPoint::MakeXY(10, 300),
425 });
426 return builder.Build();
427 };
428
429 std::unique_ptr<impeller::testing::Screenshot> right =
430 MakeScreenshot(callback("h", 0.444));
431 if (!right) {
432 GTEST_SKIP() << "making screenshots not supported.";
433 }
434 std::unique_ptr<impeller::testing::Screenshot> left =
435 MakeScreenshot(callback("e", 0.444));
436
437 int32_t left_max_y = CalculateMaxY(left.get());
438 int32_t right_max_y = CalculateMaxY(right.get());
439 int32_t y_diff = std::abs(left_max_y - right_max_y);
440 EXPECT_TRUE(y_diff <= 2) << "y diff: " << y_diff;
441}
442
443TEST_P(DlGoldenTest, MaintainsSpace) {
444 SetWindowSize(impeller::ISize(1024, 200));
446 auto callback = [&](const char* text,
447 impeller::Scalar scale) -> sk_sp<DisplayList> {
448 DisplayListBuilder builder;
449 DlPaint paint;
450 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
451 builder.DrawPaint(paint);
452 builder.Scale(scale, scale);
453 RenderTextInCanvasSkia(&builder, text, "Roboto-Regular.ttf",
454 DlPoint::MakeXY(10, 300),
457 });
458 return builder.Build();
459 };
460
461 std::optional<int32_t> last_space;
462 for (int i = 0; i <= 100; ++i) {
463 Scalar scale = 0.440 + i / 1000.0;
464 std::unique_ptr<impeller::testing::Screenshot> right =
465 MakeScreenshot(callback("ui", scale));
466 if (!right) {
467 GTEST_SKIP() << "making screenshots not supported.";
468 }
469
470 int32_t space = CalculateSpaceBetweenUI(right.get());
471 if (last_space.has_value()) {
472 int32_t diff = abs(space - *last_space);
473 EXPECT_TRUE(diff <= 1)
474 << "i:" << i << " space:" << space << " last_space:" << *last_space;
475 }
476 last_space = space;
477 }
478}
479
480namespace {
481struct LeftmostIntensity {
482 int32_t x;
483 int32_t value;
484};
485
486/// Returns the highest value in the green channel for leftmost column that
487/// isn't all black.
488LeftmostIntensity CalculateLeftmostIntensity(
490 LeftmostIntensity result = {.x = static_cast<int32_t>(img->GetWidth()),
491 .value = 0};
492 const uint32_t* ptr = reinterpret_cast<const uint32_t*>(img->GetBytes());
493 for (size_t i = 0; i < img->GetHeight(); ++i) {
494 for (int32_t j = 0; j < static_cast<int32_t>(img->GetWidth()); ++j) {
495 if (((*ptr & 0x00ffffff) != 0)) {
496 if (j < result.x) {
497 result.x = j;
498 result.value = (*ptr & 0xff00) >> 8;
499 } else if (j == result.x) {
500 result.value =
501 std::max(static_cast<int32_t>(*ptr & 0xff), result.value);
502 }
503 }
504 ptr++;
505 }
506 }
507 return result;
508}
509} // namespace
510
511// Checks that the left most edge of the glyph is fading out as we push
512// it to the right by fractional pixels.
514 SetWindowSize(impeller::ISize(1024, 200));
516 auto callback = [&](Scalar offset_x) -> sk_sp<DisplayList> {
517 DisplayListBuilder builder;
518 DlPaint paint;
519 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
520 builder.DrawPaint(paint);
521 RenderTextInCanvasSkia(&builder, "ui", "Roboto-Regular.ttf",
522 DlPoint::MakeXY(offset_x, 180),
525 .is_subpixel = true,
526 });
527 return builder.Build();
528 };
529
530 LeftmostIntensity intensity[5];
531 for (int i = 0; i <= 4; ++i) {
532 Scalar offset = 10 + (i / 4.0);
533 std::unique_ptr<impeller::testing::Screenshot> right =
534 MakeScreenshot(callback(offset));
535 if (!right) {
536 GTEST_SKIP() << "making screenshots not supported.";
537 }
538 intensity[i] = CalculateLeftmostIntensity(right.get());
539 ASSERT_NE(intensity[i].value, 0);
540 }
541 for (int i = 1; i < 5; ++i) {
542 EXPECT_TRUE(intensity[i].x - intensity[i - 1].x == 1 ||
543 intensity[i].value < intensity[i - 1].value)
544 << i;
545 }
546 EXPECT_EQ(intensity[4].x - intensity[0].x, 1);
547}
548
549// Checks that the left most edge of the glyph is fading out as we push
550// it to the right by fractional pixels.
551TEST_P(DlGoldenTest, SubpixelScaled) {
552 SetWindowSize(impeller::ISize(1024, 200));
554 Scalar scalar = 0.75;
555 auto callback = [&](Scalar offset_x) -> sk_sp<DisplayList> {
556 DisplayListBuilder builder;
557 builder.Scale(scalar, scalar);
558 DlPaint paint;
559 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
560 builder.DrawPaint(paint);
561 RenderTextInCanvasSkia(&builder, "ui", "Roboto-Regular.ttf",
562 DlPoint::MakeXY(offset_x, 180),
565 .is_subpixel = true,
566 });
567 return builder.Build();
568 };
569
570 LeftmostIntensity intensity[5];
571 Scalar offset_fraction = 0.25 / scalar;
572 for (int i = 0; i <= 4; ++i) {
573 Scalar offset = 10 + (offset_fraction * i);
574 std::unique_ptr<impeller::testing::Screenshot> right =
575 MakeScreenshot(callback(offset));
576 if (!right) {
577 GTEST_SKIP() << "making screenshots not supported.";
578 }
579 intensity[i] = CalculateLeftmostIntensity(right.get());
580 ASSERT_NE(intensity[i].value, 0);
581 }
582 for (int i = 1; i < 5; ++i) {
583 EXPECT_TRUE(intensity[i].x - intensity[i - 1].x == 1 ||
584 intensity[i].value < intensity[i - 1].value)
585 << i;
586 }
587 EXPECT_EQ(intensity[4].x - intensity[0].x, 1);
588}
589
590// Checks that the left most edge of the glyph is fading out as we push
591// it to the right by fractional pixels.
592TEST_P(DlGoldenTest, SubpixelScaledTranslated) {
593 SetWindowSize(impeller::ISize(1024, 200));
595 Scalar scalar = 0.75;
596 auto callback = [&](Scalar offset_x) -> sk_sp<DisplayList> {
597 DisplayListBuilder builder;
598 builder.Scale(scalar, scalar);
599 DlPaint paint;
600 paint.setColor(DlColor::ARGB(1, 0, 0, 0));
601 builder.DrawPaint(paint);
602 builder.Translate(offset_x, 180);
603 RenderTextInCanvasSkia(&builder, "ui", "Roboto-Regular.ttf",
604 DlPoint::MakeXY(0, 0),
607 .is_subpixel = true,
608 });
609 return builder.Build();
610 };
611
612 LeftmostIntensity intensity[5];
613 Scalar offset_fraction = 0.25 / scalar;
614 for (int i = 0; i <= 4; ++i) {
615 Scalar offset = 10 + (offset_fraction * i);
616 std::unique_ptr<impeller::testing::Screenshot> right =
617 MakeScreenshot(callback(offset));
618 if (!right) {
619 GTEST_SKIP() << "making screenshots not supported.";
620 }
621 intensity[i] = CalculateLeftmostIntensity(right.get());
622 ASSERT_NE(intensity[i].value, 0);
623 }
624 for (int i = 1; i < 5; ++i) {
625 EXPECT_TRUE(intensity[i].x - intensity[i - 1].x == 1 ||
626 intensity[i].value < intensity[i - 1].value)
627 << i;
628 }
629 EXPECT_EQ(intensity[4].x - intensity[0].x, 1);
630}
631
632} // namespace testing
633} // 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
bool RenderTextInCanvasSkia(DlCanvas *canvas, const std::string &text, const std::string_view &font_fixture, DlPoint position, const TextRenderOptions &options)
TEST_P(DlGoldenTest, TextBlurMaskFilterRespectCTM)
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:26
#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