Flutter Engine
 
Loading...
Searching...
No Matches
flutter::testing::CanvasCompareTester Class Reference

Public Types

enum class  DirectoryStatus {
  kExisted ,
  kCreated ,
  kFailed
}
 

Static Public Member Functions

static std::unique_ptr< DlSurfaceProviderGetProvider (BackendType type)
 
static void ClearProviders ()
 
static bool AddProvider (BackendType type)
 
static void RenderAll (const TestParameters &params, const BoundsTolerance &tolerance=DefaultTolerance)
 
static void RenderWithSaveRestore (const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance)
 
static void RenderWithAttributes (const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance)
 
static void RenderWithStrokes (const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance_in)
 
static void RenderWithTransforms (const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance)
 
static void RenderWithClips (const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &diff_tolerance)
 
static DirectoryStatus CheckDir (const std::string &dir)
 
static void SetupImpellerFailureImageDirectory ()
 
static void save_to_png (const RenderResult *result, const std::string &op_desc, const std::string &reason)
 
static void RenderWith (const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance_in, const CaseParameters &caseP)
 
static bool fuzzyCompare (uint32_t pixel_a, uint32_t pixel_b, int fudge)
 
static int groupOpacityFudgeFactor (const RenderEnvironment &env)
 
static void checkGroupOpacity (const RenderEnvironment &env, const sk_sp< DisplayList > &display_list, const RenderResult *ref_result, const std::string &info, DlColor bg)
 
static bool checkPixels (const RenderResult *ref_result, const DlRect ref_bounds, const std::string &info, const DlColor bg=DlColor::kTransparent())
 
static int countModifiedTransparentPixels (const RenderResult *ref_result, const RenderResult *test_result)
 
static void quickCompareToReference (const RenderEnvironment &env, const std::string &info)
 
static bool quickCompareToReference (const RenderResult *ref_result, const RenderResult *test_result, bool should_match, const std::string &info)
 
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, int width=kTestWidth, int height=kTestHeight, bool printMismatches=false)
 
static void showBoundsOverflow (const std::string &info, DlIRect &bounds, const BoundsTolerance *tolerance, int pixLeft, int pixTop, int pixRight, int pixBottom)
 
static sk_sp< SkTextBlob > MakeTextBlob (const std::string &string, DlScalar font_height)
 

Static Public Attributes

static std::vector< BackendTypeTestBackends
 
static std::string ImpellerFailureImageDirectory = ""
 
static bool SaveImpellerFailureImages = false
 
static std::vector< std::string > ImpellerFailureImages
 
static bool ImpellerSupported = false
 
static BoundsTolerance DefaultTolerance
 

Detailed Description

Definition at line 1107 of file dl_rendering_unittests.cc.

Member Enumeration Documentation

◆ DirectoryStatus

Member Function Documentation

◆ AddProvider()

static bool flutter::testing::CanvasCompareTester::AddProvider ( BackendType  type)
inlinestatic

Definition at line 1129 of file dl_rendering_unittests.cc.

1129 {
1130 auto provider = GetProvider(type);
1131 if (!provider) {
1132 return false;
1133 }
1134 if (provider->supports_impeller()) {
1135 ImpellerSupported = true;
1136 }
1137 TestBackends.push_back(type);
1138 return true;
1139 }
GLenum type
static std::vector< BackendType > TestBackends
static std::unique_ptr< DlSurfaceProvider > GetProvider(BackendType type)

References GetProvider(), ImpellerSupported, TestBackends, and type.

Referenced by flutter::testing::DisplayListRenderingTestBase< BaseT >::SetUpTestSuite().

◆ CheckDir()

static DirectoryStatus flutter::testing::CanvasCompareTester::CheckDir ( const std::string &  dir)
inlinestatic

Definition at line 2276 of file dl_rendering_unittests.cc.

2276 {
2277 auto ret =
2279 if (ret.is_valid()) {
2281 }
2282 ret =
2284 if (ret.is_valid()) {
2286 }
2287 FML_LOG(ERROR) << "Could not create directory (" << dir
2288 << ") for impeller failure images" << ", ret = " << ret.get()
2289 << ", errno = " << errno;
2291 }
#define FML_LOG(severity)
Definition logging.h:101
fml::UniqueFD OpenDirectory(const char *path, bool create_if_necessary, FilePermission permission)
Definition file_posix.cc:97

References FML_LOG, kCreated, kExisted, kFailed, fml::kRead, fml::kReadWrite, and fml::OpenDirectory().

Referenced by SetupImpellerFailureImageDirectory().

◆ checkGroupOpacity()

static void flutter::testing::CanvasCompareTester::checkGroupOpacity ( const RenderEnvironment env,
const sk_sp< DisplayList > &  display_list,
const RenderResult ref_result,
const std::string &  info,
DlColor  bg 
)
inlinestatic

Definition at line 2548 of file dl_rendering_unittests.cc.

2552 {
2553 DlScalar opacity = 128.0 / 255.0;
2554
2555 DisplayListJobRenderer opacity_job(display_list);
2556 RenderJobInfo opacity_info = {
2557 .bg = bg,
2558 .opacity = opacity,
2559 };
2560 auto group_opacity_result = env.getResult(opacity_info, opacity_job);
2561
2562 ASSERT_EQ(group_opacity_result->width(), kTestWidth) << info;
2563 ASSERT_EQ(group_opacity_result->height(), kTestHeight) << info;
2564
2565 ASSERT_EQ(ref_result->width(), kTestWidth) << info;
2566 ASSERT_EQ(ref_result->height(), kTestHeight) << info;
2567
2568 int pixels_touched = 0;
2569 int pixels_different = 0;
2570 int max_diff = 0;
2571 // We need to allow some slight differences per component due to the
2572 // fact that rearranging discrete calculations can compound round off
2573 // errors. Off-by-2 is enough for 8 bit components, but for the 565
2574 // tests we allow at least 9 which is the maximum distance between
2575 // samples when converted to 8 bits. (You might think it would be a
2576 // max step of 8 converting 5 bits to 8 bits, but it is really
2577 // converting 31 steps to 255 steps with an average step size of
2578 // 8.23 - 24 of the steps are by 8, but 7 of them are by 9.)
2579 int fudge = groupOpacityFudgeFactor(env);
2580 for (int y = 0; y < kTestHeight; y++) {
2581 const uint32_t* ref_row = ref_result->addr32(0, y);
2582 const uint32_t* test_row = group_opacity_result->addr32(0, y);
2583 for (int x = 0; x < kTestWidth; x++) {
2584 uint32_t ref_pixel = ref_row[x];
2585 uint32_t test_pixel = test_row[x];
2586 if (ref_pixel != bg.argb() || test_pixel != bg.argb()) {
2587 pixels_touched++;
2588 for (int i = 0; i < 32; i += 8) {
2589 int ref_comp = (ref_pixel >> i) & 0xff;
2590 int bg_comp = (bg.argb() >> i) & 0xff;
2591 DlScalar faded_comp = bg_comp + (ref_comp - bg_comp) * opacity;
2592 int test_comp = (test_pixel >> i) & 0xff;
2593 if (std::abs(faded_comp - test_comp) > fudge) {
2594 int diff = std::abs(faded_comp - test_comp);
2595 if (max_diff < diff) {
2596 max_diff = diff;
2597 }
2598 pixels_different++;
2599 break;
2600 }
2601 }
2602 }
2603 }
2604 }
2605 ASSERT_GT(pixels_touched, 20) << info;
2606 if (pixels_different > 1) {
2607 FML_LOG(ERROR) << "max diff == " << max_diff << " for " << info;
2608 }
2609 ASSERT_LE(pixels_different, 1) << info;
2610 }
static int groupOpacityFudgeFactor(const RenderEnvironment &env)
int32_t x
double y
impeller::Scalar DlScalar

References flutter::testing::RenderResult::addr32(), flutter::DlColor::argb(), flutter::testing::RenderJobInfo::bg, FML_LOG, flutter::testing::RenderEnvironment::getResult(), groupOpacityFudgeFactor(), flutter::testing::RenderResult::height(), i, flutter::testing::kTestHeight, flutter::testing::kTestWidth, flutter::testing::RenderResult::width(), x, and y.

Referenced by RenderWith().

◆ checkPixels()

static bool flutter::testing::CanvasCompareTester::checkPixels ( const RenderResult ref_result,
const DlRect  ref_bounds,
const std::string &  info,
const DlColor  bg = DlColor::kTransparent() 
)
inlinestatic

Definition at line 2612 of file dl_rendering_unittests.cc.

2615 {
2616 uint32_t untouched = PremultipliedArgb(bg);
2617 int pixels_touched = 0;
2618 int pixels_oob = 0;
2619 DlIRect i_bounds = DlIRect::RoundOut(ref_bounds);
2620 EXPECT_EQ(ref_result->width(), kTestWidth) << info;
2621 EXPECT_EQ(ref_result->height(), kTestWidth) << info;
2622 for (int y = 0; y < kTestHeight; y++) {
2623 const uint32_t* ref_row = ref_result->addr32(0, y);
2624 for (int x = 0; x < kTestWidth; x++) {
2625 if (ref_row[x] != untouched) {
2626 pixels_touched++;
2627 if (!i_bounds.Contains({x, y})) {
2628 pixels_oob++;
2629 }
2630 }
2631 }
2632 }
2633 EXPECT_EQ(pixels_oob, 0) << info;
2634 EXPECT_GT(pixels_touched, 0) << info;
2635 return pixels_oob == 0 && pixels_touched > 0;
2636 }
impeller::IRect32 DlIRect
RoundOut(const TRect< U > &r)
Definition rect.h:679

References flutter::testing::RenderResult::addr32(), impeller::TRect< T >::Contains(), flutter::testing::RenderResult::height(), flutter::testing::kTestHeight, flutter::testing::kTestWidth, impeller::TRect< T >::RoundOut(), flutter::testing::RenderResult::width(), x, and y.

Referenced by RenderAll(), and RenderWith().

◆ ClearProviders()

static void flutter::testing::CanvasCompareTester::ClearProviders ( )
inlinestatic

◆ compareToReference()

static void flutter::testing::CanvasCompareTester::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,
int  width = kTestWidth,
int  height = kTestHeight,
bool  printMismatches = false 
)
inlinestatic

Definition at line 2691 of file dl_rendering_unittests.cc.

2700 {
2701 uint32_t untouched = PremultipliedArgb(bg);
2702 ASSERT_EQ(test_result->width(), width) << info;
2703 ASSERT_EQ(test_result->height(), height) << info;
2704 DlIRect i_bounds =
2705 bounds ? DlIRect::RoundOut(*bounds) : DlIRect::MakeWH(width, height);
2706
2707 int pixels_different = 0;
2708 int pixels_oob = 0;
2709 int min_x = width;
2710 int min_y = height;
2711 int max_x = 0;
2712 int max_y = 0;
2713 for (int y = 0; y < height; y++) {
2714 const uint32_t* ref_row = ref_result->addr32(0, y);
2715 const uint32_t* test_row = test_result->addr32(0, y);
2716 for (int x = 0; x < width; x++) {
2717 if (bounds && test_row[x] != untouched) {
2718 if (min_x > x) {
2719 min_x = x;
2720 }
2721 if (min_y > y) {
2722 min_y = y;
2723 }
2724 if (max_x <= x) {
2725 max_x = x + 1;
2726 }
2727 if (max_y <= y) {
2728 max_y = y + 1;
2729 }
2730 if (!i_bounds.Contains({x, y})) {
2731 pixels_oob++;
2732 }
2733 }
2734 bool match = fuzzyCompares ? fuzzyCompare(test_row[x], ref_row[x], 1)
2735 : test_row[x] == ref_row[x];
2736 if (!match) {
2737 if (printMismatches && pixels_different < 5) {
2738 FML_LOG(ERROR) << "pix[" << x << ", " << y
2739 << "] mismatch: " << std::hex << test_row[x]
2740 << "(test) != (ref)" << ref_row[x] << std::dec;
2741 }
2742 pixels_different++;
2743 }
2744 }
2745 }
2746 if (pixels_oob > 0) {
2747 FML_LOG(ERROR) << "pix bounds["
2748 << DlIRect::MakeLTRB(min_x, min_y, max_x, max_y) //
2749 << "]";
2750 FML_LOG(ERROR) << "dl_bounds[" << bounds << "]";
2751 } else if (bounds) {
2752 showBoundsOverflow(info, i_bounds, tolerance, min_x, min_y, max_x, max_y);
2753 }
2754 ASSERT_EQ(pixels_oob, 0) << info;
2755 ASSERT_EQ(pixels_different, 0) << info;
2756 }
static void showBoundsOverflow(const std::string &info, DlIRect &bounds, const BoundsTolerance *tolerance, int pixLeft, int pixTop, int pixRight, int pixBottom)
static bool fuzzyCompare(uint32_t pixel_a, uint32_t pixel_b, int fudge)
int32_t height
int32_t width
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129

