7#include "absl/strings/str_split.h"
28#ifdef IMPELLER_SUPPORTS_RENDERING
33#include "flutter/third_party/skia/include/core/SkColor.h"
34#include "flutter/third_party/skia/include/core/SkColorFilter.h"
151constexpr uint8_t toC(
DlScalar fComp) {
152 return round(fComp * 255);
155constexpr uint32_t PremultipliedArgb(
const DlColor& color) {
160 return (color.
argb() & 0xFF000000) |
161 toC(color.
getRedF() * f) << 16 |
178 for (
int y = 0;
y <
width;
y += cbdim) {
179 for (
int x = 0;
x <
height;
x += cbdim) {
187 const sk_sp<DlImage>&
image) {
188 return std::make_shared<DlImageColorSource>(
image,
199 : warning_(warning) {}
202 if (warnings_sent_.find(
name) == warnings_sent_.end()) {
203 warnings_sent_.insert(
name);
209 std::string warning_;
210 std::set<std::string> warnings_sent_;
237 copy.bounds_pad_ +=
DlPoint(bounds_pad_x, bounds_pad_y);
243 copy.scale_ *=
DlPoint(scale_x, scale_y);
250 copy.absolute_pad_ +=
DlPoint(absolute_pad_x, absolute_pad_y);
257 copy.clip_pad_ +=
DlPoint(absolute_pad_x, absolute_pad_y);
276 return rect.
Expand(outset_x, outset_y);
280 int worst_bounds_pad_x,
281 int worst_bounds_pad_y)
const {
283 allowed = allowed.
Expand(bounds_pad_.
x, bounds_pad_.
y);
284 allowed =
Scale(allowed, scale_);
285 allowed = allowed.
Expand(absolute_pad_.
x, absolute_pad_.
y);
287 allowed = allowed.
Expand(clip_pad_.
x, clip_pad_.
y);
289 int pad_left = std::max(0, pix_bounds.
GetLeft() - rounded.
GetLeft());
290 int pad_top = std::max(0, pix_bounds.
GetTop() - rounded.
GetTop());
293 int allowed_pad_x = std::max(pad_left, pad_right);
294 int allowed_pad_y = std::max(pad_top, pad_bottom);
295 if (worst_bounds_pad_x > allowed_pad_x ||
296 worst_bounds_pad_y > allowed_pad_y) {
297 FML_LOG(ERROR) <<
"acceptable bounds padding: "
298 << allowed_pad_x <<
", " << allowed_pad_y;
300 return (worst_bounds_pad_x > allowed_pad_x ||
301 worst_bounds_pad_y > allowed_pad_y);
307 return bounds_pad_ == other.bounds_pad_ && scale_ == other.scale_ &&
308 absolute_pad_ == other.absolute_pad_ && clip_ == other.clip_ &&
309 clip_pad_ == other.clip_pad_ &&
310 discrete_offset_ == other.discrete_offset_;
316 DlPoint absolute_pad_ = {0, 0};
323class RenderEnvironment;
356 .render_bounds = bounds,
400 : dl_setup_(dl_setup),
401 dl_render_(dl_render),
402 dl_restore_(dl_restore) {}
409 dl_setup_({env, canvas, paint});
410 setup_paint_ = paint;
415 dl_render_({env, canvas, paint});
416 dl_restore_({env, canvas, paint});
422 Render(env, &builder, info);
423 return builder.
Build();
440 : display_list_(
std::move(display_list)) {}
449 sk_sp<DisplayList> display_list_;
455 : provider_(provider), format_(
format) {}
472 ref_dl_result_ =
GetResult(info, dl_job);
480 std::shared_ptr<DlSurfaceInstance>
surface =
487 renderer.
Render(*
this, &builder, info);
488 sk_sp<DisplayList> display_list = builder.
Build();
489 DlRect dl_bounds = display_list->GetBounds();
490 surface->RenderDisplayList(display_list);
515 if (test_image_ ==
nullptr) {
516 test_image_ = MakeTestImage();
522 if (test_text_ ==
nullptr) {
523 test_text_ = MakeTestText();
529 mutable std::shared_ptr<DlSurfaceInstance> cached_surface_;
530 std::shared_ptr<DlSurfaceInstance> getSurface(
int width,
int height)
const {
532 if (cached_surface_ ==
nullptr ||
533 cached_surface_->width() !=
width ||
534 cached_surface_->height() !=
height) {
535 cached_surface_.reset();
539 return cached_surface_;
542 const DlSurfaceProvider* provider_;
545 DlPaint ref_dl_paint_;
548 RenderResult ref_dl_result_;
550 mutable sk_sp<DlImage> test_image_;
551 sk_sp<DlImage> MakeTestImage()
const {
552 std::shared_ptr<DlSurfaceInstance>
surface =
557 surface->RenderDisplayList(builder.Build());
559 return surface->SnapshotToImage();
562 mutable std::shared_ptr<DlText> test_text_;
563 std::shared_ptr<DlText> MakeTestText()
const {
565 if (provider_->TargetsImpeller()) {
566#ifdef IMPELLER_SUPPORTS_RENDERING
576 static sk_sp<SkTextBlob> MakeTextBlob(
const std::string&
string,
579 sk_sp<SkTypeface> face = font.refTypeface();
581 FML_CHECK(face->countGlyphs() > 0) <<
"No glyphs in font";
582 return SkTextBlob::MakeFromText(
string.c_str(),
string.
size(), font,
583 SkTextEncoding::kUTF8);
625 has_mutating_save_layer_, fuzzy_compare_components_);
630 has_mutating_save_layer_, fuzzy_compare_components_);
633 std::string
info()
const {
return info_; }
643 const std::string info_;
647 const bool has_diff_clip_;
648 const bool has_mutating_save_layer_;
649 const bool fuzzy_compare_components_;
742 getCap(ref_attr, geo_flags) !=
getCap(attr, geo_flags)) {
754 ref_miter < 1.4 || test_miter < 1.4) {
755 if (ref_miter != test_miter) {
837 h_tolerance = v_tolerance =
adjust;
841 return new_tolerance;
862 is_draw_text_blob_ =
true;
866 is_draw_display_list_ =
true;
870 is_draw_line_ =
true;
874 is_draw_arc_center_ =
true;
878 is_draw_path_ =
true;
882 ignores_dashes_ =
true;
886 is_horizontal_line_ =
true;
890 is_vertical_line_ =
true;
898 bool is_draw_text_blob_ =
false;
899 bool is_draw_display_list_ =
false;
900 bool is_draw_line_ =
false;
901 bool is_draw_arc_center_ =
false;
902 bool is_draw_path_ =
false;
903 bool ignores_dashes_ =
false;
904 bool is_horizontal_line_ =
false;
905 bool is_vertical_line_ =
false;
910 static std::string failure_image_directory_;
911 static bool save_failure_images_;
912 static std::vector<std::string> failure_image_filenames_;
918 if (failure_image_filenames_.empty()) {
922 FML_LOG(INFO) << failure_image_filenames_.size() <<
" images saved in "
923 << failure_image_directory_;
924 for (
const std::string& filename : failure_image_filenames_) {
925 FML_LOG(INFO) <<
" " << filename;
932 static void RenderAll(
const std::unique_ptr<DlSurfaceProvider>& provider,
942 if (
params.uses_paint()) {
961 ctx.canvas->DrawRect(
964 ctx.canvas->Restore();
968 ctx.canvas->Restore();
976 "With prior save/clip/restore",
982 p2.setBlendMode(DlBlendMode::kClear);
988 "saveLayer no paint, no bounds",
992 .with_restore(dl_safe_restore,
false));
995 "saveLayer no paint, with bounds",
999 .with_restore(dl_safe_restore,
true));
1002 "saveLayer with alpha, no bounds",
1005 save_p.
setColor(alpha_layer_color);
1008 .with_restore(dl_safe_restore,
true));
1011 "saveLayer with peephole alpha, no bounds",
1014 save_p.
setColor(alpha_layer_color);
1017 .with_restore(dl_opt_restore,
true,
true));
1020 "saveLayer with alpha and bounds",
1023 save_p.
setColor(alpha_layer_color);
1026 .with_restore(dl_safe_restore,
true));
1053 testP, backdrop_env, tolerance,
1055 "saveLayer with backdrop",
1057 dl_backdrop_setup(ctx);
1059 dl_content_setup(ctx);
1061 .with_restore(dl_safe_restore,
true));
1064 "saveLayer with bounds and backdrop",
1066 dl_backdrop_setup(ctx);
1069 dl_content_setup(ctx);
1071 .with_restore(dl_safe_restore,
true));
1073 testP, backdrop_env, tolerance,
1075 "clipped saveLayer with backdrop",
1077 dl_backdrop_setup(ctx);
1080 dl_content_setup(ctx);
1082 .with_restore(dl_safe_restore,
true));
1088 constexpr float rotate_alpha_color_matrix[20] = {
1095 std::shared_ptr<const DlColorFilter> dl_alpha_rotate_filter =
1103 "saveLayer ColorFilter, no bounds",
1110 .with_restore(dl_safe_restore,
true));
1115 "saveLayer ColorFilter and bounds",
1122 .with_restore(dl_safe_restore,
true));
1129 constexpr float color_matrix[20] = {
1136 std::shared_ptr<const DlColorFilter> dl_color_filter =
1138 std::shared_ptr<DlImageFilter> dl_cf_image_filter =
1146 "saveLayer ImageFilter, no bounds",
1153 .with_restore(dl_safe_restore,
true));
1158 "saveLayer ImageFilter and bounds",
1165 .with_restore(dl_safe_restore,
true));
1196 testP, aa_env, aa_tolerance,
1198 "AntiAlias == True",
1201 testP, aa_env, aa_tolerance,
1203 "AntiAlias == False",
1212 testP, env, tolerance,
1219 testP, env, tolerance,
1274 RenderWith(testP, blur_env, blur_5_tolerance,
1276 "ImageFilter == Decal Blur 5",
1288 RenderWith(testP, blur_env, blur_5_tolerance,
1290 "ImageFilter == Clamp Blur 5",
1317 "ImageFilter == Dilate 5",
1319 dl_dilate_setup(ctx);
1345 "ImageFilter == Erode 1",
1347 dl_erode_setup(ctx);
1355 constexpr float rotate_color_matrix[20] = {
1362 std::shared_ptr<const DlColorFilter> dl_color_filter =
1371 "ColorFilter == RotateRGB",
1386 "ColorFilter == Invert",
1405 "MaskFilter == Blur 5",
1431 std::shared_ptr<DlColorSource> dl_gradient =
1440 "LinearGradient GYB",
1483 "Stroke + defaults",
1493 "Fill + unnecessary StrokeWidth 10",
1511 RenderWith(testP, stroke_base_env, tolerance,
1518 RenderWith(testP, stroke_base_env, tolerance,
1526 RenderWith(testP, stroke_base_env, tolerance,
1528 "Stroke Width 5, Square Cap",
1534 RenderWith(testP, stroke_base_env, tolerance,
1536 "Stroke Width 5, Round Cap",
1543 RenderWith(testP, stroke_base_env, tolerance,
1545 "Stroke Width 5, Bevel Join",
1551 RenderWith(testP, stroke_base_env, tolerance,
1553 "Stroke Width 5, Round Join",
1560 RenderWith(testP, stroke_base_env, tolerance,
1562 "Stroke Width 5, Miter 10",
1570 RenderWith(testP, stroke_base_env, tolerance,
1572 "Stroke Width 5, Miter 0",
1590 testP, env, tolerance,
1595 testP, env, tolerance,
1600 testP, env, skewed_tolerance,
1605 testP, env, skewed_tolerance,
1620 1.0 + tweak, tweak, 0, 5,
1621 tweak, 1.0 + tweak, 0, 10,
1630 testP, env, skewed_tolerance,
1632 "Transform 2D Affine Matrix",
1637 testP, env, skewed_tolerance,
1639 "Transform 2D Affine inline",
1642 tweak, 1.0 + tweak, 10);
1649 0.0f, 0.0f, 1.0f, 0.0f,
1650 0.0f, 0.0f, .001f, 1.0f);
1658 testP, env, skewed_tolerance,
1660 "Transform Full Perspective Matrix",
1665 testP, env, skewed_tolerance,
1667 "Transform Full Perspective inline",
1671 0.997564, 0.000000, 0.069756, 0.243591,
1672 0.003651, 0.998630, -0.052208, -0.228027,
1673 -0.069661, 0.052336, 0.996197, 1.732491,
1674 -0.000070, 0.000052, 0.000996, 1.001732
1700 "Hard ClipRect inset by 15.4",
1706 "AntiAlias ClipRect inset by 15.4",
1712 "Hard ClipRect Diff, inset by 15.4",
1725 "AntiAlias ClipOval",
1731 "Hard ClipOval Diff",
1749 "Hard ClipRRect with radius of 9",
1756 "AntiAlias ClipRRect with radius of 9",
1763 "Hard ClipRRect Diff, with radius of 9",
1781 "Hard ClipPath inset by 15.4",
1788 "AntiAlias ClipPath inset by 15.4",
1795 "Hard ClipPath Diff, inset by 15.4",
1821 FML_LOG(ERROR) <<
"Could not create directory (" << dir
1822 <<
") for impeller failure images" <<
", ret = " << ret.
get()
1823 <<
", errno = " << errno;
1828 std::string base_dir =
"./failure_images";
1832 for (
int i = 0;
i < 10000;
i++) {
1833 std::string sub_dir = std::to_string(
i);
1834 while (sub_dir.length() < 4) {
1835 sub_dir =
"0" + sub_dir;
1837 std::string try_dir = base_dir +
"/" + sub_dir;
1842 failure_image_directory_ = try_dir;
1848 FML_LOG(ERROR) <<
"Too many output directories for failure images";
1852 const std::string& op_desc,
1853 const std::string& reason) {
1854 if (!save_failure_images_) {
1857 if (failure_image_directory_.length() == 0) {
1859 if (failure_image_directory_.length() == 0) {
1860 save_failure_images_ =
false;
1865 std::string filename = failure_image_directory_ +
"/";
1866 for (
const char& ch : op_desc) {
1867 filename += (ch ==
':' || ch ==
' ') ?
'_' : ch;
1869 filename = filename +
".png";
1871 FML_LOG(ERROR) <<
"Could not write output to " << filename;
1873 failure_image_filenames_.push_back(filename);
1874 FML_LOG(ERROR) << reason <<
": " << filename;
1904 std::string test_name =
1905 ::testing::UnitTest::GetInstance()->current_test_info()->name();
1906 const std::string info =
1926 const sk_sp<DisplayList> display_list =
1932 DlRect dl_bounds = display_list->GetBounds();
1934 info +
" (DisplayList reference)", bg);
1949 info +
" (attribute should not have effect)") &&
1954 info +
" (attribute should affect rendering)") &&
1958 if (save_failure_images_ && !success) {
1959 FML_LOG(ERROR) <<
"Rendering issue encountered for: " << *display_list;
1960 save_to_png(dl_result, info +
" (Test Result)",
"output saved in");
1962 "compare to reference without attributes");
1975 if (display_list->can_apply_group_opacity()) {
1977 info +
" with Group Opacity", bg);
1982 for (
int i = 0;
i < 32;
i += 8) {
1983 int comp_a = (pixel_a >>
i) & 0xff;
1984 int comp_b = (pixel_b >>
i) & 0xff;
1985 if (std::abs(comp_a - comp_b) > fudge) {
2005 const sk_sp<DisplayList>& display_list,
2007 const std::string& info,
2020 env.
GetResult(opacity_info, opacity_job);
2028 int pixels_touched = 0;
2029 int pixels_different = 0;
2041 const uint32_t* ref_row = ref_result.
pixel_data->addr32(0,
y);
2042 const uint32_t* test_row = group_opacity_result.
pixel_data->addr32(0,
y);
2044 uint32_t ref_pixel = ref_row[
x];
2045 uint32_t test_pixel = test_row[
x];
2046 if (ref_pixel != bg.
argb() || test_pixel != bg.
argb()) {
2048 for (
int i = 0;
i < 32;
i += 8) {
2049 int ref_comp = (ref_pixel >>
i) & 0xff;
2050 int bg_comp = (bg.
argb() >>
i) & 0xff;
2051 DlScalar faded_comp = bg_comp + (ref_comp - bg_comp) * opacity;
2052 int test_comp = (test_pixel >>
i) & 0xff;
2053 if (std::abs(faded_comp - test_comp) > fudge) {
2054 int diff = std::abs(faded_comp - test_comp);
2055 if (max_diff < diff) {
2065 ASSERT_GT(pixels_touched, 20) << info;
2066 if (pixels_different > 1) {
2067 FML_LOG(ERROR) <<
"max diff == " << max_diff <<
" for " << info;
2069 ASSERT_LE(pixels_different, 1) << info;
2074 const std::string& info,
2076 uint32_t untouched = PremultipliedArgb(bg);
2077 int pixels_touched = 0;
2083 const uint32_t* ref_row = ref_result.
pixel_data->addr32(0,
y);
2085 if (ref_row[
x] != untouched) {
2093 EXPECT_EQ(pixels_oob, 0) << info;
2094 EXPECT_GT(pixels_touched, 0) << info;
2095 return pixels_oob == 0 && pixels_touched > 0;
2102 const uint32_t* ref_row = ref_result.
pixel_data->addr32(0,
y);
2103 const uint32_t* test_row = test_result.
pixel_data->addr32(0,
y);
2105 if (ref_row[
x] != test_row[
x]) {
2106 if (ref_row[
x] == 0) {
2118 const std::string& info) {
2119 uint32_t w = test_result.
pixel_data->width();
2121 EXPECT_EQ(w, ref_result.
pixel_data->width()) << info;
2122 EXPECT_EQ(
h, ref_result.
pixel_data->height()) << info;
2123 int pixels_different = 0;
2124 for (uint32_t
y = 0;
y <
h;
y++) {
2125 const uint32_t* ref_row = ref_result.
pixel_data->addr32(0,
y);
2126 const uint32_t* test_row = test_result.
pixel_data->addr32(0,
y);
2127 for (uint32_t
x = 0;
x < w;
x++) {
2128 if (ref_row[
x] != test_row[
x]) {
2129 if (should_match && pixels_different < 5) {
2130 FML_LOG(ERROR) << std::hex << ref_row[
x] <<
" != " << test_row[
x];
2137 EXPECT_EQ(pixels_different, 0) << info;
2138 return pixels_different == 0;
2140 EXPECT_NE(pixels_different, 0) << info;
2141 return pixels_different != 0;
2147 const std::string& info,
2151 bool fuzzyCompares =
false,
2154 bool printMismatches =
false) {
2155 uint32_t untouched = PremultipliedArgb(bg);
2161 int pixels_different = 0;
2163 uint32_t min_x =
width;
2168 const uint32_t* ref_row = ref_result.
pixel_data->addr32(0,
y);
2169 const uint32_t* test_row = test_result.
pixel_data->addr32(0,
y);
2170 for (uint32_t
x = 0;
x <
width;
x++) {
2171 if (bounds && test_row[
x] != untouched) {
2188 bool match = fuzzyCompares ?
fuzzyCompare(test_row[
x], ref_row[
x], 1)
2189 : test_row[
x] == ref_row[
x];
2191 if (printMismatches && pixels_different < 5) {
2192 FML_LOG(ERROR) <<
"pix[" <<
x <<
", " <<
y
2193 <<
"] mismatch: " << std::hex << test_row[
x]
2194 <<
"(test) != (ref)" << ref_row[
x] << std::dec;
2200 if (pixels_oob > 0) {
2201 FML_LOG(ERROR) <<
"pix bounds["
2204 FML_LOG(ERROR) <<
"dl_bounds[" << bounds <<
"]";
2205 }
else if (bounds) {
2208 ASSERT_EQ(pixels_oob, 0) << info;
2209 ASSERT_EQ(pixels_different, 0) << info;
2219 int pad_left = std::max(0, pixLeft - bounds.
GetLeft());
2220 int pad_top = std::max(0, pixTop - bounds.
GetTop());
2221 int pad_right = std::max(0, bounds.
GetRight() - pixRight);
2222 int pad_bottom = std::max(0, bounds.
GetBottom() - pixBottom);
2226 int pix_width = pix_size.
width;
2227 int pix_height = pix_size.
height;
2228 int worst_pad_x = std::max(pad_left, pad_right);
2229 int worst_pad_y = std::max(pad_top, pad_bottom);
2230 if (tolerance->
overflows(pix_bounds, worst_pad_x, worst_pad_y)) {
2231 FML_LOG(ERROR) <<
"Computed bounds for " << info;
2232 FML_LOG(ERROR) <<
"pix bounds["
2233 << pixLeft <<
", " << pixTop <<
" => "
2234 << pixRight <<
", " << pixBottom
2236 FML_LOG(ERROR) <<
"dl_bounds[" << bounds <<
"]";
2237 FML_LOG(ERROR) <<
"Bounds overly conservative by up to "
2238 << worst_pad_x <<
", " << worst_pad_y
2239 <<
" (" << (worst_pad_x * 100.0 / pix_width)
2240 <<
"%, " << (worst_pad_y * 100.0 / pix_height) <<
"%)";
2241 int pix_area = pix_size.
Area();
2242 int dl_area = bounds.
Area();
2243 FML_LOG(ERROR) <<
"Total overflow area: " << (dl_area - pix_area)
2244 <<
" (+" << (dl_area * 100.0 / pix_area - 100.0)
2251std::string CanvasCompareTester::failure_image_directory_ =
"";
2252bool CanvasCompareTester::save_failure_images_ =
false;
2253std::vector<std::string> CanvasCompareTester::failure_image_filenames_;
2269 test_backends_.clear();
2271 std::vector<std::string>
args = ::testing::internal::GetArgvs();
2275 if (command_line.
HasOption(
"--save-failure-images")) {
2279 std::vector<BackendType> enable_backends =
2282 AddProvider(backend);
2285 std::vector<BackendType> disable_backends =
2288 RemoveProvider(backend);
2292 AddProvider(BackendType::kSkiaSoftware);
2295 std::string providers =
"";
2299 FML_LOG(INFO) <<
"Running tests on [" << providers <<
" ]";
2307 return test_backends_;
2311 std::unique_ptr<DlSurfaceProvider> provider =
2313 if (provider ==
nullptr) {
2315 <<
" not supported (ignoring)";
2319 PixelFormat::kN32Premul);
2327 std::unique_ptr<DlSurfaceProvider> provider =
GetProvider(backend);
2333 static std::vector<BackendType> test_backends_;
2342 if (existing ==
type) {
2343 FML_LOG(ERROR) <<
"Backend " << provider->GetBackendName()
2344 <<
" already added";
2348 test_backends_.push_back(
type);
2358 for (
auto it = test_backends_.begin(); it < test_backends_.end(); it++) {
2360 test_backends_.erase(it);
2364 FML_LOG(ERROR) <<
"Backend " << provider->GetBackendName()
2365 <<
" was not present to remove";
2369 static std::vector<BackendType> ParseBackendList(
2370 const std::vector<std::string_view>& arg_list) {
2371 std::vector<BackendType> value_list;
2372 for (
const std::string_view& name_list : arg_list) {
2373 std::vector<std::string> names = absl::StrSplit(name_list,
',');
2374 for (
const std::string&
name : names) {
2375 std::optional<BackendType> backend =
2377 if (backend.has_value()) {
2378 value_list.push_back(backend.value());
2380 FML_LOG(ERROR) <<
"Unrecognized backend name: " <<
name;
2390std::vector<BackendType> DisplayListRendering::test_backends_;
2609 path_builder.
Close();
2614 path_builder.
Close();
2633 kDrawArcNoCenterFlags));
2652 kDrawArcWithCenterFlags)
2653 .set_draw_arc_center());
2678 {x0, y0}, {x1, y0}, {x2, y0}, {x3, y0}, {x4, y0}, {x5, y0}, {x6, y0},
2679 {x0, y1}, {x1, y1}, {x2, y1}, {x3, y1}, {x4, y1}, {x5, y1}, {x6, y1},
2680 {x0, y2}, {x1, y2}, {x2, y2}, {x3, y2}, {x4, y2}, {x5, y2}, {x6, y2},
2681 {x0, y3}, {x1, y3}, {x2, y3}, {x3, y3}, {x4, y3}, {x5, y3}, {x6, y3},
2682 {x0, y4}, {x1, y4}, {x2, y4}, {x3, y4}, {x4, y4}, {x5, y4}, {x6, y4},
2683 {x0, y5}, {x1, y5}, {x2, y5}, {x3, y5}, {x4, y5}, {x5, y5}, {x6, y5},
2684 {x0, y6}, {x1, y6}, {x2, y6}, {x3, y6}, {x4, y6}, {x5, y6}, {x6, y6},
2695 kDrawPointsAsPointsFlags)
2720 {x0, y0}, {x3, y3}, {x3, y0}, {x0, y3},
2731 ASSERT_TRUE((count & 1) == 0);
2738 kDrawPointsAsLinesFlags));
2756 const int count1 =
sizeof(points1) /
sizeof(points1[0]);
2764 kDrawPointsAsPolygonFlags));
2787 const DlColor dl_colors[6] = {
2791 const std::shared_ptr<DlVertices> dl_vertices =
2800 kDrawVerticesFlags));
2831 const std::shared_ptr<DlVertices> dl_vertices =
2839 v_paint.setColorSource(MakeColorSource(ctx.env.GetTestImage()));
2844 kDrawVerticesFlags));
2855 kDrawImageWithPaintFlags));
2877 kDrawImageWithPaintFlags));
2890 kDrawImageRectWithPaintFlags));
2903 kDrawImageRectFlags));
2916 kDrawImageRectWithPaintFlags));
2928 kDrawImageNineWithPaintFlags));
2940 kDrawImageNineFlags));
2952 kDrawImageNineWithPaintFlags));
2973 relative_rect(0.0f, 0.0f, 0.5f, 0.5f),
2974 relative_rect(0.5f, 0.0f, 1.0f, 0.5f),
2975 relative_rect(0.5f, 0.5f, 1.0f, 1.0f),
2976 relative_rect(0.0f, 0.5f, 0.5f, 1.0f),
2989 dl_colors, 4, DlBlendMode::kSrcOver,
2990 dl_sampling,
nullptr, &ctx.
paint);
2992 kDrawAtlasWithPaintFlags));
3013 relative_rect(0.0f, 0.0f, 0.5f, 0.5f),
3014 relative_rect(0.5f, 0.0f, 1.0f, 0.5f),
3015 relative_rect(0.5f, 0.5f, 1.0f, 1.0f),
3016 relative_rect(0.0f, 0.5f, 0.5f, 1.0f),
3029 dl_colors, 4, DlBlendMode::kSrcOver,
3030 dl_sampling,
nullptr,
nullptr);
3053 relative_rect(0.0f, 0.0f, 0.5f, 0.5f),
3054 relative_rect(0.5f, 0.0f, 1.0f, 0.5f),
3055 relative_rect(0.5f, 0.5f, 1.0f, 1.0f),
3056 relative_rect(0.0f, 0.5f, 0.5f, 1.0f),
3069 dl_colors, 2, DlBlendMode::kSrcOver,
3070 dl_sampling,
nullptr, &ctx.
paint);
3072 kDrawAtlasWithPaintFlags));
3095 return builder.
Build();
3105 kDrawDisplayListFlags)
3106 .set_draw_display_list());
3113#if defined(OS_FUCHSIA)
3114 GTEST_SKIP() <<
"Rendering comparisons require a valid default font manager";
3123 render_y_1_3, paint);
3125 render_y_2_3, paint);
3130 .set_draw_text_blob(),
3209 std::shared_ptr<DlImageFilter> layer_filter =
3220 kSaveLayerWithPaintFlags);
3221 CaseParameters case_params(
"Filtered SaveLayer with clipped content");
3225 std::unique_ptr<DlSurfaceProvider> provider = GetProvider(back_end);
3234 float commutable_color_matrix[]{
3242 float non_commutable_color_matrix[]{
3252 contract_matrix.
Scale({0.9f, 0.9f});
3255 std::vector<DlScalar> opacities = {
3260 std::vector<std::shared_ptr<const DlColorFilter>> color_filters = {
3267 std::vector<std::shared_ptr<DlImageFilter>> image_filters = {
3292 auto test_attributes_env =
3294 const DlPaint& paint_both,
bool same,
bool rev_same,
3295 const std::string& desc1,
const std::string& desc2,
3300 render_content(nested_builder);
3306 render_content(reverse_builder);
3311 render_content(combined_builder);
3313 env->GetResult(combined_builder.
Build());
3322 const bool always =
false;
3327 if (always || same) {
3329 nested_results, combined_results,
3330 "nested " + desc1 +
" then " + desc2,
nullptr,
3333 combined_results.
pixel_data->height(),
true);
3335 if (always || rev_same) {
3337 reverse_results, combined_results,
3338 "nested " + desc2 +
" then " + desc1,
nullptr,
3341 combined_results.
pixel_data->height(),
true);
3346 auto test_attributes = [test_attributes_env](
3348 const DlPaint& paint_both,
bool same,
3349 bool rev_same,
const std::string& desc1,
3350 const std::string& desc2) ->
void {
3352 std::unique_ptr<DlSurfaceProvider> provider = GetProvider(back_end);
3353 std::unique_ptr<RenderEnvironment> env =
3354 std::make_unique<RenderEnvironment>(provider.get(),
3355 PixelFormat::kN32Premul);
3356 test_attributes_env(paint1, paint2, paint_both,
3357 same, rev_same, desc1, desc2, env.get());
3363 for (
size_t cfi = 0; cfi < color_filters.size(); cfi++) {
3364 std::shared_ptr<const DlColorFilter>& color_filter = color_filters[cfi];
3365 std::string cf_desc =
"color filter #" + std::to_string(cfi + 1);
3368 for (
size_t oi = 0; oi < opacities.size(); oi++) {
3370 std::string op_desc =
"opacity " + std::to_string(opacity);
3373 DlPaint combined_paint = nested_paint1;
3376 bool op_then_cf_works = opacity <= 0.0 || opacity >= 1.0 ||
3377 color_filter->can_commute_with_opacity();
3379 test_attributes(nested_paint1, nested_paint2, combined_paint,
true,
3380 op_then_cf_works, cf_desc, op_desc);
3388 for (
size_t oi = 0; oi < opacities.size(); oi++) {
3390 std::string op_desc =
"opacity " + std::to_string(opacity);
3393 for (
size_t ifi = 0; ifi < image_filters.size(); ifi++) {
3394 std::shared_ptr<DlImageFilter>& image_filter = image_filters[ifi];
3395 std::string if_desc =
"image filter #" + std::to_string(ifi + 1);
3398 DlPaint combined_paint = nested_paint1;
3401 bool if_then_op_works = opacity <= 0.0 || opacity >= 1.0;
3402 test_attributes(nested_paint1, nested_paint2, combined_paint,
true,
3403 if_then_op_works, op_desc, if_desc);
3409 for (
size_t cfi = 0; cfi < color_filters.size(); cfi++) {
3410 std::shared_ptr<const DlColorFilter>& color_filter = color_filters[cfi];
3411 std::string cf_desc =
"color filter #" + std::to_string(cfi + 1);
3414 for (
size_t ifi = 0; ifi < image_filters.size(); ifi++) {
3415 std::shared_ptr<DlImageFilter>& image_filter = image_filters[ifi];
3416 std::string if_desc =
"image filter #" + std::to_string(ifi + 1);
3419 DlPaint combined_paint = nested_paint1;
3422 test_attributes(nested_paint1, nested_paint2, combined_paint,
true,
false,
3429 auto test_matrix = [](
int element,
DlScalar value) ->
void {
3439 "matrix[" + std::to_string(element) +
"] = " + std::to_string(
value);
3440 float original_value = matrix[element];
3441 matrix[element] =
value;
3448 std::shared_ptr<const DlColorFilter> dl_filter =
3450 bool is_identity = (dl_filter ==
nullptr || original_value ==
value);
3460 sk_sp<DisplayList> display_list1 = builder1.
Build();
3469 sk_sp<DisplayList> display_list2 = builder2.
Build();
3472 std::unique_ptr<DlSurfaceProvider> provider = GetProvider(back_end);
3473 std::unique_ptr<RenderEnvironment> env =
3474 std::make_unique<RenderEnvironment>(provider.get(),
3475 PixelFormat::kN32Premul);
3479 results1, results2, is_identity, desc +
" filter affects rendering");
3480 int modified_transparent_pixels =
3484 modified_transparent_pixels != 0)
3492 for (
int i = 0;
i < 20;
i++) {
3493 test_matrix(
i, -0.25);
3495 test_matrix(
i, 0.25);
3497 test_matrix(
i, 1.25);
3498 test_matrix(
i, SK_ScalarNaN);
3499 test_matrix(
i, SK_ScalarInfinity);
3500 test_matrix(
i, -SK_ScalarInfinity);
3505 auto test_matrix = [](
int element,
DlScalar value) ->
void {
3515 "matrix[" + std::to_string(element) +
"] = " + std::to_string(
value);
3516 matrix[element] =
value;
3517 std::shared_ptr<const DlColorFilter> filter =
3519 EXPECT_EQ(std::isfinite(
value), filter !=
nullptr);
3532 sk_sp<DisplayList> display_list1 = builder1.
Build();
3541 sk_sp<DisplayList> display_list2 = builder2.
Build();
3544 std::unique_ptr<DlSurfaceProvider> provider = GetProvider(back_end);
3545 std::unique_ptr<RenderEnvironment> env =
3546 std::make_unique<RenderEnvironment>(provider.get(),
3547 PixelFormat::kN32Premul);
3550 if (!filter || filter->can_commute_with_opacity()) {
3564 for (
int i = 0;
i < 20;
i++) {
3565 test_matrix(
i, -0.25);
3567 test_matrix(
i, 0.25);
3569 test_matrix(
i, 1.1);
3570 test_matrix(
i, SK_ScalarNaN);
3571 test_matrix(
i, SK_ScalarInfinity);
3572 test_matrix(
i, -SK_ScalarInfinity);
3576#define FOR_EACH_BLEND_MODE_ENUM(FUNC) \
3609 std::stringstream desc_str;
3611 desc_str <<
"blend[" << mode_string <<
", " << color <<
"]";
3612 std::string desc = desc_str.str();
3626 sk_sp<DisplayList> display_list1 = builder1.
Build();
3635 sk_sp<DisplayList> display_list2 = builder2.
Build();
3638 std::unique_ptr<DlSurfaceProvider> provider = GetProvider(back_end);
3639 std::unique_ptr<RenderEnvironment> env =
3640 std::make_unique<RenderEnvironment>(provider.get(),
3641 PixelFormat::kN32Premul);
3644 int modified_transparent_pixels =
3648 modified_transparent_pixels != 0)
3649 << provider->GetBackendName() <<
": " << desc;
3661#define TEST_MODE(V) test_mode(DlBlendMode::V);
3668 std::stringstream desc_str;
3670 desc_str <<
"blend[" << mode_string <<
", " << color <<
"]";
3671 std::string desc = desc_str.str();
3691 sk_sp<DisplayList> display_list1 = builder1.
Build();
3700 sk_sp<DisplayList> display_list2 = builder2.
Build();
3703 std::unique_ptr<DlSurfaceProvider> provider = GetProvider(back_end);
3704 std::string provider_desc =
" " + provider->GetBackendName() +
" " + desc;
3705 std::unique_ptr<RenderEnvironment> env =
3706 std::make_unique<RenderEnvironment>(provider.get(),
3707 PixelFormat::kN32Premul);
3713 results2, results1, provider_desc,
nullptr,
nullptr,
3730#define TEST_MODE(V) test_mode(DlBlendMode::V);
3756 const int step = 0x55;
3757 static_assert(step * 3 == 255);
3758 for (
int a = step; a < 256; a += step) {
3759 for (
int r = step; r < 256; r += step) {
3760 for (
int g = step; g < 256; g += step) {
3761 for (
int b = step; b < 256; b += step) {
3768 static constexpr float color_filter_matrix_nomtb[] = {
3769 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
3770 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
3771 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
3772 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
3774 static constexpr float color_filter_matrix_mtb[] = {
3775 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
3776 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
3777 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
3778 0.0001, 0.0001, 0.0001, 0.9997, 0.1,
3804 std::shared_ptr<DlSurfaceInstance> test_surface =
get_output(
3808 paint.setBlendMode(DlBlendMode::kSrc);
3809 for (DlColor color : test_dst_colors) {
3810 paint.setColor(color);
3811 canvas->DrawRect(DlRect::MakeXYWH(x, 0, 1, 1), paint);
3815 sk_sp<DlImage> test_image = test_surface->SnapshotToImage();
3816 std::shared_ptr<DlPixelData> test_pixels =
3817 test_surface->SnapshotToPixelData();
3823 int data_count = test_image->width();
3824 std::shared_ptr<DlSurfaceInstance> dst_surface =
3825 get_output(provider, data_count, data_count,
true,
3826 [&test_image, data_count](
DlCanvas* canvas) {
3827 ASSERT_EQ(test_image->width(), data_count);
3828 ASSERT_EQ(test_image->height(), 1);
3829 for (
int y = 0;
y < data_count;
y++) {
3834 std::shared_ptr<DlPixelData> dst_pixels =
3835 dst_surface->SnapshotToPixelData();
3837 std::shared_ptr<DlSurfaceInstance> src_surface =
3838 get_output(provider, data_count, data_count,
true,
3839 [&test_image, data_count](DlCanvas* canvas) {
3840 ASSERT_EQ(test_image->width(), data_count);
3841 ASSERT_EQ(test_image->height(), 1);
3842 canvas->Translate(data_count, 0);
3844 for (
int y = 0;
y < data_count;
y++) {
3845 canvas->DrawImage(test_image,
DlPoint(0,
y),
3849 std::shared_ptr<DlPixelData> src_pixels =
3850 src_surface->SnapshotToPixelData();
3853 for (
int y = 0;
y < data_count;
y++) {
3854 for (
int x = 0;
x < data_count;
x++) {
3855 EXPECT_EQ(*dst_pixels->addr32(
x,
y), *test_pixels->addr32(
x, 0));
3856 EXPECT_EQ(*src_pixels->addr32(
x,
y), *test_pixels->addr32(
y, 0));
3861 .test_image_1d = test_surface->SnapshotToImage(),
3864 .dst_image_2d = dst_surface->SnapshotToImage(),
3867 .src_image_2d = src_surface->SnapshotToImage(),
3874 static constexpr int kWasNotNop = 0x1;
3875 static constexpr int kWasMTB = 0x2;
3887 if (entry == test_datas.end()) {
3888 TestData test_data = make_test_data(provider);
3892 return entry->second;
3900 const std::function<
void(
DlCanvas*)>& renderer) {
3901 std::shared_ptr<DlSurfaceInstance>
surface =
3906 surface->FlushSubmitCpuSync();
3914 const sk_sp<DisplayList>& dl,
3915 const std::string& desc) {
3917 bool is_error =
false;
3920 is_error = !dl->modifies_transparent_black();
3922 if (result_color != dst_color) {
3924 is_error = (dl->op_count() == 0u);
3927 FML_LOG(ERROR) << std::hex << dst_color
3928 << std::dec <<
" at " <<
x <<
", " <<
y
3929 <<
" filters to " << std::hex << result_color
3937 const sk_sp<DisplayList>& dl,
3938 const std::string& desc) {
3942 for (uint32_t
y = 0;
y < dst_data.
pixel_data->height();
y++) {
3943 const uint32_t* dst_pixels = dst_data.
pixel_data->addr32(0,
y);
3944 const uint32_t* result_pixels = result_data.
pixel_data->addr32(0,
y);
3945 for (uint32_t
x = 0;
x < dst_data.
pixel_data->width();
x++) {
3946 all_flags |= check_color_result(
3954 const sk_sp<DisplayList>& dl,
3955 const std::string& desc) {
3956 if (!dl->modifies_transparent_black()) {
3957 EXPECT_TRUE((all_flags & kWasMTB) == 0);
3958 }
else if ((all_flags & kWasMTB) == 0) {
3959 FML_LOG(INFO) <<
"combination does not affect transparency: " << desc;
3961 if (dl->op_count() == 0u) {
3962 EXPECT_TRUE((all_flags & kWasNotNop) == 0);
3963 }
else if ((all_flags & kWasNotNop) == 0) {
3964 FML_LOG(INFO) <<
"combination could be classified as a nop: " << desc;
3969 std::stringstream desc_stream;
3970 desc_stream <<
" using SkColorFilter::filterColor() with: ";
3972 desc_stream <<
"/" << color;
3973 std::string desc = desc_stream.str();
3977 sk_sp<DisplayList> dl = builder.
Build();
3978 if (dl->modifies_transparent_black()) {
3979 ASSERT_TRUE(dl->op_count() != 0u);
3982 SkBlendMode sk_mode =
static_cast<SkBlendMode
>(
mode);
3983 sk_sp<SkColorFilter> sk_color_filter =
3984 SkColorFilters::Blend(
ToSkColor4f(color),
nullptr, sk_mode);
3985 sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB();
3987 if (sk_color_filter) {
3988 for (
DlColor dst_color : test_dst_colors) {
3991 sk_color_filter->filterColor4f(dst_color_f, srgb.get(), srgb.get())
3994 check_color_result(dst_color, result, 0, 0, dl, desc);
3996 if ((all_flags & kWasMTB) != 0) {
3997 EXPECT_FALSE(sk_color_filter->isAlphaUnchanged());
4000 report_results(all_flags, dl, desc);
4004 std::stringstream desc_stream;
4005 desc_stream <<
" rendering with: ";
4007 desc_stream <<
"/" << color;
4008 std::string desc = desc_stream.str();
4012 sk_sp<DisplayList> properties_display_list = builder_for_properties.
Build();
4013 bool dl_is_elided = properties_display_list->op_count() == 0u;
4014 bool dl_affects_transparent_pixels =
4015 properties_display_list->modifies_transparent_black();
4016 ASSERT_TRUE(!dl_is_elided || !dl_affects_transparent_pixels);
4022 std::unique_ptr<DlSurfaceProvider> provider = GetProvider(back_end);
4023 const TestData test_data = GetTestData(provider.get());
4024 std::string provider_desc =
" " + provider->GetBackendName() + desc;
4029 std::shared_ptr<DlSurfaceInstance> result_surface =
4030 provider->MakeOffscreenSurface(test_image->width(),
4031 test_image->height(),
4037 builder_for_rendering.
DrawRect(test_bounds, paint);
4038 result_surface->RenderDisplayList(builder_for_rendering.
Build());
4039 result_surface->FlushSubmitCpuSync();
4043 check_image_result(test_data.
test_pixels, result_pixels,
4044 properties_display_list, provider_desc);
4045 report_results(all_flags, properties_display_list, provider_desc);
4054 std::stringstream desc_stream;
4055 desc_stream <<
" rendering with: ";
4057 desc_stream <<
"/" << color;
4058 std::string cf_mtb = color_filter
4060 ?
"modifies transparency"
4061 :
"preserves transparency"
4063 desc_stream <<
", CF: " << cf_mtb;
4064 std::string if_mtb = image_filter
4066 ?
"modifies transparency"
4067 :
"preserves transparency"
4069 desc_stream <<
", IF: " << if_mtb;
4070 std::string desc = desc_stream.str();
4073 std::unique_ptr<DlSurfaceProvider> provider = GetProvider(back_end);
4074 const TestData test_data = GetTestData(provider.get());
4075 std::string provider_desc =
" " + provider->GetBackendName() + desc;
4085 sk_sp<DisplayList> properties_display_list =
4086 builder_for_properties.
Build();
4090 std::shared_ptr<DlSurfaceInstance> result_surface =
4099 result_surface->RenderDisplayList(builder_for_rendering.
Build());
4100 result_surface->FlushSubmitCpuSync();
4104 check_image_result(test_data.
dst_pixels, result_pixels,
4105 properties_display_list, provider_desc);
4106 report_results(all_flags, properties_display_list, provider_desc);
4113 for (
DlColor color : test_src_colors) {
4114 test_mode_color_via_filter(
mode, color);
4118#define TEST_MODE(V) test_mode_filter(DlBlendMode::V);
4126 for (
DlColor color : test_src_colors) {
4127 test_mode_color_via_rendering(
mode, color);
4131#define TEST_MODE(V) test_mode_render(DlBlendMode::V);
4140 for (
DlColor color : test_src_colors) {
4141 test_attributes_image(
mode, color,
nullptr,
nullptr);
4142 test_attributes_image(
mode, color, color_filter_nomtb.get(),
nullptr);
4143 test_attributes_image(
mode, color, color_filter_mtb.get(),
nullptr);
4144 test_attributes_image(
mode, color,
nullptr, &image_filter_nomtb);
4145 test_attributes_image(
mode, color,
nullptr, &image_filter_mtb);
4149#define TEST_MODE(V) test_mode_render(DlBlendMode::V);
4154#undef FOR_EACH_BLEND_MODE_ENUM
constexpr bool applies_color() const
constexpr bool is_stroked(DlDrawStyle style=DlDrawStyle::kStroke) const
constexpr bool applies_color_filter() const
constexpr bool ignores_paint() const
constexpr bool applies_image_filter() const
constexpr bool applies_shader() const
const DisplayListSpecialGeometryFlags GeometryFlags(bool is_stroked) const
constexpr bool applies_anti_alias() const
constexpr bool applies_mask_filter() const
constexpr bool applies_blend() const
The primitive honors the DlBlendMode.
constexpr bool is_flood() const
void DrawImage(const sk_sp< DlImage > &image, const DlPoint &point, DlImageSampling sampling, const DlPaint *paint=nullptr) 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 Rotate(DlScalar degrees) override
void Scale(DlScalar sx, DlScalar sy) override
void Translate(DlScalar tx, DlScalar ty) override
sk_sp< DisplayList > Build()
void DrawRect(const DlRect &rect, const DlPaint &paint) override
constexpr bool may_have_joins() const
The geometry may have segments connect non-continuously.
constexpr bool may_have_end_caps() const
The geometry may have segments that end without closing the path.
constexpr bool may_have_acute_joins() const
constexpr bool butt_cap_becomes_square() const
Mainly for drawPoints(PointMode) where Butt caps are rendered as squares.
bool can_commute_with_opacity() const override
bool modifies_transparent_black() const override
Developer-facing API for rendering anything within the engine.
virtual void Transform(const DlMatrix &matrix)=0
virtual void ClipRect(const DlRect &rect, DlClipOp clip_op=DlClipOp::kIntersect, bool is_aa=false)=0
virtual void DrawPaint(const DlPaint &paint)=0
virtual void DrawCircle(const DlPoint ¢er, DlScalar radius, const DlPaint &paint)=0
virtual void ClipRoundRect(const DlRoundRect &rrect, DlClipOp clip_op=DlClipOp::kIntersect, bool is_aa=false)=0
virtual DlRect GetDestinationClipCoverage() const =0
virtual void DrawRoundRect(const DlRoundRect &rrect, const DlPaint &paint)=0
virtual void DrawDisplayList(const sk_sp< DisplayList > display_list, DlScalar opacity=SK_Scalar1)=0
virtual DlISize GetBaseLayerDimensions() const =0
virtual void TransformFullPerspective(DlScalar mxx, DlScalar mxy, DlScalar mxz, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myz, DlScalar myt, DlScalar mzx, DlScalar mzy, DlScalar mzz, DlScalar mzt, DlScalar mwx, DlScalar mwy, DlScalar mwz, DlScalar mwt)=0
virtual void DrawImageNine(const sk_sp< DlImage > &image, const DlIRect ¢er, const DlRect &dst, DlFilterMode filter, const DlPaint *paint=nullptr)=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 DrawLine(const DlPoint &p0, const DlPoint &p1, const DlPaint &paint)=0
virtual void DrawDiffRoundRect(const DlRoundRect &outer, const DlRoundRect &inner, const DlPaint &paint)=0
virtual void DrawRect(const DlRect &rect, const DlPaint &paint)=0
virtual void DrawVertices(const std::shared_ptr< DlVertices > &vertices, DlBlendMode mode, const DlPaint &paint)=0
virtual void ClipOval(const DlRect &bounds, DlClipOp clip_op=DlClipOp::kIntersect, bool is_aa=false)=0
virtual void Transform2DAffine(DlScalar mxx, DlScalar mxy, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myt)=0
virtual void DrawText(const std::shared_ptr< DlText > &text, DlScalar x, DlScalar y, const DlPaint &paint)=0
virtual void DrawImage(const sk_sp< DlImage > &image, const DlPoint &point, DlImageSampling sampling, const DlPaint *paint=nullptr)=0
virtual void DrawOval(const DlRect &bounds, const DlPaint &paint)=0
virtual void Translate(DlScalar tx, DlScalar ty)=0
virtual void DrawColor(DlColor color, DlBlendMode mode=DlBlendMode::kSrcOver)=0
virtual DlMatrix GetMatrix() const =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 DrawPath(const DlPath &path, const DlPaint &paint)=0
virtual void DrawPoints(DlPointMode mode, uint32_t count, const DlPoint pts[], const DlPaint &paint)=0
virtual void ClipPath(const DlPath &path, DlClipOp clip_op=DlClipOp::kIntersect, bool is_aa=false)=0
void Clear(DlColor color)
virtual void DrawArc(const DlRect &bounds, DlScalar start, DlScalar sweep, bool useCenter, const DlPaint &paint)=0
virtual void DrawAtlas(const sk_sp< DlImage > &atlas, const DlRSTransform xform[], const DlRect tex[], const DlColor colors[], int count, DlBlendMode mode, DlImageSampling sampling, const DlRect *cullRect, const DlPaint *paint=nullptr)=0
virtual void Skew(DlScalar sx, DlScalar sy)=0
virtual void DrawImageRect(const sk_sp< DlImage > &image, const DlRect &src, const DlRect &dst, DlImageSampling sampling, const DlPaint *paint=nullptr, DlSrcRectConstraint constraint=DlSrcRectConstraint::kFast)=0
virtual void Scale(DlScalar sx, DlScalar sy)=0
virtual void DrawShadow(const DlPath &path, const DlColor color, const DlScalar elevation, bool transparent_occluder, DlScalar dpr)=0
Draws the shadow of the given |path| rendered in the provided |color| (which is only consulted for it...
static std::shared_ptr< const DlColorFilter > MakeBlend(DlColor color, DlBlendMode mode)
static std::shared_ptr< const DlColorFilter > MakeLinearToSrgbGamma()
virtual bool modifies_transparent_black() const =0
static std::shared_ptr< const DlColorFilter > MakeMatrix(const float matrix[20])
static std::shared_ptr< const DlColorFilter > MakeSrgbToLinearGamma()
static std::shared_ptr< DlColorSource > MakeLinear(const DlPoint start_point, const DlPoint end_point, uint32_t stop_count, const DlColor *colors, const float *stops, DlTileMode tile_mode, const DlMatrix *matrix=nullptr)
static std::shared_ptr< DlImageFilter > MakeDilate(DlScalar radius_x, DlScalar radius_y)
static std::shared_ptr< DlImageFilter > MakeBlur(DlScalar sigma_x, DlScalar sigma_y, DlTileMode tile_mode)
static std::shared_ptr< DlImageFilter > MakeColorFilter(const std::shared_ptr< const DlColorFilter > &filter)
virtual bool modifies_transparent_black() const =0
static std::shared_ptr< DlImageFilter > MakeMatrix(const DlMatrix &matrix, DlImageSampling sampling)
static std::shared_ptr< DlImageFilter > MakeErode(DlScalar radius_x, DlScalar radius_y)
bool modifies_transparent_black() const override
DlStrokeCap getStrokeCap() const
DlPaint & setColor(DlColor color)
DlPaint & setAntiAlias(bool isAntiAlias)
DlPaint & setInvertColors(bool isInvertColors)
DlBlendMode getBlendMode() const
float getStrokeMiter() const
DlStrokeJoin getStrokeJoin() const
const DlColorSource * getColorSourcePtr() const
DlPaint & setStrokeCap(DlStrokeCap cap)
DlPaint & setStrokeWidth(float width)
DlPaint & setAlpha(uint8_t alpha)
DlPaint & setStrokeMiter(float miter)
DlPaint & setBlendMode(DlBlendMode mode)
const std::shared_ptr< const DlMaskFilter > & getMaskFilter() const
DlDrawStyle getDrawStyle() const
DlPaint & setImageFilter(std::nullptr_t filter)
const std::shared_ptr< const DlColorSource > & getColorSource() const
const std::shared_ptr< DlImageFilter > & getImageFilter() const
float getStrokeWidth() const
const std::shared_ptr< const DlColorFilter > & getColorFilter() const
DlPaint & setMaskFilter(std::nullptr_t filter)
DlPaint & setDrawStyle(DlDrawStyle style)
DlPaint & setStrokeJoin(DlStrokeJoin join)
DlPaint & setOpacity(DlScalar opacity)
DlPaint & setColorFilter(std::nullptr_t filter)
DlPaint & setColorSource(std::nullptr_t source)
bool isInvertColors() const
DlPathBuilder & LineTo(DlPoint p2)
Draw a line from the current point to the indicated point p2.
DlPathBuilder & MoveTo(DlPoint p2)
Start a new contour that will originate at the indicated point p2.
DlPathBuilder & SetFillType(DlPathFillType fill_type)
Set the fill type that should be used to determine the interior of this path to the indicated |fill_t...
const DlPath TakePath()
Returns the path constructed by this path builder and resets its internal state to the default state ...
DlPathBuilder & AddCircle(DlPoint center, DlScalar radius)
Append a closed circular contour to the path centered on the provided point at the provided radius.
DlPathBuilder & AddRect(const DlRect &rect)
Append a closed rectangular contour to the path.
DlPathBuilder & AddRoundRect(const DlRoundRect &round_rect)
Append a closed rounded rect contour to the path.
DlPathBuilder & Close()
The path is closed back to the location of the most recent MoveTo call. Contours that are filled are ...
static std::shared_ptr< DlTextImpeller > MakeFromBlob(const sk_sp< SkTextBlob > &blob)
static std::shared_ptr< DlTextSkia > Make(const sk_sp< SkTextBlob > &blob)
static std::shared_ptr< DlVertices > Make(DlVertexMode mode, int vertex_count, const DlPoint vertices[], const DlPoint texture_coordinates[], const DlColor colors[], int index_count=0, const uint16_t indices[]=nullptr, const DlRect *bounds=nullptr)
Constructs a DlVector with compact inline storage for all of its required and optional lists of data.
BoundsTolerance()=default
bool overflows(DlIRect pix_bounds, int worst_bounds_pad_x, int worst_bounds_pad_y) const
BoundsTolerance addBoundsPadding(DlScalar bounds_pad_x, DlScalar bounds_pad_y) const
static DlRect Scale(const DlRect &rect, const DlPoint &scales)
BoundsTolerance addPostClipPadding(DlScalar absolute_pad_x, DlScalar absolute_pad_y) const
BoundsTolerance mulScale(DlScalar scale_x, DlScalar scale_y) const
BoundsTolerance(const BoundsTolerance &)=default
BoundsTolerance clip(DlRect clip) const
BoundsTolerance addAbsolutePadding(DlScalar absolute_pad_x, DlScalar absolute_pad_y) const
bool operator==(BoundsTolerance const &other) const
BoundsTolerance addDiscreteOffset(DlScalar discrete_offset) const
DlScalar discrete_offset() const
static void RenderWithAttributes(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance)
static void checkGroupOpacity(const RenderEnvironment &env, const sk_sp< DisplayList > &display_list, const RenderResult &ref_result, const std::string &info, DlColor bg)
static void compareToReference(const RenderResult &test_result, const RenderResult &ref_result, const std::string &info, const DlRect *bounds, const BoundsTolerance *tolerance, const DlColor bg, bool fuzzyCompares=false, uint32_t width=kTestWidth, uint32_t height=kTestHeight, bool printMismatches=false)
static void PrintFailureImageFileNames()
static void RenderWithStrokes(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance_in)
static void RenderWithSaveRestore(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance)
static void RenderAll(const std::unique_ptr< DlSurfaceProvider > &provider, const TestParameters ¶ms, const BoundsTolerance &tolerance=DefaultTolerance)
static DirectoryStatus CheckDir(const std::string &dir)
static void SetupFailureImageDirectory()
static void RenderWithClips(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &diff_tolerance)
static void RenderWith(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance_in, const CaseParameters &caseP)
static void showBoundsOverflow(const std::string &info, DlIRect &bounds, const BoundsTolerance *tolerance, int pixLeft, int pixTop, int pixRight, int pixBottom)
static bool checkPixels(const RenderResult &ref_result, const DlRect ref_bounds, const std::string &info, const DlColor bg=DlColor::kTransparent())
static bool fuzzyCompare(uint32_t pixel_a, uint32_t pixel_b, int fudge)
static void save_to_png(const RenderResult &result, const std::string &op_desc, const std::string &reason)
static void EnableSaveImagesOnFailures()
static bool quickCompareToReference(const RenderResult &ref_result, const RenderResult &test_result, bool should_match, const std::string &info)
static void RenderWithTransforms(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance)
static int countModifiedTransparentPixels(const RenderResult &ref_result, const RenderResult &test_result)
static BoundsTolerance DefaultTolerance
static int groupOpacityFudgeFactor(const RenderEnvironment &env)
CaseParameters with_diff_clip()
bool fuzzy_compare_components() const
bool has_mutating_save_layer() const
bool has_diff_clip() const
CaseParameters(std::string info, DlSetup &dl_setup)
CaseParameters(std::string info)
CaseParameters(std::string info, DlSetup &dl_setup, DlRenderer &dl_restore, DlColor bg, bool has_diff_clip, bool has_mutating_save_layer, bool fuzzy_compare_components)
CaseParameters with_restore(DlRenderer &dl_restore, bool mutating_layer, bool fuzzy_compare_components=false)
CaseParameters with_bg(DlColor bg)
DlRenderer dl_restore() const
std::shared_ptr< DlSurfaceInstance > get_output(DlSurfaceProvider *provider, int w, int h, bool snapshot, const std::function< void(DlCanvas *)> &renderer)
const TestData make_test_data(DlSurfaceProvider *provider)
std::map< DlSurfaceProvider::BackendType, TestData > test_datas
void report_results(int all_flags, const sk_sp< DisplayList > &dl, const std::string &desc)
int check_image_result(const RenderResult &dst_data, const RenderResult &result_data, const sk_sp< DisplayList > &dl, const std::string &desc)
std::shared_ptr< const DlColorFilter > color_filter_nomtb
std::vector< DlColor > test_dst_colors
void test_mode_color_via_rendering(DlBlendMode mode, DlColor color)
std::vector< DlColor > test_src_colors
std::shared_ptr< const DlColorFilter > color_filter_mtb
void test_mode_color_via_filter(DlBlendMode mode, DlColor color)
void test_attributes_image(DlBlendMode mode, DlColor color, const DlColorFilter *color_filter, DlImageFilter *image_filter)
int check_color_result(DlColor dst_color, DlColor result_color, int x, int y, const sk_sp< DisplayList > &dl, const std::string &desc)
const TestData GetTestData(DlSurfaceProvider *provider)
static void TearDownTestSuite()
static std::unique_ptr< DlSurfaceProvider > GetProvider(BackendType type)
DisplayListRendering()=default
static void RenderAll(const TestParameters ¶ms, const BoundsTolerance &tolerance=CanvasCompareTester::DefaultTolerance)
static void SetUpTestSuite()
static const std::vector< BackendType > & GetTestBackends()
virtual bool TargetsImpeller() const =0
static std::optional< BackendType > NameToBackend(const std::string &name)
virtual std::unique_ptr< DlSurfaceInstance > MakeOffscreenSurface(size_t width, size_t height, PixelFormat format=kN32Premul) const =0
static std::string BackendName(BackendType type)
static std::unique_ptr< DlSurfaceProvider > Create(BackendType backend_type)
virtual bool SupportsPixelFormat(PixelFormat format) const =0
virtual const std::string GetBackendName() const =0
virtual BackendType GetBackendType() const =0
void warn(const std::string &name)
OncePerBackendWarning(const std::string &warning)
const std::string GetBackendName() const
const sk_sp< DlImage > GetTestImage() const
const DlMatrix & GetReferenceMatrix() const
RenderResult GetResult(const RenderJobInfo &info, JobRenderer &renderer) const
const DlPaint & GetReferencePaint() const
PixelFormat GetPixelFormat() const
static RenderEnvironment MakeN32(const DlSurfaceProvider *provider)
const std::shared_ptr< DlText > GetTestText() const
const DlSurfaceProvider * GetProvider() const
const RenderResult & GetReferenceResult() const
RenderEnvironment(const DlSurfaceProvider *provider, PixelFormat format)
static RenderEnvironment Make565(const DlSurfaceProvider *provider)
RenderResult GetResult(const sk_sp< DisplayList > &dl) const
const DlIRect & GetReferenceClipBounds() const
void InitializeReference(DlSetup &dl_setup, DlRenderer &dl_renderer, DlColor bg=DlColor::kTransparent())
TestParameters & set_draw_display_list()
TestParameters & set_draw_text_blob()
TestParameters & set_vertical_line()
bool ignores_dashes() const
bool is_draw_display_list() const
TestParameters(const DlRenderer &dl_renderer, const DisplayListAttributeFlags &flags)
bool is_draw_arc_center() const
const BoundsTolerance lineAdjust(const BoundsTolerance &tolerance, const DlPaint &paint, const DlMatrix &matrix) const
TestParameters & set_draw_path()
bool uses_gradient() const
TestParameters & set_ignores_dashes()
bool is_draw_path() const
bool is_horizontal_line() const
TestParameters & set_draw_line()
bool is_draw_line() const
TestParameters & set_draw_arc_center()
TestParameters & set_horizontal_line()
DisplayListAttributeFlags flags() const
bool is_draw_text_blob() const
const BoundsTolerance adjust(const BoundsTolerance &tolerance, const DlPaint &paint, const DlMatrix &matrix) const
bool is_vertical_line() const
const DlRenderer & dl_renderer() const
bool impeller_compatible(const DlPaint &paint) const
bool should_match(const RenderEnvironment &env, const CaseParameters &caseP, const DlPaint &attr, const MatrixClipJobRenderer &renderer) const
DlStrokeCap getCap(const DlPaint &attr, DisplayListSpecialGeometryFlags geo_flags) const
std::vector< std::string_view > GetOptionValues(std::string_view name) const
bool HasOption(std::string_view name, size_t *index=nullptr) const
#define FOR_EACH_BLEND_MODE_ENUM(FUNC)
const EmbeddedViewParams * params
FlutterVulkanImage * image
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint32_t uint32_t * format
#define FML_LOG(severity)
#define FML_CHECK(condition)
#define FML_DCHECK(condition)
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
DlSurfaceProvider::BackendType BackendType
TEST_F(DisplayListTest, Defaults)
constexpr DlScalar kYOffsetU3
constexpr DlRect kRenderBounds
const std::function< void(const DlSetupContext &)> DlSetup
static void DrawCheckerboard(DlCanvas *canvas)
constexpr uint32_t kTestWidth
constexpr DlScalar kTextFontHeight
constexpr DlScalar kMiter4DiamondOffsetX
const DlPoint kHorizontalMiterDiamondPoints[]
constexpr DlRect kTestBounds2
constexpr DlScalar kYOffsetD3
static const DlSetup kEmptyDlSetup
constexpr uint32_t kRenderHeight
SkFont CreateTestFontOfSize(DlScalar scalar)
constexpr DlScalar kYOffsetU2
sk_sp< DisplayList > makeTestDisplayList()
const int kHorizontalMiterDiamondPointCount
constexpr DlScalar kRenderCenterY
static std::shared_ptr< DlImageColorSource > MakeColorSource(const sk_sp< DlImage > &image)
constexpr DlScalar kRenderCenterX
constexpr DlScalar kYOffsetU1
constexpr DlScalar kMiter4DiamondOffsetY
constexpr DlScalar kRenderLeft
constexpr DlScalar kRenderBottom
constexpr DlScalar kXOffsetR2
constexpr DlScalar kYOffset0
DlSurfaceProvider::PixelFormat PixelFormat
constexpr uint32_t kTestHeight
constexpr DlScalar kXOffset0
constexpr DlScalar kRenderTop
constexpr DlScalar kMiterExtremeDiamondOffsetY
constexpr DlScalar kXOffsetL1
constexpr DlScalar kYOffsetD1
constexpr DlScalar kMiter10DiamondOffsetY
constexpr DlScalar kXOffsetL2
constexpr DlScalar kXOffsetL3
constexpr DlScalar kRenderCornerRadius
constexpr DlScalar kXOffsetR3
const int kVerticalMiterDiamondPointCount
const DlPoint kTestCenter2
constexpr uint32_t kRenderWidth
constexpr DlScalar kMiterExtremeDiamondOffsetX
static const DlRenderer kEmptyDlRenderer
constexpr DlScalar kRenderRight
constexpr DlScalar kMiter10DiamondOffsetX
constexpr DlPoint kVerticalMiterDiamondPoints[]
const std::function< void(const DlRenderContext &)> DlRenderer
constexpr DlScalar kXOffsetR1
constexpr DlScalar kYOffsetD2
constexpr DlScalar kRenderRadius
impeller::Scalar DlScalar
@ kMiter
extends to miter limit
@ kBevel
connects outside edges
@ kButt
no stroke extension
impeller::Matrix DlMatrix
impeller::Degrees DlDegrees
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
@ kLines
draw each separate pair of points as a line segment
@ kPolygon
draw each pair of overlapping points as a line segment
@ kPoints
draw each point separately
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
SkColor4f ToSkColor4f(DlColor color)
DEF_SWITCHES_START aot vmservice shared library name
@ kTriangles
The vertices are taken 3 at a time to form a triangle.
@ kStroke
strokes boundary of shapes
@ kFill
fills interior of shapes
impeller::IRect32 DlIRect
impeller::IPoint32 DlIPoint
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
@ kNormal
fuzzy inside and outside
bool NotEquals(const T *a, const U *b)
TEST_F(EngineAnimatorTest, AnimatorAcceptsMultipleRenders)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder h
fml::UniqueFD OpenDirectory(const char *path, bool create_if_necessary, FilePermission permission)
CommandLine CommandLineFromIterators(InputIterator first, InputIterator last)
const char * BlendModeToString(BlendMode blend_mode)
impeller::ShaderType type
static constexpr DlColor kMagenta()
static constexpr DlColor kWhite()
static constexpr DlColor kBlue()
static constexpr DlColor kBlack()
static constexpr DlColor kYellow()
static constexpr DlColor kLightGrey()
constexpr DlScalar getRedF() const
constexpr DlScalar getAlphaF() const
constexpr DlScalar getBlueF() const
constexpr DlScalar getGreenF() const
static constexpr DlColor kTransparent()
static constexpr DlColor kRed()
static constexpr DlColor kGreen()
constexpr bool isTransparent() const
static constexpr DlColor kDarkGrey()
static constexpr DlColor kCyan()
constexpr bool isOpaque() const
DlColor withAlpha(uint8_t alpha) const
void Render(const RenderEnvironment &env, DlCanvas *canvas, const RenderJobInfo &info) override
DisplayListJobRenderer(sk_sp< DisplayList > display_list)
sk_sp< DlImage > test_image_1d
sk_sp< DlImage > src_image_2d
sk_sp< DlImage > dst_image_2d
void Render(const RenderEnvironment &env, DlCanvas *canvas, const RenderJobInfo &info) override
const DlPaint & GetSetupPaint() const
DlJobRenderer(const DlSetup &dl_setup, const DlRenderer &dl_render, const DlRenderer &dl_restore)
sk_sp< DisplayList > MakeDisplayList(const RenderEnvironment &env, const RenderJobInfo &info)
const RenderEnvironment & env
const RenderEnvironment & env
virtual void Render(const RenderEnvironment &env, DlCanvas *canvas, const RenderJobInfo &info)=0
const DlMatrix & GetSetupMatrix() const
const DlIRect & GetSetupClipBounds() const
DlIRect setup_clip_bounds_
static RenderResult Make(const std::shared_ptr< DlSurfaceInstance > &surface)
static RenderResult Make(const std::shared_ptr< DlPixelData > &data)
std::shared_ptr< DlPixelData > pixel_data
static RenderResult Make(const std::shared_ptr< DlPixelData > &data, const DlRect &bounds)
A 4x4 matrix using column-major storage.
constexpr Matrix Translate(const Vector3 &t) const
static Matrix MakeRotationY(Radians r)
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)
constexpr Matrix Scale(const Vector3 &s) const
static Matrix MakeRotationX(Radians r)
static RoundRect MakeRectXY(const Rect &rect, Scalar x_radius, Scalar y_radius)
constexpr auto GetBottom() const
static constexpr TRect MakeWH(Type width, Type height)
constexpr auto GetTop() const
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle which may be negative in either width or height and may have been c...
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
constexpr T Area() const
Get the area of the rectangle, equivalent to |GetSize().Area()|.
constexpr bool Contains(const TPoint< Type > &p) const
Returns true iff the provided point |p| is inside the half-open interior of this rectangle.
static constexpr std::enable_if_t< std::is_floating_point_v< FT >, TRect > Make(const TRect< U > &rect)
constexpr auto GetLeft() const
constexpr TPoint< T > GetLeftTop() const
RoundOut(const TRect< U > &r)
constexpr auto GetRight() const
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
constexpr TPoint< T > GetRightBottom() const
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
constexpr Point GetCenter() const
Get the center point as a |Point|.
constexpr TRect IntersectionOrEmpty(const TRect &o) const
constexpr TRect< T > Shift(T dx, T dy) const
Returns a new rectangle translated by the given offset.
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
constexpr Type Area() const
std::vector< Point > points