References flutter::testing::RenderResult::addr32(), impeller::TRect< T >::Contains(), FML_LOG, fuzzyCompare(), flutter::testing::RenderResult::height(), height, impeller::TRect< T >::MakeLTRB(), impeller::TRect< T >::MakeWH(), impeller::TRect< T >::RoundOut(), showBoundsOverflow(), flutter::testing::RenderResult::width(), width, x, and y.

Referenced by RenderWith(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), and flutter::testing::TEST_F().

◆ countModifiedTransparentPixels()

static int flutter::testing::CanvasCompareTester::countModifiedTransparentPixels ( const RenderResult ref_result,
const RenderResult test_result 
)
inlinestatic

Definition at line 2638 of file dl_rendering_unittests.cc.

2639 {
2640 int count = 0;
2641 for (int y = 0; y < kTestHeight; y++) {
2642 const uint32_t* ref_row = ref_result->addr32(0, y);
2643 const uint32_t* test_row = test_result->addr32(0, y);
2644 for (int x = 0; x < kTestWidth; x++) {
2645 if (ref_row[x] != test_row[x]) {
2646 if (ref_row[x] == 0) {
2647 count++;
2648 }
2649 }
2650 }
2651 }
2652 return count;
2653 }

References flutter::testing::RenderResult::addr32(), flutter::testing::kTestHeight, flutter::testing::kTestWidth, x, and y.

Referenced by flutter::testing::TEST_F(), and flutter::testing::TEST_F().

◆ fuzzyCompare()

static bool flutter::testing::CanvasCompareTester::fuzzyCompare ( uint32_t  pixel_a,
uint32_t  pixel_b,
int  fudge 
)
inlinestatic

Definition at line 2526 of file dl_rendering_unittests.cc.

2526 {
2527 for (int i = 0; i < 32; i += 8) {
2528 int comp_a = (pixel_a >> i) & 0xff;
2529 int comp_b = (pixel_b >> i) & 0xff;
2530 if (std::abs(comp_a - comp_b) > fudge) {
2531 return false;
2532 }
2533 }
2534 return true;
2535 }

References i.

Referenced by compareToReference().

◆ GetProvider()

static std::unique_ptr< DlSurfaceProvider > flutter::testing::CanvasCompareTester::GetProvider ( BackendType  type)
inlinestatic

Definition at line 1115 of file dl_rendering_unittests.cc.

1115 {
1116 auto provider = DlSurfaceProvider::Create(type);
1117 if (provider == nullptr) {
1118 FML_LOG(ERROR) << "provider " << DlSurfaceProvider::BackendName(type)
1119 << " not supported (ignoring)";
1120 return nullptr;
1121 }
1122 provider->InitializeSurface(kTestWidth, kTestHeight,
1123 PixelFormat::kN32PremulPixelFormat);
1124 return provider;
1125 }
static std::string BackendName(BackendType type)
static std::unique_ptr< DlSurfaceProvider > Create(BackendType backend_type)

References flutter::testing::DlSurfaceProvider::BackendName(), flutter::testing::DlSurfaceProvider::Create(), FML_LOG, flutter::testing::kTestHeight, flutter::testing::kTestWidth, and type.

Referenced by AddProvider(), RenderAll(), flutter::testing::DisplayListNopTest::test_attributes_image(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), and flutter::testing::DisplayListNopTest::test_mode_color_via_rendering().

◆ groupOpacityFudgeFactor()

static int flutter::testing::CanvasCompareTester::groupOpacityFudgeFactor ( const RenderEnvironment env)
inlinestatic

Definition at line 2537 of file dl_rendering_unittests.cc.

2537 {
2538 if (env.format() == PixelFormat::k565PixelFormat) {
2539 return 9;
2540 }
2541 if (env.provider()->backend_type() == BackendType::kOpenGlBackend) {
2542 // OpenGL gets a little fuzzy at times. Still, "within 5" (aka +/-4)
2543 // for byte samples is not bad, though the other backends give +/-1
2544 return 5;
2545 }
2546 return 2;
2547 }

References flutter::testing::DlSurfaceProvider::backend_type(), flutter::testing::RenderEnvironment::format(), and flutter::testing::RenderEnvironment::provider().

Referenced by checkGroupOpacity().

◆ MakeTextBlob()

static sk_sp< SkTextBlob > flutter::testing::CanvasCompareTester::MakeTextBlob ( const std::string &  string,
DlScalar  font_height 
)
inlinestatic

Definition at line 2796 of file dl_rendering_unittests.cc.

2797 {
2798 SkFont font = CreateTestFontOfSize(font_height);
2799 sk_sp<SkTypeface> face = font.refTypeface();
2800 FML_CHECK(face);
2801 FML_CHECK(face->countGlyphs() > 0) << "No glyphs in font";
2802 return SkTextBlob::MakeFromText(string.c_str(), string.size(), font,
2803 SkTextEncoding::kUTF8);
2804 }
#define FML_CHECK(condition)
Definition logging.h:104
SkFont CreateTestFontOfSize(DlScalar scalar)
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

References flutter::testing::CreateTestFontOfSize(), FML_CHECK, and flutter::size.

Referenced by flutter::testing::TEST_F().

◆ quickCompareToReference() [1/2]

static void flutter::testing::CanvasCompareTester::quickCompareToReference ( const RenderEnvironment env,
const std::string &  info 
)
inlinestatic

◆ quickCompareToReference() [2/2]

static bool flutter::testing::CanvasCompareTester::quickCompareToReference ( const RenderResult ref_result,
const RenderResult test_result,
bool  should_match,
const std::string &  info 
)
inlinestatic

Definition at line 2661 of file dl_rendering_unittests.cc.

2664 {
2665 int w = test_result->width();
2666 int h = test_result->height();
2667 EXPECT_EQ(w, ref_result->width()) << info;
2668 EXPECT_EQ(h, ref_result->height()) << info;
2669 int pixels_different = 0;
2670 for (int y = 0; y < h; y++) {
2671 const uint32_t* ref_row = ref_result->addr32(0, y);
2672 const uint32_t* test_row = test_result->addr32(0, y);
2673 for (int x = 0; x < w; x++) {
2674 if (ref_row[x] != test_row[x]) {
2675 if (should_match && pixels_different < 5) {
2676 FML_LOG(ERROR) << std::hex << ref_row[x] << " != " << test_row[x];
2677 }
2678 pixels_different++;
2679 }
2680 }
2681 }
2682 if (should_match) {
2683 EXPECT_EQ(pixels_different, 0) << info;
2684 return pixels_different == 0;
2685 } else {
2686 EXPECT_NE(pixels_different, 0) << info;
2687 return pixels_different != 0;
2688 }
2689 }
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
Definition switch_defs.h:54

References flutter::testing::RenderResult::addr32(), FML_LOG, flutter::h, flutter::testing::RenderResult::height(), flutter::testing::RenderResult::width(), x, and y.

◆ RenderAll()

static void flutter::testing::CanvasCompareTester::RenderAll ( const TestParameters params,
const BoundsTolerance tolerance = DefaultTolerance 
)
inlinestatic

Definition at line 1143 of file dl_rendering_unittests.cc.

1144 {
1145 for (auto& back_end : TestBackends) {
1146 auto provider = GetProvider(back_end);
1147 RenderEnvironment env = RenderEnvironment::MakeN32(provider.get());
1148 env.init_ref(kEmptySkSetup, params.sk_renderer(), //
1149 kEmptyDlSetup, params.dl_renderer(), params.imp_renderer());
1150 quickCompareToReference(env, "default");
1151 if (env.supports_impeller()) {
1152 auto impeller_result = env.ref_impeller_result();
1153 if (!checkPixels(impeller_result, impeller_result->render_bounds(),
1154 "Impeller reference")) {
1155 std::string test_name =
1156 ::testing::UnitTest::GetInstance()->current_test_info()->name();
1157 save_to_png(impeller_result, test_name + " (Impeller reference)",
1158 "base rendering was blank or out of bounds");
1159 }
1160 } else {
1161 static OncePerBackendWarning warnings("No Impeller output tests");
1162 warnings.warn(env.backend_name());
1163 }
1164
1165 RenderWithTransforms(params, env, tolerance);
1166 RenderWithClips(params, env, tolerance);
1167 RenderWithSaveRestore(params, env, tolerance);
1168 // Only test attributes if the canvas version uses the paint object
1169 if (params.uses_paint()) {
1170 RenderWithAttributes(params, env, tolerance);
1171 }
1172 }
1173 }
static bool checkPixels(const RenderResult *ref_result, const DlRect ref_bounds, const std::string &info, const DlColor bg=DlColor::kTransparent())
static void RenderWithAttributes(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance)
static void RenderWithSaveRestore(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance)
static void RenderWithClips(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &diff_tolerance)
static void save_to_png(const RenderResult *result, const std::string &op_desc, const std::string &reason)
static void RenderWithTransforms(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance)
static RenderEnvironment MakeN32(const DlSurfaceProvider *provider)
const EmbeddedViewParams * params
static const DlSetup kEmptyDlSetup
static const SkSetup kEmptySkSetup

References flutter::testing::RenderEnvironment::backend_name(), checkPixels(), GetProvider(), flutter::testing::RenderEnvironment::init_ref(), flutter::testing::kEmptyDlSetup, flutter::testing::kEmptySkSetup, flutter::testing::RenderEnvironment::MakeN32(), params, quickCompareToReference(), flutter::testing::RenderEnvironment::ref_impeller_result(), RenderWithAttributes(), RenderWithClips(), RenderWithSaveRestore(), RenderWithTransforms(), save_to_png(), flutter::testing::RenderEnvironment::supports_impeller(), TestBackends, and flutter::testing::OncePerBackendWarning::warn().

Referenced by flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), and flutter::testing::TEST_F().

◆ RenderWith()

static void flutter::testing::CanvasCompareTester::RenderWith ( const TestParameters testP,
const RenderEnvironment env,
const BoundsTolerance tolerance_in,
const CaseParameters caseP 
)
inlinestatic

Definition at line 2341 of file dl_rendering_unittests.cc.

2344 {
2345 std::string test_name =
2346 ::testing::UnitTest::GetInstance()->current_test_info()->name();
2347 const std::string info =
2348 env.backend_name() + ": " + test_name + " (" + caseP.info() + ")";
2349 const DlColor bg = caseP.bg();
2350 RenderJobInfo base_info = {
2351 .bg = bg,
2352 };
2353
2354 // sk_result is a direct rendering via SkCanvas to SkSurface
2355 // DisplayList mechanisms are not involved in this operation
2356 SkJobRenderer sk_job(caseP.sk_setup(), //
2357 testP.sk_renderer(), //
2358 caseP.sk_restore(), //
2359 env.sk_image());
2360 auto sk_result = env.getResult(base_info, sk_job);
2361
2362 DlJobRenderer dl_job(caseP.dl_setup(), //
2363 testP.dl_renderer(), //
2364 caseP.dl_restore(), //
2365 env.dl_image());
2366 auto dl_result = env.getResult(base_info, dl_job);
2367
2368 if (sk_job.setup_matrix() != dl_job.setup_matrix()) {
2369 EXPECT_EQ(sk_job.setup_matrix(), dl_job.setup_matrix());
2370 }
2371 EXPECT_EQ(sk_job.setup_clip_bounds(), dl_job.setup_clip_bounds());
2372 ASSERT_EQ(sk_result->width(), kTestWidth) << info;
2373 ASSERT_EQ(sk_result->height(), kTestHeight) << info;
2374 ASSERT_EQ(dl_result->width(), kTestWidth) << info;
2375 ASSERT_EQ(dl_result->height(), kTestHeight) << info;
2376
2377 const BoundsTolerance tolerance =
2378 testP.adjust(tolerance_in, dl_job.setup_paint(), dl_job.setup_matrix());
2379 const sk_sp<SkPicture> sk_picture = sk_job.MakePicture(base_info);
2380 const sk_sp<DisplayList> display_list = dl_job.MakeDisplayList(base_info);
2381
2382 DlRect sk_bounds = ToDlRect(sk_picture->cullRect());
2383 checkPixels(sk_result.get(), sk_bounds, info + " (Skia reference)", bg);
2384
2385 if (testP.should_match(env, caseP, dl_job.setup_paint(), dl_job)) {
2386 quickCompareToReference(env.ref_sk_result(), sk_result.get(), true,
2387 info + " (attribute should not have effect)");
2388 } else {
2389 quickCompareToReference(env.ref_sk_result(), sk_result.get(), false,
2390 info + " (attribute should affect rendering)");
2391 }
2392
2393 // If either the reference setup or the test setup contain attributes
2394 // that Impeller doesn't support, we skip the Impeller testing. This
2395 // is mostly stroked or patterned text which is vectored through drawPath
2396 // for Impeller.
2397 if (env.supports_impeller() &&
2398 testP.impeller_compatible(dl_job.setup_paint()) &&
2399 testP.impeller_compatible(env.ref_dl_paint())) {
2400 DlJobRenderer imp_job(caseP.dl_setup(), //
2401 testP.imp_renderer(), //
2402 caseP.dl_restore(), //
2403 env.impeller_image());
2404 auto imp_result = env.getImpellerResult(base_info, imp_job);
2405 std::string imp_info = info + " (Impeller)";
2406 bool success = checkPixels(imp_result.get(), imp_result->render_bounds(),
2407 imp_info, bg);
2408 if (testP.should_match(env, caseP, imp_job.setup_paint(), imp_job)) {
2409 success = success && //
2411 env.ref_impeller_result(), imp_result.get(), true,
2412 imp_info + " (attribute should not have effect)");
2413 } else {
2414 success = success && //
2416 env.ref_impeller_result(), imp_result.get(), false,
2417 imp_info + " (attribute should affect rendering)");
2418 }
2419 if (SaveImpellerFailureImages && !success) {
2420 FML_LOG(ERROR) << "Impeller issue encountered for: "
2421 << *imp_job.MakeDisplayList(base_info);
2422 save_to_png(imp_result.get(), info + " (Impeller Result)",
2423 "output saved in");
2424 save_to_png(env.ref_impeller_result(), info + " (Impeller Reference)",
2425 "compare to reference without attributes");
2426 save_to_png(sk_result.get(), info + " (Skia Result)",
2427 "and to Skia reference with attributes");
2428 save_to_png(env.ref_sk_result(), info + " (Skia Reference)",
2429 "and to Skia reference without attributes");
2430 }
2431 }
2432
2433 quickCompareToReference(sk_result.get(), dl_result.get(), true,
2434 info + " (DlCanvas output matches SkCanvas)");
2435
2436 {
2437 DlRect dl_bounds = display_list->GetBounds();
2438 DlRect sk_padded_bounds = DlRect::RoundOut(sk_bounds);
2439 if (!sk_padded_bounds.Contains(dl_bounds)) {
2440 FML_LOG(ERROR) << "For " << info;
2441 FML_LOG(ERROR) << "sk ref: " << sk_bounds;
2442 FML_LOG(ERROR) << "dl: " << dl_bounds;
2443 if (!dl_bounds.Contains(sk_bounds)) {
2444 FML_LOG(ERROR) << "DisplayList bounds are too small!";
2445 }
2446 if (!dl_bounds.IsEmpty() &&
2447 !sk_padded_bounds.Contains(DlRect::RoundOut(dl_bounds))) {
2448 FML_LOG(ERROR) << "###### DisplayList bounds larger than reference!";
2449 }
2450 }
2451
2452 // This EXPECT sometimes triggers, but when it triggers and I examine
2453 // the ref_bounds, they are always unnecessarily large and since the
2454 // pixel OOB tests in the compare method do not trigger, we will trust
2455 // the DL bounds.
2456 // EXPECT_TRUE(dl_bounds.contains(ref_bounds)) << info;
2457
2458 // When we are drawing a DisplayList, the display_list built above
2459 // will contain just a single drawDisplayList call plus the case
2460 // attribute. The sk_picture will, however, contain a list of all
2461 // of the embedded calls in the display list and so the op counts
2462 // will not be equal between the two.
2463 if (!testP.is_draw_display_list()) {
2464 EXPECT_EQ(static_cast<int>(display_list->op_count()),
2465 sk_picture->approximateOpCount())
2466 << info;
2467 EXPECT_EQ(static_cast<int>(display_list->op_count()),
2468 sk_picture->approximateOpCount())
2469 << info;
2470 }
2471
2472 DisplayListJobRenderer dl_builder_job(display_list);
2473 auto dl_builder_result = env.getResult(base_info, dl_builder_job);
2474 if (caseP.fuzzy_compare_components()) {
2476 dl_builder_result.get(), dl_result.get(),
2477 info + " (DlCanvas DL output close to Builder Dl output)",
2478 &dl_bounds, &tolerance, bg, true);
2479 } else {
2481 dl_builder_result.get(), dl_result.get(), true,
2482 info + " (DlCanvas DL output matches Builder Dl output)");
2483 }
2484
2485 compareToReference(dl_result.get(), sk_result.get(),
2486 info + " (DisplayList built directly -> surface)",
2487 &dl_bounds, &tolerance, bg,
2488 caseP.fuzzy_compare_components());
2489
2490 if (display_list->can_apply_group_opacity()) {
2491 checkGroupOpacity(env, display_list, dl_result.get(),
2492 info + " with Group Opacity", bg);
2493 }
2494 }
2495
2496 {
2497 // This sequence uses an SkPicture generated previously from the SkCanvas
2498 // calls and a DisplayList generated previously from the DlCanvas calls
2499 // and renders both back under a transform (scale(2x)) to see if their
2500 // rendering is affected differently by a change of matrix between
2501 // recording time and rendering time.
2502 const int test_width_2 = kTestWidth * 2;
2503 const int test_height_2 = kTestHeight * 2;
2504 const DlScalar test_scale = 2.0;
2505
2506 SkPictureJobRenderer sk_job_x2(sk_picture);
2507 RenderJobInfo info_2x = {
2508 .width = test_width_2,
2509 .height = test_height_2,
2510 .bg = bg,
2511 .scale = test_scale,
2512 };
2513 auto ref_x2_result = env.getResult(info_2x, sk_job_x2);
2514 ASSERT_EQ(ref_x2_result->width(), test_width_2) << info;
2515 ASSERT_EQ(ref_x2_result->height(), test_height_2) << info;
2516
2517 DisplayListJobRenderer dl_job_x2(display_list);
2518 auto test_x2_result = env.getResult(info_2x, dl_job_x2);
2519 compareToReference(test_x2_result.get(), ref_x2_result.get(),
2520 info + " (Both rendered scaled 2x)", nullptr, nullptr,
2521 bg, caseP.fuzzy_compare_components(), //
2522 test_width_2, test_height_2, false);
2523 }
2524 }
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, int width=kTestWidth, int height=kTestHeight, bool printMismatches=false)
static void checkGroupOpacity(const RenderEnvironment &env, const sk_sp< DisplayList > &display_list, const RenderResult *ref_result, const std::string &info, DlColor bg)
impeller::Rect DlRect
const DlRect & ToDlRect(const SkRect &rect)
flutter::DlColor DlColor

References flutter::testing::TestParameters::adjust(), flutter::testing::RenderEnvironment::backend_name(), flutter::testing::RenderJobInfo::bg, flutter::testing::CaseParameters::bg(), checkGroupOpacity(), checkPixels(), compareToReference(), impeller::TRect< T >::Contains(), flutter::testing::RenderEnvironment::dl_image(), flutter::testing::TestParameters::dl_renderer(), flutter::testing::CaseParameters::dl_restore(), flutter::testing::CaseParameters::dl_setup(), FML_LOG, flutter::testing::CaseParameters::fuzzy_compare_components(), flutter::testing::RenderEnvironment::getImpellerResult(), flutter::testing::RenderEnvironment::getResult(), flutter::testing::TestParameters::imp_renderer(), flutter::testing::TestParameters::impeller_compatible(), flutter::testing::RenderEnvironment::impeller_image(), flutter::testing::CaseParameters::info(), flutter::testing::TestParameters::is_draw_display_list(), impeller::TRect< T >::IsEmpty(), flutter::testing::kTestHeight, flutter::testing::kTestWidth, flutter::testing::DlJobRenderer::MakeDisplayList(), flutter::testing::SkJobRenderer::MakePicture(), quickCompareToReference(), flutter::testing::RenderEnvironment::ref_dl_paint(), flutter::testing::RenderEnvironment::ref_impeller_result(), flutter::testing::RenderEnvironment::ref_sk_result(), impeller::TRect< Scalar >::RoundOut(), save_to_png(), SaveImpellerFailureImages, flutter::testing::MatrixClipJobRenderer::setup_clip_bounds(), flutter::testing::MatrixClipJobRenderer::setup_matrix(), flutter::testing::DlJobRenderer::setup_paint(), flutter::testing::TestParameters::should_match(), flutter::testing::RenderEnvironment::sk_image(), flutter::testing::TestParameters::sk_renderer(), flutter::testing::CaseParameters::sk_restore(), flutter::testing::CaseParameters::sk_setup(), flutter::testing::RenderEnvironment::supports_impeller(), flutter::ToDlRect(), and flutter::testing::RenderJobInfo::width.

Referenced by RenderWithAttributes(), RenderWithClips(), RenderWithSaveRestore(), RenderWithStrokes(), RenderWithTransforms(), and flutter::testing::TEST_F().

◆ RenderWithAttributes()

static void flutter::testing::CanvasCompareTester::RenderWithAttributes ( const TestParameters testP,
const RenderEnvironment env,
const BoundsTolerance tolerance 
)
inlinestatic

Definition at line 1487 of file dl_rendering_unittests.cc.

1489 {
1490 RenderWith(testP, env, tolerance, CaseParameters("Defaults Test"));
1491
1492 {
1493 // CPU renderer with default line width of 0 does not show antialiasing
1494 // for stroked primitives, so we make a new reference with a non-trivial
1495 // stroke width to demonstrate the differences
1496 RenderEnvironment aa_env = RenderEnvironment::MakeN32(env.provider());
1497 // Tweak the bounds tolerance for the displacement of 1/10 of a pixel
1498 const BoundsTolerance aa_tolerance = tolerance.addBoundsPadding(1, 1);
1499 auto sk_aa_setup = [=](SkSetupContext ctx, bool is_aa) {
1500 ctx.canvas->translate(0.1, 0.1);
1501 ctx.paint.setAntiAlias(is_aa);
1502 ctx.paint.setStrokeWidth(5.0);
1503 };
1504 auto dl_aa_setup = [=](DlSetupContext ctx, bool is_aa) {
1505 ctx.canvas->Translate(0.1, 0.1);
1506 ctx.paint.setAntiAlias(is_aa);
1507 ctx.paint.setStrokeWidth(5.0);
1508 };
1509 aa_env.init_ref(
1510 [=](const SkSetupContext& ctx) { sk_aa_setup(ctx, false); },
1511 testP.sk_renderer(),
1512 [=](const DlSetupContext& ctx) { dl_aa_setup(ctx, false); },
1513 testP.dl_renderer(), testP.imp_renderer());
1514 quickCompareToReference(aa_env, "AntiAlias");
1515 RenderWith(
1516 testP, aa_env, aa_tolerance,
1517 CaseParameters(
1518 "AntiAlias == True",
1519 [=](const SkSetupContext& ctx) { sk_aa_setup(ctx, true); },
1520 [=](const DlSetupContext& ctx) { dl_aa_setup(ctx, true); }));
1521 RenderWith(
1522 testP, aa_env, aa_tolerance,
1523 CaseParameters(
1524 "AntiAlias == False",
1525 [=](const SkSetupContext& ctx) { sk_aa_setup(ctx, false); },
1526 [=](const DlSetupContext& ctx) { dl_aa_setup(ctx, false); }));
1527 }
1528
1529 RenderWith( //
1530 testP, env, tolerance,
1531 CaseParameters(
1532 "Color == Blue",
1533 [=](const SkSetupContext& ctx) {
1534 ctx.paint.setColor(SK_ColorBLUE);
1535 },
1536 [=](const DlSetupContext& ctx) {
1537 ctx.paint.setColor(DlColor::kBlue());
1538 }));
1539 RenderWith( //
1540 testP, env, tolerance,
1541 CaseParameters(
1542 "Color == Green",
1543 [=](const SkSetupContext& ctx) {
1544 ctx.paint.setColor(SK_ColorGREEN);
1545 },
1546 [=](const DlSetupContext& ctx) {
1547 ctx.paint.setColor(DlColor::kGreen());
1548 }));
1549
1550 RenderWithStrokes(testP, env, tolerance);
1551
1552 {
1553 // half opaque cyan
1554 DlColor blendable_color = DlColor::kCyan().withAlpha(0x7f);
1555 DlColor bg = DlColor::kWhite();
1556
1557 RenderWith(testP, env, tolerance,
1558 CaseParameters(
1559 "Blend == SrcIn",
1560 [=](const SkSetupContext& ctx) {
1561 ctx.paint.setBlendMode(SkBlendMode::kSrcIn);
1562 ctx.paint.setColor(blendable_color.argb());
1563 },
1564 [=](const DlSetupContext& ctx) {
1565 ctx.paint.setBlendMode(DlBlendMode::kSrcIn);
1566 ctx.paint.setColor(blendable_color);
1567 })
1568 .with_bg(bg));
1569 RenderWith(testP, env, tolerance,
1570 CaseParameters(
1571 "Blend == DstIn",
1572 [=](const SkSetupContext& ctx) {
1573 ctx.paint.setBlendMode(SkBlendMode::kDstIn);
1574 ctx.paint.setColor(blendable_color.argb());
1575 },
1576 [=](const DlSetupContext& ctx) {
1577 ctx.paint.setBlendMode(DlBlendMode::kDstIn);
1578 ctx.paint.setColor(blendable_color);
1579 })
1580 .with_bg(bg));
1581 }
1582
1583 {
1584 // Being able to see a blur requires some non-default attributes,
1585 // like a non-trivial stroke width and a shader rather than a color
1586 // (for drawPaint) so we create a new environment for these tests.
1587 RenderEnvironment blur_env = RenderEnvironment::MakeN32(env.provider());
1588 SkSetup sk_blur_setup = [=](const SkSetupContext& ctx) {
1589 ctx.paint.setShader(MakeColorSource(ctx.image));
1590 ctx.paint.setStrokeWidth(5.0);
1591 };
1592 DlSetup dl_blur_setup = [=](const DlSetupContext& ctx) {
1593 ctx.paint.setColorSource(MakeColorSource(ctx.image));
1594 ctx.paint.setStrokeWidth(5.0);
1595 };
1596 blur_env.init_ref(sk_blur_setup, testP.sk_renderer(), //
1597 dl_blur_setup, testP.dl_renderer(),
1598 testP.imp_renderer());
1599 quickCompareToReference(blur_env, "blur");
1600 DlBlurImageFilter dl_filter_decal_5(5.0, 5.0, DlTileMode::kDecal);
1601 auto sk_filter_decal_5 =
1602 SkImageFilters::Blur(5.0, 5.0, SkTileMode::kDecal, nullptr);
1603 BoundsTolerance blur_5_tolerance = tolerance.addBoundsPadding(4, 4);
1604 {
1605 RenderWith(testP, blur_env, blur_5_tolerance,
1606 CaseParameters(
1607 "ImageFilter == Decal Blur 5",
1608 [=](const SkSetupContext& ctx) {
1609 sk_blur_setup(ctx);
1610 ctx.paint.setImageFilter(sk_filter_decal_5);
1611 },
1612 [=](const DlSetupContext& ctx) {
1613 dl_blur_setup(ctx);
1614 ctx.paint.setImageFilter(&dl_filter_decal_5);
1615 }));
1616 }
1617 DlBlurImageFilter dl_filter_clamp_5(5.0, 5.0, DlTileMode::kClamp);
1618 auto sk_filter_clamp_5 =
1619 SkImageFilters::Blur(5.0, 5.0, SkTileMode::kClamp, nullptr);
1620 {
1621 RenderWith(testP, blur_env, blur_5_tolerance,
1622 CaseParameters(
1623 "ImageFilter == Clamp Blur 5",
1624 [=](const SkSetupContext& ctx) {
1625 sk_blur_setup(ctx);
1626 ctx.paint.setImageFilter(sk_filter_clamp_5);
1627 },
1628 [=](const DlSetupContext& ctx) {
1629 dl_blur_setup(ctx);
1630 ctx.paint.setImageFilter(&dl_filter_clamp_5);
1631 }));
1632 }
1633 }
1634
1635 {
1636 // Being able to see a dilate requires some non-default attributes,
1637 // like a non-trivial stroke width and a shader rather than a color
1638 // (for drawPaint) so we create a new environment for these tests.
1639 RenderEnvironment dilate_env = RenderEnvironment::MakeN32(env.provider());
1640 SkSetup sk_dilate_setup = [=](const SkSetupContext& ctx) {
1641 ctx.paint.setShader(MakeColorSource(ctx.image));
1642 ctx.paint.setStrokeWidth(5.0);
1643 };
1644 DlSetup dl_dilate_setup = [=](const DlSetupContext& ctx) {
1645 ctx.paint.setColorSource(MakeColorSource(ctx.image));
1646 ctx.paint.setStrokeWidth(5.0);
1647 };
1648 dilate_env.init_ref(sk_dilate_setup, testP.sk_renderer(), //
1649 dl_dilate_setup, testP.dl_renderer(),
1650 testP.imp_renderer());
1651 quickCompareToReference(dilate_env, "dilate");
1652 DlDilateImageFilter dl_dilate_filter_5(5.0, 5.0);
1653 auto sk_dilate_filter_5 = SkImageFilters::Dilate(5.0, 5.0, nullptr);
1654 RenderWith(testP, dilate_env, tolerance,
1655 CaseParameters(
1656 "ImageFilter == Dilate 5",
1657 [=](const SkSetupContext& ctx) {
1658 sk_dilate_setup(ctx);
1659 ctx.paint.setImageFilter(sk_dilate_filter_5);
1660 },
1661 [=](const DlSetupContext& ctx) {
1662 dl_dilate_setup(ctx);
1663 ctx.paint.setImageFilter(&dl_dilate_filter_5);
1664 }));
1665 }
1666
1667 {
1668 // Being able to see an erode requires some non-default attributes,
1669 // like a non-trivial stroke width and a shader rather than a color
1670 // (for drawPaint) so we create a new environment for these tests.
1671 RenderEnvironment erode_env = RenderEnvironment::MakeN32(env.provider());
1672 SkSetup sk_erode_setup = [=](const SkSetupContext& ctx) {
1673 ctx.paint.setShader(MakeColorSource(ctx.image));
1674 ctx.paint.setStrokeWidth(6.0);
1675 };
1676 DlSetup dl_erode_setup = [=](const DlSetupContext& ctx) {
1677 ctx.paint.setColorSource(MakeColorSource(ctx.image));
1678 ctx.paint.setStrokeWidth(6.0);
1679 };
1680 erode_env.init_ref(sk_erode_setup, testP.sk_renderer(), //
1681 dl_erode_setup, testP.dl_renderer(),
1682 testP.imp_renderer());
1683 quickCompareToReference(erode_env, "erode");
1684 // do not erode too much, because some tests assert there are enough
1685 // pixels that are changed.
1686 DlErodeImageFilter dl_erode_filter_1(1.0, 1.0);
1687 auto sk_erode_filter_1 = SkImageFilters::Erode(1.0, 1.0, nullptr);
1688 RenderWith(testP, erode_env, tolerance,
1689 CaseParameters(
1690 "ImageFilter == Erode 1",
1691 [=](const SkSetupContext& ctx) {
1692 sk_erode_setup(ctx);
1693 ctx.paint.setImageFilter(sk_erode_filter_1);
1694 },
1695 [=](const DlSetupContext& ctx) {
1696 dl_erode_setup(ctx);
1697 ctx.paint.setImageFilter(&dl_erode_filter_1);
1698 }));
1699 }
1700
1701 {
1702 // clang-format off
1703 constexpr float rotate_color_matrix[20] = {
1704 0, 1, 0, 0, 0,
1705 0, 0, 1, 0, 0,
1706 1, 0, 0, 0, 0,
1707 0, 0, 0, 1, 0,
1708 };
1709 constexpr float invert_color_matrix[20] = {
1710 -1.0, 0, 0, 1.0, 0,
1711 0, -1.0, 0, 1.0, 0,
1712 0, 0, -1.0, 1.0, 0,
1713 1.0, 1.0, 1.0, 1.0, 0,
1714 };
1715 // clang-format on
1716 auto dl_color_filter = DlColorFilter::MakeMatrix(rotate_color_matrix);
1717 auto sk_color_filter = SkColorFilters::Matrix(rotate_color_matrix);
1718 {
1719 DlColor bg = DlColor::kWhite();
1720 RenderWith(testP, env, tolerance,
1721 CaseParameters(
1722 "ColorFilter == RotateRGB",
1723 [=](const SkSetupContext& ctx) {
1724 ctx.paint.setColor(SK_ColorYELLOW);
1725 ctx.paint.setColorFilter(sk_color_filter);
1726 },
1727 [=](const DlSetupContext& ctx) {
1728 ctx.paint.setColor(DlColor::kYellow());
1729 ctx.paint.setColorFilter(dl_color_filter);
1730 })
1731 .with_bg(bg));
1732 }
1733 {
1734 DlColor bg = DlColor::kWhite();
1735 RenderWith(testP, env, tolerance,
1736 CaseParameters(
1737 "ColorFilter == Invert",
1738 [=](const SkSetupContext& ctx) {
1739 ctx.paint.setColor(SK_ColorYELLOW);
1740 ctx.paint.setColorFilter(
1741 SkColorFilters::Matrix(invert_color_matrix));
1742 },
1743 [=](const DlSetupContext& ctx) {
1744 ctx.paint.setColor(DlColor::kYellow());
1745 ctx.paint.setInvertColors(true);
1746 })
1747 .with_bg(bg));
1748 }
1749 }
1750
1751 {
1752 const DlBlurMaskFilter dl_mask_filter(DlBlurStyle::kNormal, 5.0);
1753 auto sk_mask_filter = SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 5.0);
1754 BoundsTolerance blur_5_tolerance = tolerance.addBoundsPadding(4, 4);
1755 {
1756 // Stroked primitives need some non-trivial stroke size to be blurred
1757 RenderWith(testP, env, blur_5_tolerance,
1758 CaseParameters(
1759 "MaskFilter == Blur 5",
1760 [=](const SkSetupContext& ctx) {
1761 ctx.paint.setStrokeWidth(5.0);
1762 ctx.paint.setMaskFilter(sk_mask_filter);
1763 },
1764 [=](const DlSetupContext& ctx) {
1765 ctx.paint.setStrokeWidth(5.0);
1766 ctx.paint.setMaskFilter(&dl_mask_filter);
1767 }));
1768 }
1769 }
1770
1771 {
1772 DlPoint dl_end_points[] = {
1775 };
1776 DlColor dl_colors[] = {
1780 };
1781 SkColor sk_colors[] = {
1782 SK_ColorGREEN,
1783 SkColorSetA(SK_ColorYELLOW, 0x7f),
1784 SK_ColorBLUE,
1785 };
1786 float stops[] = {
1787 0.0,
1788 0.5,
1789 1.0,
1790 };
1791 auto dl_gradient =
1792 DlColorSource::MakeLinear(dl_end_points[0], dl_end_points[1], 3,
1793 dl_colors, stops, DlTileMode::kMirror);
1794 auto sk_gradient = SkGradientShader::MakeLinear(
1795 ToSkPoints(dl_end_points), sk_colors, stops, 3, SkTileMode::kMirror,
1796 0, nullptr);
1797 {
1798 RenderWith(testP, env, tolerance,
1799 CaseParameters(
1800 "LinearGradient GYB",
1801 [=](const SkSetupContext& ctx) {
1802 ctx.paint.setShader(sk_gradient);
1803 ctx.paint.setDither(testP.uses_gradient());
1804 },
1805 [=](const DlSetupContext& ctx) {
1806 ctx.paint.setColorSource(dl_gradient);
1807 }));
1808 }
1809 }
1810 }
static std::shared_ptr< const DlColorFilter > MakeMatrix(const float matrix[20])
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 void RenderWithStrokes(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance_in)
static void RenderWith(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance_in, const CaseParameters &caseP)
constexpr DlRect kRenderBounds
const std::function< void(const DlSetupContext &)> DlSetup
RenderContext< DlCanvas *, DlPaint &, sk_sp< DlImage > > DlSetupContext
RenderContext< SkCanvas *, SkPaint &, sk_sp< SkImage > > SkSetupContext
static std::shared_ptr< DlImageColorSource > MakeColorSource(const sk_sp< DlImage > &image)
const std::function< void(const SkSetupContext &)> SkSetup
const SkPoint * ToSkPoints(const DlPoint *points)
@ kNormal
fuzzy inside and outside
impeller::Point DlPoint
static constexpr DlColor kWhite()
Definition dl_color.h:70
static constexpr DlColor kBlue()
Definition dl_color.h:73
static constexpr DlColor kYellow()
Definition dl_color.h:76
static constexpr DlColor kGreen()
Definition dl_color.h:72
static constexpr DlColor kCyan()
Definition dl_color.h:74
DlColor withAlpha(uint8_t alpha) const
Definition dl_color.h:120
constexpr TPoint< T > GetLeftTop() const
Definition rect.h:359
constexpr TPoint< T > GetRightBottom() const
Definition rect.h:371

References flutter::testing::BoundsTolerance::addBoundsPadding(), flutter::DlColor::argb(), flutter::testing::TestParameters::dl_renderer(), impeller::TRect< T >::GetLeftTop(), impeller::TRect< T >::GetRightBottom(), flutter::testing::TestParameters::imp_renderer(), flutter::testing::RenderEnvironment::init_ref(), flutter::DlColor::kBlue(), flutter::kClamp, flutter::DlColor::kCyan(), flutter::kDecal, flutter::DlColor::kGreen(), flutter::kMirror, flutter::kNormal, flutter::testing::kRenderBounds, flutter::DlColor::kWhite(), flutter::DlColor::kYellow(), flutter::testing::MakeColorSource(), flutter::DlColorSource::MakeLinear(), flutter::DlColorFilter::MakeMatrix(), flutter::testing::RenderEnvironment::MakeN32(), flutter::testing::RenderEnvironment::provider(), quickCompareToReference(), RenderWith(), RenderWithStrokes(), flutter::testing::TestParameters::sk_renderer(), flutter::ToSkPoints(), flutter::testing::TestParameters::uses_gradient(), and flutter::DlColor::withAlpha().

Referenced by RenderAll().

◆ RenderWithClips()

static void flutter::testing::CanvasCompareTester::RenderWithClips ( const TestParameters testP,
const RenderEnvironment env,
const BoundsTolerance diff_tolerance 
)
inlinestatic

Definition at line 2110 of file dl_rendering_unittests.cc.

2112 {
2113 // We used to use an inset of 15.5 pixels here, but since Skia's rounding
2114 // behavior at the center of pixels does not match between HW and SW, we
2115 // ended up with some clips including different pixels between the two
2116 // destinations and this interacted poorly with the carefully chosen
2117 // geometry in some of the tests which was designed to have just the
2118 // right features fully filling the clips based on the SW rounding. By
2119 // moving to a 15.4 inset, the edge of the clip is never on the "rounding
2120 // edge" of a pixel.
2121 DlRect r_clip = kRenderBounds.Expand(-15.4, -15.4);
2122 BoundsTolerance intersect_tolerance = diff_tolerance.clip(r_clip);
2123 intersect_tolerance = intersect_tolerance.addPostClipPadding(1, 1);
2124 RenderWith(testP, env, intersect_tolerance,
2125 CaseParameters(
2126 "Hard ClipRect inset by 15.4",
2127 [=](const SkSetupContext& ctx) {
2128 ctx.canvas->clipRect(ToSkRect(r_clip),
2129 SkClipOp::kIntersect, false);
2130 },
2131 [=](const DlSetupContext& ctx) {
2132 ctx.canvas->ClipRect(r_clip, DlClipOp::kIntersect, false);
2133 }));
2134 RenderWith(testP, env, intersect_tolerance,
2135 CaseParameters(
2136 "AntiAlias ClipRect inset by 15.4",
2137 [=](const SkSetupContext& ctx) {
2138 ctx.canvas->clipRect(ToSkRect(r_clip),
2139 SkClipOp::kIntersect, true);
2140 },
2141 [=](const DlSetupContext& ctx) {
2142 ctx.canvas->ClipRect(r_clip, DlClipOp::kIntersect, true);
2143 }));
2144 RenderWith(testP, env, diff_tolerance,
2145 CaseParameters(
2146 "Hard ClipRect Diff, inset by 15.4",
2147 [=](const SkSetupContext& ctx) {
2148 ctx.canvas->clipRect(ToSkRect(r_clip),
2149 SkClipOp::kDifference, false);
2150 },
2151 [=](const DlSetupContext& ctx) {
2152 ctx.canvas->ClipRect(r_clip, DlClipOp::kDifference, false);
2153 })
2154 .with_diff_clip());
2155 RenderWith(testP, env, intersect_tolerance,
2156 CaseParameters(
2157 "Hard ClipOval",
2158 [=](const SkSetupContext& ctx) {
2159 // Skia lacks clipOval so we use an oval SkRRect
2160 ctx.canvas->clipRRect(SkRRect::MakeOval(ToSkRect(r_clip)),
2161 SkClipOp::kIntersect, false);
2162 },
2163 [=](const DlSetupContext& ctx) {
2164 ctx.canvas->ClipOval(r_clip, DlClipOp::kIntersect, false);
2165 }));
2166 RenderWith(testP, env, intersect_tolerance,
2167 CaseParameters(
2168 "AntiAlias ClipOval",
2169 [=](const SkSetupContext& ctx) {
2170 // Skia lacks clipOval so we use an oval SkRRect
2171 ctx.canvas->clipRRect(SkRRect::MakeOval(ToSkRect(r_clip)),
2172 SkClipOp::kIntersect, true);
2173 },
2174 [=](const DlSetupContext& ctx) {
2175 ctx.canvas->ClipOval(r_clip, DlClipOp::kIntersect, true);
2176 }));
2177 RenderWith(testP, env, diff_tolerance,
2178 CaseParameters(
2179 "Hard ClipOval Diff",
2180 [=](const SkSetupContext& ctx) {
2181 // Skia lacks clipOval so we use an oval SkRRect
2182 ctx.canvas->clipRRect(SkRRect::MakeOval(ToSkRect(r_clip)),
2183 SkClipOp::kDifference, false);
2184 },
2185 [=](const DlSetupContext& ctx) {
2186 ctx.canvas->ClipOval(r_clip, DlClipOp::kDifference, false);
2187 })
2188 .with_diff_clip());
2189 // This test RR clip used to use very small radii, but due to
2190 // optimizations in the HW rrect rasterization, this caused small
2191 // bulges in the corners of the RRect which were interpreted as
2192 // "clip overruns" by the clip OOB pixel testing code. Using less
2193 // abusively small radii fixes the problem.
2194 DlRoundRect rr_clip = DlRoundRect::MakeRectXY(r_clip, 9, 9);
2195 RenderWith(testP, env, intersect_tolerance,
2196 CaseParameters(
2197 "Hard ClipRRect with radius of 9",
2198 [=](const SkSetupContext& ctx) {
2199 ctx.canvas->clipRRect(ToSkRRect(rr_clip),
2200 SkClipOp::kIntersect, false);
2201 },
2202 [=](const DlSetupContext& ctx) {
2203 ctx.canvas->ClipRoundRect(rr_clip, DlClipOp::kIntersect,
2204 false);
2205 }));
2206 RenderWith(testP, env, intersect_tolerance,
2207 CaseParameters(
2208 "AntiAlias ClipRRect with radius of 9",
2209 [=](const SkSetupContext& ctx) {
2210 ctx.canvas->clipRRect(ToSkRRect(rr_clip),
2211 SkClipOp::kIntersect, true);
2212 },
2213 [=](const DlSetupContext& ctx) {
2214 ctx.canvas->ClipRoundRect(rr_clip, DlClipOp::kIntersect,
2215 true);
2216 }));
2217 RenderWith(testP, env, diff_tolerance,
2218 CaseParameters(
2219 "Hard ClipRRect Diff, with radius of 9",
2220 [=](const SkSetupContext& ctx) {
2221 ctx.canvas->clipRRect(ToSkRRect(rr_clip),
2222 SkClipOp::kDifference, false);
2223 },
2224 [=](const DlSetupContext& ctx) {
2225 ctx.canvas->ClipRoundRect(rr_clip, DlClipOp::kDifference,
2226 false);
2227 })
2228 .with_diff_clip());
2229 DlPathBuilder path_builder;
2230 path_builder.SetFillType(DlPathFillType::kOdd);
2231 path_builder.AddRect(r_clip);
2232 path_builder.AddCircle(DlPoint(kRenderCenterX, kRenderCenterY), 1.0f);
2233 DlPath path_clip = path_builder.TakePath();
2234 RenderWith(testP, env, intersect_tolerance,
2235 CaseParameters(
2236 "Hard ClipPath inset by 15.4",
2237 [=](const SkSetupContext& ctx) {
2238 ctx.canvas->clipPath(path_clip.GetSkPath(),
2239 SkClipOp::kIntersect, false);
2240 },
2241 [=](const DlSetupContext& ctx) {
2242 ctx.canvas->ClipPath(path_clip, DlClipOp::kIntersect,
2243 false);
2244 }));
2245 RenderWith(testP, env, intersect_tolerance,
2246 CaseParameters(
2247 "AntiAlias ClipPath inset by 15.4",
2248 [=](const SkSetupContext& ctx) {
2249 ctx.canvas->clipPath(path_clip.GetSkPath(),
2250 SkClipOp::kIntersect, true);
2251 },
2252 [=](const DlSetupContext& ctx) {
2253 ctx.canvas->ClipPath(path_clip, DlClipOp::kIntersect,
2254 true);
2255 }));
2256 RenderWith(testP, env, diff_tolerance,
2257 CaseParameters(
2258 "Hard ClipPath Diff, inset by 15.4",
2259 [=](const SkSetupContext& ctx) {
2260 ctx.canvas->clipPath(path_clip.GetSkPath(),
2261 SkClipOp::kDifference, false);
2262 },
2263 [=](const DlSetupContext& ctx) {
2264 ctx.canvas->ClipPath(path_clip, DlClipOp::kDifference,
2265 false);
2266 })
2267 .with_diff_clip());
2268 }
impeller::RoundRect DlRoundRect
const SkRRect ToSkRRect(const DlRoundRect &round_rect)
const SkRect & ToSkRect(const DlRect &rect)
flutter::DlPath DlPath
static RoundRect MakeRectXY(const Rect &rect, Scalar x_radius, Scalar y_radius)
Definition round_rect.h:31
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:618

References flutter::DlPathBuilder::AddCircle(), flutter::testing::BoundsTolerance::addPostClipPadding(), flutter::DlPathBuilder::AddRect(), flutter::testing::BoundsTolerance::clip(), impeller::TRect< T >::Expand(), flutter::DlPath::GetSkPath(), flutter::kDifference, flutter::kIntersect, flutter::testing::kRenderBounds, flutter::testing::kRenderCenterX, flutter::testing::kRenderCenterY, impeller::RoundRect::MakeRectXY(), RenderWith(), flutter::DlPathBuilder::SetFillType(), flutter::ToSkRect(), and flutter::ToSkRRect().

Referenced by RenderAll().

◆ RenderWithSaveRestore()

static void flutter::testing::CanvasCompareTester::RenderWithSaveRestore ( const TestParameters testP,
const RenderEnvironment env,
const BoundsTolerance tolerance 
)
inlinestatic

Definition at line 1175 of file dl_rendering_unittests.cc.

1177 {
1178 DlRect clip =
1181 DlColor alpha_layer_color = DlColor::kCyan().withAlpha(0x7f);
1182 SkRenderer sk_safe_restore = [=](const SkRenderContext& ctx) {
1183 // Draw another primitive to disable peephole optimizations
1184 ctx.canvas->drawRect(ToSkRect(kRenderBounds).makeOffset(500, 500),
1185 SkPaint());
1186 ctx.canvas->restore();
1187 };
1188 DlRenderer dl_safe_restore = [=](const DlRenderContext& ctx) {
1189 // Draw another primitive to disable peephole optimizations
1190 // As the rendering op rejection in the DisplayList Builder
1191 // gets smarter and smarter, this operation has had to get
1192 // sneakier and sneakier about specifying an operation that
1193 // won't practically show up in the output, but technically
1194 // can't be culled.
1195 ctx.canvas->DrawRect(
1197 DlPaint());
1198 ctx.canvas->Restore();
1199 };
1200 SkRenderer sk_opt_restore = [=](const SkRenderContext& ctx) {
1201 // Just a simple restore to allow peephole optimizations to occur
1202 ctx.canvas->restore();
1203 };
1204 DlRenderer dl_opt_restore = [=](const DlRenderContext& ctx) {
1205 // Just a simple restore to allow peephole optimizations to occur
1206 ctx.canvas->Restore();
1207 };
1208 DlRect layer_bounds = kRenderBounds.Expand(-15, -15);
1209 RenderWith(testP, env, tolerance,
1210 CaseParameters(
1211 "With prior save/clip/restore",
1212 [=](const SkSetupContext& ctx) {
1213 ctx.canvas->save();
1214 ctx.canvas->clipRect(ToSkRect(clip), SkClipOp::kIntersect,
1215 false);
1216 SkPaint p2;
1217 ctx.canvas->drawRect(ToSkRect(rect), p2);
1218 p2.setBlendMode(SkBlendMode::kClear);
1219 ctx.canvas->drawRect(ToSkRect(rect), p2);
1220 ctx.canvas->restore();
1221 },
1222 [=](const DlSetupContext& ctx) {
1223 ctx.canvas->Save();
1224 ctx.canvas->ClipRect(clip, DlClipOp::kIntersect, false);
1225 DlPaint p2;
1226 ctx.canvas->DrawRect(rect, p2);
1227 p2.setBlendMode(DlBlendMode::kClear);
1228 ctx.canvas->DrawRect(rect, p2);
1229 ctx.canvas->Restore();
1230 }));
1231 RenderWith(testP, env, tolerance,
1232 CaseParameters(
1233 "saveLayer no paint, no bounds",
1234 [=](const SkSetupContext& ctx) {
1235 ctx.canvas->saveLayer(nullptr, nullptr);
1236 },
1237 [=](const DlSetupContext& ctx) {
1238 ctx.canvas->SaveLayer(std::nullopt, nullptr);
1239 })
1240 .with_restore(sk_safe_restore, dl_safe_restore, false));
1241 RenderWith(testP, env, tolerance,
1242 CaseParameters(
1243 "saveLayer no paint, with bounds",
1244 [=](const SkSetupContext& ctx) {
1245 ctx.canvas->saveLayer(ToSkRect(layer_bounds), nullptr);
1246 },
1247 [=](const DlSetupContext& ctx) {
1248 ctx.canvas->SaveLayer(layer_bounds, nullptr);
1249 })
1250 .with_restore(sk_safe_restore, dl_safe_restore, true));
1251 RenderWith(testP, env, tolerance,
1252 CaseParameters(
1253 "saveLayer with alpha, no bounds",
1254 [=](const SkSetupContext& ctx) {
1255 SkPaint save_p;
1256 save_p.setColor(ToSkColor4f(alpha_layer_color));
1257 ctx.canvas->saveLayer(nullptr, &save_p);
1258 },
1259 [=](const DlSetupContext& ctx) {
1260 DlPaint save_p;
1261 save_p.setColor(alpha_layer_color);
1262 ctx.canvas->SaveLayer(std::nullopt, &save_p);
1263 })
1264 .with_restore(sk_safe_restore, dl_safe_restore, true));
1265 RenderWith(testP, env, tolerance,
1266 CaseParameters(
1267 "saveLayer with peephole alpha, no bounds",
1268 [=](const SkSetupContext& ctx) {
1269 SkPaint save_p;
1270 save_p.setColor(ToSkColor4f(alpha_layer_color));
1271 ctx.canvas->saveLayer(nullptr, &save_p);
1272 },
1273 [=](const DlSetupContext& ctx) {
1274 DlPaint save_p;
1275 save_p.setColor(alpha_layer_color);
1276 ctx.canvas->SaveLayer(std::nullopt, &save_p);
1277 })
1278 .with_restore(sk_opt_restore, dl_opt_restore, true, true));
1279 RenderWith(testP, env, tolerance,
1280 CaseParameters(
1281 "saveLayer with alpha and bounds",
1282 [=](const SkSetupContext& ctx) {
1283 SkPaint save_p;
1284 save_p.setColor(ToSkColor4f(alpha_layer_color));
1285 ctx.canvas->saveLayer(ToSkRect(layer_bounds), &save_p);
1286 },
1287 [=](const DlSetupContext& ctx) {
1288 DlPaint save_p;
1289 save_p.setColor(alpha_layer_color);
1290 ctx.canvas->SaveLayer(layer_bounds, &save_p);
1291 })
1292 .with_restore(sk_safe_restore, dl_safe_restore, true));
1293 {
1294 // Being able to see a backdrop blur requires a non-default background
1295 // so we create a new environment for these tests that has a checkerboard
1296 // background that can be blurred by the backdrop filter. We also want
1297 // to avoid the rendered primitive from obscuring the blurred background
1298 // so we set an alpha value which works for all primitives except for
1299 // drawColor which can override the alpha with its color, but it now uses
1300 // a non-opaque color to avoid that problem.
1301 RenderEnvironment backdrop_env =
1302 RenderEnvironment::MakeN32(env.provider());
1303 SkSetup sk_backdrop_setup = [=](const SkSetupContext& ctx) {
1304 SkPaint setup_p;
1305 setup_p.setShader(MakeColorSource(ctx.image));
1306 ctx.canvas->drawPaint(setup_p);
1307 };
1308 DlSetup dl_backdrop_setup = [=](const DlSetupContext& ctx) {
1309 DlPaint setup_p;
1310 setup_p.setColorSource(MakeColorSource(ctx.image));
1311 ctx.canvas->DrawPaint(setup_p);
1312 };
1313 SkSetup sk_content_setup = [=](const SkSetupContext& ctx) {
1314 ctx.paint.setAlpha(ctx.paint.getAlpha() / 2);
1315 };
1316 DlSetup dl_content_setup = [=](const DlSetupContext& ctx) {
1317 ctx.paint.setAlpha(ctx.paint.getAlpha() / 2);
1318 };
1319 backdrop_env.init_ref(sk_backdrop_setup, testP.sk_renderer(),
1320 dl_backdrop_setup, testP.dl_renderer(),
1321 testP.imp_renderer());
1322 quickCompareToReference(backdrop_env, "backdrop");
1323
1324 DlBlurImageFilter dl_backdrop(5, 5, DlTileMode::kDecal);
1325 auto sk_backdrop =
1326 SkImageFilters::Blur(5, 5, SkTileMode::kDecal, nullptr);
1327 RenderWith(
1328 testP, backdrop_env, tolerance,
1329 CaseParameters(
1330 "saveLayer with backdrop",
1331 [=](const SkSetupContext& ctx) {
1332 sk_backdrop_setup(ctx);
1333 ctx.canvas->saveLayer(
1334 SkCanvas::SaveLayerRec(nullptr, nullptr, sk_backdrop.get(),
1335 SkTileMode::kDecal, nullptr, 0));
1336 sk_content_setup(ctx);
1337 },
1338 [=](const DlSetupContext& ctx) {
1339 dl_backdrop_setup(ctx);
1340 ctx.canvas->SaveLayer(std::nullopt, nullptr, &dl_backdrop);
1341 dl_content_setup(ctx);
1342 })
1343 .with_restore(sk_safe_restore, dl_safe_restore, true));
1344 RenderWith(testP, backdrop_env, tolerance,
1345 CaseParameters(
1346 "saveLayer with bounds and backdrop",
1347 [=](const SkSetupContext& ctx) {
1348 sk_backdrop_setup(ctx);
1349 ctx.canvas->saveLayer(SkCanvas::SaveLayerRec(
1350 &ToSkRect(layer_bounds), nullptr, sk_backdrop.get(),
1351 SkTileMode::kDecal, nullptr, 0));
1352 sk_content_setup(ctx);
1353 },
1354 [=](const DlSetupContext& ctx) {
1355 dl_backdrop_setup(ctx);
1356 ctx.canvas->SaveLayer(layer_bounds, nullptr,
1357 &dl_backdrop);
1358 dl_content_setup(ctx);
1359 })
1360 .with_restore(sk_safe_restore, dl_safe_restore, true));
1361 RenderWith(
1362 testP, backdrop_env, tolerance,
1363 CaseParameters(
1364 "clipped saveLayer with backdrop",
1365 [=](const SkSetupContext& ctx) {
1366 sk_backdrop_setup(ctx);
1367 ctx.canvas->clipRect(ToSkRect(layer_bounds));
1368 ctx.canvas->saveLayer(
1369 SkCanvas::SaveLayerRec(nullptr, nullptr, sk_backdrop.get(),
1370 SkTileMode::kDecal, nullptr, 0));
1371 sk_content_setup(ctx);
1372 },
1373 [=](const DlSetupContext& ctx) {
1374 dl_backdrop_setup(ctx);
1375 ctx.canvas->ClipRect(layer_bounds);
1376 ctx.canvas->SaveLayer(std::nullopt, nullptr, &dl_backdrop);
1377 dl_content_setup(ctx);
1378 })
1379 .with_restore(sk_safe_restore, dl_safe_restore, true));
1380 }
1381
1382 {
1383 // clang-format off
1384 constexpr float rotate_alpha_color_matrix[20] = {
1385 0, 1, 0, 0 , 0,
1386 0, 0, 1, 0 , 0,
1387 1, 0, 0, 0 , 0,
1388 0, 0, 0, 0.5, 0,
1389 };
1390 // clang-format on
1391 auto dl_alpha_rotate_filter =
1392 DlColorFilter::MakeMatrix(rotate_alpha_color_matrix);
1393 auto sk_alpha_rotate_filter =
1394 SkColorFilters::Matrix(rotate_alpha_color_matrix);
1395 {
1396 RenderWith(testP, env, tolerance,
1397 CaseParameters(
1398 "saveLayer ColorFilter, no bounds",
1399 [=](const SkSetupContext& ctx) {
1400 SkPaint save_p;
1401 save_p.setColorFilter(sk_alpha_rotate_filter);
1402 ctx.canvas->saveLayer(nullptr, &save_p);
1403 ctx.paint.setStrokeWidth(5.0);
1404 },
1405 [=](const DlSetupContext& ctx) {
1406 DlPaint save_p;
1407 save_p.setColorFilter(dl_alpha_rotate_filter);
1408 ctx.canvas->SaveLayer(std::nullopt, &save_p);
1409 ctx.paint.setStrokeWidth(5.0);
1410 })
1411 .with_restore(sk_safe_restore, dl_safe_restore, true));
1412 }
1413 {
1414 RenderWith(testP, env, tolerance,
1415 CaseParameters(
1416 "saveLayer ColorFilter and bounds",
1417 [=](const SkSetupContext& ctx) {
1418 SkPaint save_p;
1419 save_p.setColorFilter(sk_alpha_rotate_filter);
1420 ctx.canvas->saveLayer(ToSkRect(kRenderBounds),
1421 &save_p);
1422 ctx.paint.setStrokeWidth(5.0);
1423 },
1424 [=](const DlSetupContext& ctx) {
1425 DlPaint save_p;
1426 save_p.setColorFilter(dl_alpha_rotate_filter);
1427 ctx.canvas->SaveLayer(kRenderBounds, &save_p);
1428 ctx.paint.setStrokeWidth(5.0);
1429 })
1430 .with_restore(sk_safe_restore, dl_safe_restore, true));
1431 }
1432 }
1433
1434 {
1435 // clang-format off
1436 constexpr float color_matrix[20] = {
1437 0.5, 0, 0, 0, 0.5,
1438 0, 0.5, 0, 0, 0.5,
1439 0, 0, 0.5, 0, 0.5,
1440 0, 0, 0, 1, 0,
1441 };
1442 // clang-format on
1443 auto dl_color_filter = DlColorFilter::MakeMatrix(color_matrix);
1444 auto dl_cf_image_filter = DlImageFilter::MakeColorFilter(dl_color_filter);
1445 auto sk_cf_image_filter = SkImageFilters::ColorFilter(
1446 SkColorFilters::Matrix(color_matrix), nullptr);
1447 {
1448 RenderWith(testP, env, tolerance,
1449 CaseParameters(
1450 "saveLayer ImageFilter, no bounds",
1451 [=](const SkSetupContext& ctx) {
1452 SkPaint save_p;
1453 save_p.setImageFilter(sk_cf_image_filter);
1454 ctx.canvas->saveLayer(nullptr, &save_p);
1455 ctx.paint.setStrokeWidth(5.0);
1456 },
1457 [=](const DlSetupContext& ctx) {
1458 DlPaint save_p;
1459 save_p.setImageFilter(dl_cf_image_filter);
1460 ctx.canvas->SaveLayer(std::nullopt, &save_p);
1461 ctx.paint.setStrokeWidth(5.0);
1462 })
1463 .with_restore(sk_safe_restore, dl_safe_restore, true));
1464 }
1465 {
1466 RenderWith(testP, env, tolerance,
1467 CaseParameters(
1468 "saveLayer ImageFilter and bounds",
1469 [=](const SkSetupContext& ctx) {
1470 SkPaint save_p;
1471 save_p.setImageFilter(sk_cf_image_filter);
1472 ctx.canvas->saveLayer(ToSkRect(kRenderBounds),
1473 &save_p);
1474 ctx.paint.setStrokeWidth(5.0);
1475 },
1476 [=](const DlSetupContext& ctx) {
1477 DlPaint save_p;
1478 save_p.setImageFilter(dl_cf_image_filter);
1479 ctx.canvas->SaveLayer(kRenderBounds, &save_p);
1480 ctx.paint.setStrokeWidth(5.0);
1481 })
1482 .with_restore(sk_safe_restore, dl_safe_restore, true));
1483 }
1484 }
1485 }
static std::shared_ptr< DlImageFilter > MakeColorFilter(const std::shared_ptr< const DlColorFilter > &filter)
DlPaint & setColor(DlColor color)
Definition dl_paint.h:70
DlPaint & setStrokeWidth(float width)
Definition dl_paint.h:115
DlPaint & setAlpha(uint8_t alpha)
Definition dl_paint.h:76
DlPaint & setBlendMode(DlBlendMode mode)
Definition dl_paint.h:85
DlPaint & setImageFilter(std::nullptr_t filter)
Definition dl_paint.h:167
DlPaint & setColorFilter(std::nullptr_t filter)
Definition dl_paint.h:149
DlPaint & setColorSource(std::nullptr_t source)
Definition dl_paint.h:131
const std::function< void(const SkRenderContext &)> SkRenderer
RenderContext< DlCanvas *, const DlPaint &, sk_sp< DlImage > > DlRenderContext
RenderContext< SkCanvas *, const SkPaint &, sk_sp< SkImage > > SkRenderContext
const std::function< void(const DlRenderContext &)> DlRenderer
SkColor4f ToSkColor4f(DlColor color)
flutter::DlPaint DlPaint
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition rect.h:136

References flutter::testing::TestParameters::dl_renderer(), impeller::TRect< T >::Expand(), flutter::testing::TestParameters::imp_renderer(), flutter::testing::RenderEnvironment::init_ref(), flutter::DlColor::kCyan(), flutter::kDecal, flutter::kIntersect, flutter::testing::kRenderBounds, flutter::testing::kRenderCenterX, flutter::testing::kRenderCenterY, flutter::DlImageFilter::MakeColorFilter(), flutter::testing::MakeColorSource(), flutter::DlColorFilter::MakeMatrix(), flutter::testing::RenderEnvironment::MakeN32(), impeller::TRect< Scalar >::MakeXYWH(), flutter::testing::RenderEnvironment::provider(), quickCompareToReference(), RenderWith(), flutter::DlPaint::setAlpha(), flutter::DlPaint::setBlendMode(), flutter::DlPaint::setColor(), flutter::DlPaint::setColorFilter(), flutter::DlPaint::setColorSource(), flutter::DlPaint::setImageFilter(), flutter::DlPaint::setStrokeWidth(), flutter::testing::TestParameters::sk_renderer(), flutter::ToSkColor4f(), flutter::ToSkRect(), and flutter::DlColor::withAlpha().

Referenced by RenderAll().

◆ RenderWithStrokes()

static void flutter::testing::CanvasCompareTester::RenderWithStrokes ( const TestParameters testP,
const RenderEnvironment env,
const BoundsTolerance tolerance_in 
)
inlinestatic

Definition at line 1812 of file dl_rendering_unittests.cc.

1814 {
1815 // The test cases were generated with geometry that will try to fill
1816 // out the various miter limits used for testing, but they can be off
1817 // by a couple of pixels so we will relax bounds testing for strokes by
1818 // a couple of pixels.
1819 BoundsTolerance tolerance = tolerance_in.addBoundsPadding(2, 2);
1820 RenderWith(testP, env, tolerance,
1821 CaseParameters(
1822 "Fill",
1823 [=](const SkSetupContext& ctx) {
1824 ctx.paint.setStyle(SkPaint::kFill_Style);
1825 },
1826 [=](const DlSetupContext& ctx) {
1827 ctx.paint.setDrawStyle(DlDrawStyle::kFill);
1828 }));
1829 // Skia on HW produces a strong miter consistent with width=1.0
1830 // for any width less than a pixel, but the bounds computations of
1831 // both DL and SkPicture do not account for this. We will get
1832 // OOB pixel errors for the highly mitered drawPath geometry if
1833 // we don't set stroke width to 1.0 for that test on HW.
1834 // See https://bugs.chromium.org/p/skia/issues/detail?id=14046
1835 bool no_hairlines =
1836 testP.is_draw_path() &&
1837 env.provider()->backend_type() != BackendType::kSoftwareBackend;
1838 RenderWith(testP, env, tolerance,
1839 CaseParameters(
1840 "Stroke + defaults",
1841 [=](const SkSetupContext& ctx) {
1842 if (no_hairlines) {
1843 ctx.paint.setStrokeWidth(1.0);
1844 }
1845 ctx.paint.setStyle(SkPaint::kStroke_Style);
1846 },
1847 [=](const DlSetupContext& ctx) {
1848 if (no_hairlines) {
1849 ctx.paint.setStrokeWidth(1.0);
1850 }
1851 ctx.paint.setDrawStyle(DlDrawStyle::kStroke);
1852 }));
1853
1854 RenderWith(testP, env, tolerance,
1855 CaseParameters(
1856 "Fill + unnecessary StrokeWidth 10",
1857 [=](const SkSetupContext& ctx) {
1858 ctx.paint.setStyle(SkPaint::kFill_Style);
1859 ctx.paint.setStrokeWidth(10.0);
1860 },
1861 [=](const DlSetupContext& ctx) {
1862 ctx.paint.setDrawStyle(DlDrawStyle::kFill);
1863 ctx.paint.setStrokeWidth(10.0);
1864 }));
1865
1866 RenderEnvironment stroke_base_env =
1867 RenderEnvironment::MakeN32(env.provider());
1868 SkSetup sk_stroke_setup = [=](const SkSetupContext& ctx) {
1869 ctx.paint.setStyle(SkPaint::kStroke_Style);
1870 ctx.paint.setStrokeWidth(5.0);
1871 };
1872 DlSetup dl_stroke_setup = [=](const DlSetupContext& ctx) {
1873 ctx.paint.setDrawStyle(DlDrawStyle::kStroke);
1874 ctx.paint.setStrokeWidth(5.0);
1875 };
1876 stroke_base_env.init_ref(sk_stroke_setup, testP.sk_renderer(),
1877 dl_stroke_setup, testP.dl_renderer(),
1878 testP.imp_renderer());
1879 quickCompareToReference(stroke_base_env, "stroke");
1880
1881 RenderWith(testP, stroke_base_env, tolerance,
1882 CaseParameters(
1883 "Stroke Width 10",
1884 [=](const SkSetupContext& ctx) {
1885 ctx.paint.setStyle(SkPaint::kStroke_Style);
1886 ctx.paint.setStrokeWidth(10.0);
1887 },
1888 [=](const DlSetupContext& ctx) {
1889 ctx.paint.setDrawStyle(DlDrawStyle::kStroke);
1890 ctx.paint.setStrokeWidth(10.0);
1891 }));
1892 RenderWith(testP, stroke_base_env, tolerance,
1893 CaseParameters(
1894 "Stroke Width 5",
1895 [=](const SkSetupContext& ctx) {
1896 ctx.paint.setStyle(SkPaint::kStroke_Style);
1897 ctx.paint.setStrokeWidth(5.0);
1898 },
1899 [=](const DlSetupContext& ctx) {
1900 ctx.paint.setDrawStyle(DlDrawStyle::kStroke);
1901 ctx.paint.setStrokeWidth(5.0);
1902 }));
1903
1904 RenderWith(testP, stroke_base_env, tolerance,
1905 CaseParameters(
1906 "Stroke Width 5, Square Cap",
1907 [=](const SkSetupContext& ctx) {
1908 ctx.paint.setStyle(SkPaint::kStroke_Style);
1909 ctx.paint.setStrokeWidth(5.0);
1910 ctx.paint.setStrokeCap(SkPaint::kSquare_Cap);
1911 },
1912 [=](const DlSetupContext& ctx) {
1913 ctx.paint.setDrawStyle(DlDrawStyle::kStroke);
1914 ctx.paint.setStrokeWidth(5.0);
1915 ctx.paint.setStrokeCap(DlStrokeCap::kSquare);
1916 }));
1917 RenderWith(testP, stroke_base_env, tolerance,
1918 CaseParameters(
1919 "Stroke Width 5, Round Cap",
1920 [=](const SkSetupContext& ctx) {
1921 ctx.paint.setStyle(SkPaint::kStroke_Style);
1922 ctx.paint.setStrokeWidth(5.0);
1923 ctx.paint.setStrokeCap(SkPaint::kRound_Cap);
1924 },
1925 [=](const DlSetupContext& ctx) {
1926 ctx.paint.setDrawStyle(DlDrawStyle::kStroke);
1927 ctx.paint.setStrokeWidth(5.0);
1928 ctx.paint.setStrokeCap(DlStrokeCap::kRound);
1929 }));
1930
1931 RenderWith(testP, stroke_base_env, tolerance,
1932 CaseParameters(
1933 "Stroke Width 5, Bevel Join",
1934 [=](const SkSetupContext& ctx) {
1935 ctx.paint.setStyle(SkPaint::kStroke_Style);
1936 ctx.paint.setStrokeWidth(5.0);
1937 ctx.paint.setStrokeJoin(SkPaint::kBevel_Join);
1938 },
1939 [=](const DlSetupContext& ctx) {
1940 ctx.paint.setDrawStyle(DlDrawStyle::kStroke);
1941 ctx.paint.setStrokeWidth(5.0);
1942 ctx.paint.setStrokeJoin(DlStrokeJoin::kBevel);
1943 }));
1944 RenderWith(testP, stroke_base_env, tolerance,
1945 CaseParameters(
1946 "Stroke Width 5, Round Join",
1947 [=](const SkSetupContext& ctx) {
1948 ctx.paint.setStyle(SkPaint::kStroke_Style);
1949 ctx.paint.setStrokeWidth(5.0);
1950 ctx.paint.setStrokeJoin(SkPaint::kRound_Join);
1951 },
1952 [=](const DlSetupContext& ctx) {
1953 ctx.paint.setDrawStyle(DlDrawStyle::kStroke);
1954 ctx.paint.setStrokeWidth(5.0);
1955 ctx.paint.setStrokeJoin(DlStrokeJoin::kRound);
1956 }));
1957
1958 RenderWith(testP, stroke_base_env, tolerance,
1959 CaseParameters(
1960 "Stroke Width 5, Miter 10",
1961 [=](const SkSetupContext& ctx) {
1962 ctx.paint.setStyle(SkPaint::kStroke_Style);
1963 ctx.paint.setStrokeWidth(5.0);
1964 ctx.paint.setStrokeMiter(10.0);
1965 ctx.paint.setStrokeJoin(SkPaint::kMiter_Join);
1966 },
1967 [=](const DlSetupContext& ctx) {
1968 ctx.paint.setDrawStyle(DlDrawStyle::kStroke);
1969 ctx.paint.setStrokeWidth(5.0);
1970 ctx.paint.setStrokeMiter(10.0);
1971 ctx.paint.setStrokeJoin(DlStrokeJoin::kMiter);
1972 }));
1973
1974 RenderWith(testP, stroke_base_env, tolerance,
1975 CaseParameters(
1976 "Stroke Width 5, Miter 0",
1977 [=](const SkSetupContext& ctx) {
1978 ctx.paint.setStyle(SkPaint::kStroke_Style);
1979 ctx.paint.setStrokeWidth(5.0);
1980 ctx.paint.setStrokeMiter(0.0);
1981 ctx.paint.setStrokeJoin(SkPaint::kMiter_Join);
1982 },
1983 [=](const DlSetupContext& ctx) {
1984 ctx.paint.setDrawStyle(DlDrawStyle::kStroke);
1985 ctx.paint.setStrokeWidth(5.0);
1986 ctx.paint.setStrokeMiter(0.0);
1987 ctx.paint.setStrokeJoin(DlStrokeJoin::kMiter);
1988 }));
1989 }
@ kMiter
extends to miter limit
@ kBevel
connects outside edges
@ kRound
adds circle
@ kSquare
adds square
@ kStroke
strokes boundary of shapes
@ kFill
fills interior of shapes

References flutter::testing::BoundsTolerance::addBoundsPadding(), flutter::testing::DlSurfaceProvider::backend_type(), flutter::testing::TestParameters::dl_renderer(), flutter::testing::TestParameters::imp_renderer(), flutter::testing::RenderEnvironment::init_ref(), flutter::testing::TestParameters::is_draw_path(), flutter::kBevel, flutter::kFill, flutter::kMiter, flutter::kRound, flutter::kSquare, flutter::kStroke, flutter::testing::RenderEnvironment::MakeN32(), flutter::testing::RenderEnvironment::provider(), quickCompareToReference(), RenderWith(), and flutter::testing::TestParameters::sk_renderer().

Referenced by RenderWithAttributes().

◆ RenderWithTransforms()

static void flutter::testing::CanvasCompareTester::RenderWithTransforms ( const TestParameters testP,
const RenderEnvironment env,
const BoundsTolerance tolerance 
)
inlinestatic

Definition at line 1991 of file dl_rendering_unittests.cc.

1993 {
1994 // If the rendering method does not fill the corners of the original
1995 // bounds, then the estimate under rotation or skewing will be off
1996 // so we scale the padding by about 5% to compensate.
1997 BoundsTolerance skewed_tolerance = tolerance.mulScale(1.05, 1.05);
1998 RenderWith( //
1999 testP, env, tolerance,
2000 CaseParameters(
2001 "Translate 5, 10", //
2002 [=](const SkSetupContext& ctx) { ctx.canvas->translate(5, 10); },
2003 [=](const DlSetupContext& ctx) { ctx.canvas->Translate(5, 10); }));
2004 RenderWith( //
2005 testP, env, tolerance,
2006 CaseParameters(
2007 "Scale +5%", //
2008 [=](const SkSetupContext& ctx) { ctx.canvas->scale(1.05, 1.05); },
2009 [=](const DlSetupContext& ctx) { ctx.canvas->Scale(1.05, 1.05); }));
2010 RenderWith( //
2011 testP, env, skewed_tolerance,
2012 CaseParameters(
2013 "Rotate 5 degrees", //
2014 [=](const SkSetupContext& ctx) { ctx.canvas->rotate(5); },
2015 [=](const DlSetupContext& ctx) { ctx.canvas->Rotate(5); }));
2016 RenderWith( //
2017 testP, env, skewed_tolerance,
2018 CaseParameters(
2019 "Skew 5%", //
2020 [=](const SkSetupContext& ctx) { ctx.canvas->skew(0.05, 0.05); },
2021 [=](const DlSetupContext& ctx) { ctx.canvas->Skew(0.05, 0.05); }));
2022 {
2023 // This rather odd transform can cause slight differences in
2024 // computing in-bounds samples depending on which base rendering
2025 // routine Skia uses. Making sure our matrix values are powers
2026 // of 2 reduces, but does not eliminate, these slight differences
2027 // in calculation when we are comparing rendering with an alpha
2028 // to rendering opaque colors in the group opacity tests, for
2029 // example.
2030 DlScalar tweak = 1.0 / 16.0;
2031 DlMatrix matrix = DlMatrix::MakeRow(
2032 // clang-format off
2033 1.0 + tweak, tweak, 0, 5,
2034 tweak, 1.0 + tweak, 0, 10,
2035 0, 0, 1, 0,
2036 0, 0, 0, 1
2037 // clang-format on
2038 );
2039 RenderWith( //
2040 testP, env, skewed_tolerance,
2041 CaseParameters(
2042 "Transform 2D Affine Matrix",
2043 [=](const SkSetupContext& ctx) {
2044 ctx.canvas->concat(ToSkMatrix(matrix));
2045 },
2046 [=](const DlSetupContext& ctx) {
2047 ctx.canvas->Transform(matrix);
2048 }));
2049 RenderWith( //
2050 testP, env, skewed_tolerance,
2051 CaseParameters(
2052 "Transform 2D Affine inline",
2053 [=](const SkSetupContext& ctx) {
2054 ctx.canvas->concat(SkMatrix::MakeAll(1.0 + tweak, tweak, 5, //
2055 tweak, 1.0 + tweak, 10, //
2056 0, 0, 1));
2057 },
2058 [=](const DlSetupContext& ctx) {
2059 ctx.canvas->Transform2DAffine(1.0 + tweak, tweak, 5, //
2060 tweak, 1.0 + tweak, 10);
2061 }));
2062 }
2063 {
2064 DlMatrix matrix = DlMatrix::MakeRow(1.0f, 0.0f, 0.0f, kRenderCenterX, //
2065 0.0f, 1.0f, 0.0f, kRenderCenterY, //
2066 0.0f, 0.0f, 1.0f, 0.0f, //
2067 0.0f, 0.0f, .001f, 1.0f);
2068 matrix = matrix * DlMatrix::MakeRotationX(DlDegrees(3));
2069 matrix = matrix * DlMatrix::MakeRotationY(DlDegrees(4));
2070 matrix = matrix.Translate({-kRenderCenterX, -kRenderCenterY, 0.0f});
2071 RenderWith( //
2072 testP, env, skewed_tolerance,
2073 CaseParameters(
2074 "Transform Full Perspective Matrix",
2075 [=](const SkSetupContext& ctx) {
2076 ctx.canvas->concat(ToSkM44(matrix));
2077 },
2078 [=](const DlSetupContext& ctx) {
2079 ctx.canvas->Transform(matrix);
2080 }));
2081 RenderWith( //
2082 testP, env, skewed_tolerance,
2083 CaseParameters(
2084 "Transform Full Perspective inline",
2085 [=](const SkSetupContext& ctx) {
2086 ctx.canvas->concat(SkM44(
2087 // These values match what ends up in matrix above
2088 // clang-format off
2089 0.997564, 0.000000, 0.069756, 0.243591,
2090 0.003651, 0.998630, -0.052208, -0.228027,
2091 -0.069661, 0.052336, 0.996197, 1.732491,
2092 -0.000070, 0.000052, 0.000996, 1.001732
2093 // clang-format on
2094 ));
2095 },
2096 [=](const DlSetupContext& ctx) {
2097 ctx.canvas->TransformFullPerspective(
2098 // These values match what ends up in matrix above
2099 // clang-format off
2100 0.997564, 0.000000, 0.069756, 0.243591,
2101 0.003651, 0.998630, -0.052208, -0.228027,
2102 -0.069661, 0.052336, 0.996197, 1.732491,
2103 -0.000070, 0.000052, 0.000996, 1.001732
2104 // clang-format on
2105 );
2106 }));
2107 }
2108 }
impeller::Matrix DlMatrix
impeller::Degrees DlDegrees
SkMatrix ToSkMatrix(const DlMatrix &matrix)
SkM44 ToSkM44(const DlMatrix &matrix)
static Matrix MakeRotationY(Radians r)
Definition matrix.h:208
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 Matrix MakeRotationX(Radians r)
Definition matrix.h:193

References flutter::testing::kRenderCenterX, flutter::testing::kRenderCenterY, impeller::Matrix::MakeRotationX(), impeller::Matrix::MakeRotationY(), impeller::Matrix::MakeRow(), flutter::testing::BoundsTolerance::mulScale(), RenderWith(), flutter::ToSkM44(), flutter::ToSkMatrix(), and impeller::Matrix::Translate().

Referenced by RenderAll().

◆ save_to_png()

static void flutter::testing::CanvasCompareTester::save_to_png ( const RenderResult result,
const std::string &  op_desc,
const std::string &  reason 
)
inlinestatic

Definition at line 2317 of file dl_rendering_unittests.cc.

2319 {
2321 return;
2322 }
2323 if (ImpellerFailureImageDirectory.length() == 0) {
2325 if (ImpellerFailureImageDirectory.length() == 0) {
2327 return;
2328 }
2329 }
2330
2331 std::string filename = ImpellerFailureImageDirectory + "/";
2332 for (const char& ch : op_desc) {
2333 filename += (ch == ':' || ch == ' ') ? '_' : ch;
2334 }
2335 filename = filename + ".png";
2336 result->write(filename);
2337 ImpellerFailureImages.push_back(filename);
2338 FML_LOG(ERROR) << reason << ": " << filename;
2339 }
static std::vector< std::string > ImpellerFailureImages

References FML_LOG, ImpellerFailureImageDirectory, ImpellerFailureImages, SaveImpellerFailureImages, SetupImpellerFailureImageDirectory(), and flutter::testing::RenderResult::write().

Referenced by RenderAll(), and RenderWith().

◆ SetupImpellerFailureImageDirectory()

static void flutter::testing::CanvasCompareTester::SetupImpellerFailureImageDirectory ( )
inlinestatic

Definition at line 2293 of file dl_rendering_unittests.cc.

2293 {
2294 std::string base_dir = "./impeller_failure_images";
2295 if (CheckDir(base_dir) == DirectoryStatus::kFailed) {
2296 return;
2297 }
2298 for (int i = 0; i < 10000; i++) {
2299 std::string sub_dir = std::to_string(i);
2300 while (sub_dir.length() < 4) {
2301 sub_dir = "0" + sub_dir;
2302 }
2303 std::string try_dir = base_dir + "/" + sub_dir;
2304 switch (CheckDir(try_dir)) {
2306 break;
2309 return;
2311 return;
2312 }
2313 }
2314 FML_LOG(ERROR) << "Too many output directories for Impeller failure images";
2315 }
static DirectoryStatus CheckDir(const std::string &dir)

References CheckDir(), FML_LOG, i, ImpellerFailureImageDirectory, kCreated, kExisted, and kFailed.

Referenced by save_to_png().

◆ showBoundsOverflow()

static void flutter::testing::CanvasCompareTester::showBoundsOverflow ( const std::string &  info,
DlIRect bounds,
const BoundsTolerance tolerance,
int  pixLeft,
int  pixTop,
int  pixRight,
int  pixBottom 
)
inlinestatic

Definition at line 2758 of file dl_rendering_unittests.cc.

2764 {
2765 int pad_left = std::max(0, pixLeft - bounds.GetLeft());
2766 int pad_top = std::max(0, pixTop - bounds.GetTop());
2767 int pad_right = std::max(0, bounds.GetRight() - pixRight);
2768 int pad_bottom = std::max(0, bounds.GetBottom() - pixBottom);
2769 DlIRect pix_bounds =
2770 DlIRect::MakeLTRB(pixLeft, pixTop, pixRight, pixBottom);
2771 DlISize pix_size = pix_bounds.GetSize();
2772 int pix_width = pix_size.width;
2773 int pix_height = pix_size.height;
2774 int worst_pad_x = std::max(pad_left, pad_right);
2775 int worst_pad_y = std::max(pad_top, pad_bottom);
2776 if (tolerance->overflows(pix_bounds, worst_pad_x, worst_pad_y)) {
2777 FML_LOG(ERROR) << "Computed bounds for " << info;
2778 FML_LOG(ERROR) << "pix bounds[" //
2779 << pixLeft << ", " << pixTop << " => " //
2780 << pixRight << ", " << pixBottom //
2781 << "]";
2782 FML_LOG(ERROR) << "dl_bounds[" << bounds << "]";
2783 FML_LOG(ERROR) << "Bounds overly conservative by up to " //
2784 << worst_pad_x << ", " << worst_pad_y //
2785 << " (" << (worst_pad_x * 100.0 / pix_width) //
2786 << "%, " << (worst_pad_y * 100.0 / pix_height) << "%)";
2787 int pix_area = pix_size.Area();
2788 int dl_area = bounds.Area();
2789 FML_LOG(ERROR) << "Total overflow area: " << (dl_area - pix_area) //
2790 << " (+" << (dl_area * 100.0 / pix_area - 100.0) //
2791 << "% larger)";
2792 FML_LOG(ERROR);
2793 }
2794 }
impeller::ISize32 DlISize
Type width
Definition size.h:28

References impeller::TRect< T >::Area(), impeller::TSize< T >::Area(), FML_LOG, impeller::TRect< T >::GetBottom(), impeller::TRect< T >::GetLeft(), impeller::TRect< T >::GetRight(), impeller::TRect< T >::GetSize(), impeller::TRect< T >::GetTop(), impeller::TSize< T >::height, impeller::TRect< T >::MakeLTRB(), flutter::testing::BoundsTolerance::overflows(), and impeller::TSize< T >::width.

Referenced by compareToReference().

Member Data Documentation

◆ DefaultTolerance

BoundsTolerance flutter::testing::CanvasCompareTester::DefaultTolerance
static
Initial value:
=
BoundsTolerance().addAbsolutePadding(1, 1)

Definition at line 1141 of file dl_rendering_unittests.cc.

Referenced by flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), and flutter::testing::TEST_F().

◆ ImpellerFailureImageDirectory

std::string flutter::testing::CanvasCompareTester::ImpellerFailureImageDirectory = ""
static

◆ ImpellerFailureImages

std::vector< std::string > flutter::testing::CanvasCompareTester::ImpellerFailureImages
static

◆ ImpellerSupported

bool flutter::testing::CanvasCompareTester::ImpellerSupported = false
static

◆ SaveImpellerFailureImages

bool flutter::testing::CanvasCompareTester::SaveImpellerFailureImages = false
static

◆ TestBackends


The documentation for this class was generated from the following file: