Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
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 1108 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 1130 of file dl_rendering_unittests.cc.

1130 {
1131 auto provider = GetProvider(type);
1132 if (!provider) {
1133 return false;
1134 }
1135 if (provider->supports_impeller()) {
1136 ImpellerSupported = true;
1137 }
1138 TestBackends.push_back(type);
1139 return true;
1140 }
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 2279 of file dl_rendering_unittests.cc.

2279 {
2280 auto ret =
2282 if (ret.is_valid()) {
2284 }
2285 ret =
2287 if (ret.is_valid()) {
2289 }
2290 FML_LOG(ERROR) << "Could not create directory (" << dir
2291 << ") for impeller failure images" << ", ret = " << ret.get()
2292 << ", errno = " << errno;
2294 }
#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 2551 of file dl_rendering_unittests.cc.

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

2618 {
2619 uint32_t untouched = PremultipliedArgb(bg);
2620 int pixels_touched = 0;
2621 int pixels_oob = 0;
2622 DlIRect i_bounds = DlIRect::RoundOut(ref_bounds);
2623 EXPECT_EQ(ref_result->width(), kTestWidth) << info;
2624 EXPECT_EQ(ref_result->height(), kTestWidth) << info;
2625 for (int y = 0; y < kTestHeight; y++) {
2626 const uint32_t* ref_row = ref_result->addr32(0, y);
2627 for (int x = 0; x < kTestWidth; x++) {
2628 if (ref_row[x] != untouched) {
2629 pixels_touched++;
2630 if (!i_bounds.Contains({x, y})) {
2631 pixels_oob++;
2632 }
2633 }
2634 }
2635 }
2636 EXPECT_EQ(pixels_oob, 0) << info;
2637 EXPECT_GT(pixels_touched, 0) << info;
2638 return pixels_oob == 0 && pixels_touched > 0;
2639 }
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 2694 of file dl_rendering_unittests.cc.

2703 {
2704 uint32_t untouched = PremultipliedArgb(bg);
2705 ASSERT_EQ(test_result->width(), width) << info;
2706 ASSERT_EQ(test_result->height(), height) << info;
2707 DlIRect i_bounds =
2708 bounds ? DlIRect::RoundOut(*bounds) : DlIRect::MakeWH(width, height);
2709
2710 int pixels_different = 0;
2711 int pixels_oob = 0;
2712 int min_x = width;
2713 int min_y = height;
2714 int max_x = 0;
2715 int max_y = 0;
2716 for (int y = 0; y < height; y++) {
2717 const uint32_t* ref_row = ref_result->addr32(0, y);
2718 const uint32_t* test_row = test_result->addr32(0, y);
2719 for (int x = 0; x < width; x++) {
2720 if (bounds && test_row[x] != untouched) {
2721 if (min_x > x) {
2722 min_x = x;
2723 }
2724 if (min_y > y) {
2725 min_y = y;
2726 }
2727 if (max_x <= x) {
2728 max_x = x + 1;
2729 }
2730 if (max_y <= y) {
2731 max_y = y + 1;
2732 }
2733 if (!i_bounds.Contains({x, y})) {
2734 pixels_oob++;
2735 }
2736 }
2737 bool match = fuzzyCompares ? fuzzyCompare(test_row[x], ref_row[x], 1)
2738 : test_row[x] == ref_row[x];
2739 if (!match) {
2740 if (printMismatches && pixels_different < 5) {
2741 FML_LOG(ERROR) << "pix[" << x << ", " << y
2742 << "] mismatch: " << std::hex << test_row[x]
2743 << "(test) != (ref)" << ref_row[x] << std::dec;
2744 }
2745 pixels_different++;
2746 }
2747 }
2748 }
2749 if (pixels_oob > 0) {
2750 FML_LOG(ERROR) << "pix bounds["
2751 << DlIRect::MakeLTRB(min_x, min_y, max_x, max_y) //
2752 << "]";
2753 FML_LOG(ERROR) << "dl_bounds[" << bounds << "]";
2754 } else if (bounds) {
2755 showBoundsOverflow(info, i_bounds, tolerance, min_x, min_y, max_x, max_y);
2756 }
2757 ASSERT_EQ(pixels_oob, 0) << info;
2758 ASSERT_EQ(pixels_different, 0) << info;
2759 }
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 2641 of file dl_rendering_unittests.cc.

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

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 2529 of file dl_rendering_unittests.cc.

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

References i.

Referenced by compareToReference().

◆ GetProvider()

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

Definition at line 1116 of file dl_rendering_unittests.cc.

1116 {
1117 auto provider = DlSurfaceProvider::Create(type);
1118 if (provider == nullptr) {
1119 FML_LOG(ERROR) << "provider " << DlSurfaceProvider::BackendName(type)
1120 << " not supported (ignoring)";
1121 return nullptr;
1122 }
1123 provider->InitializeSurface(kTestWidth, kTestHeight,
1124 PixelFormat::kN32PremulPixelFormat);
1125 return provider;
1126 }
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 2540 of file dl_rendering_unittests.cc.

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

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 2799 of file dl_rendering_unittests.cc.

2800 {
2801 SkFont font = CreateTestFontOfSize(font_height);
2802 sk_sp<SkTypeface> face = font.refTypeface();
2803 FML_CHECK(face);
2804 FML_CHECK(face->countGlyphs() > 0) << "No glyphs in font";
2805 return SkTextBlob::MakeFromText(string.c_str(), string.size(), font,
2806 SkTextEncoding::kUTF8);
2807 }
#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 2664 of file dl_rendering_unittests.cc.

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

1145 {
1146 for (auto& back_end : TestBackends) {
1147 auto provider = GetProvider(back_end);
1148 RenderEnvironment env = RenderEnvironment::MakeN32(provider.get());
1149 env.init_ref(kEmptySkSetup, params.sk_renderer(), //
1150 kEmptyDlSetup, params.dl_renderer(), params.imp_renderer());
1151 quickCompareToReference(env, "default");
1152 if (env.supports_impeller()) {
1153 auto impeller_result = env.ref_impeller_result();
1154 if (!checkPixels(impeller_result, impeller_result->render_bounds(),
1155 "Impeller reference")) {
1156 std::string test_name =
1157 ::testing::UnitTest::GetInstance()->current_test_info()->name();
1158 save_to_png(impeller_result, test_name + " (Impeller reference)",
1159 "base rendering was blank or out of bounds");
1160 }
1161 } else {
1162 static OncePerBackendWarning warnings("No Impeller output tests");
1163 warnings.warn(env.backend_name());
1164 }
1165
1166 RenderWithTransforms(params, env, tolerance);
1167 RenderWithClips(params, env, tolerance);
1168 RenderWithSaveRestore(params, env, tolerance);
1169 // Only test attributes if the canvas version uses the paint object
1170 if (params.uses_paint()) {
1171 RenderWithAttributes(params, env, tolerance);
1172 }
1173 }
1174 }
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 2344 of file dl_rendering_unittests.cc.

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

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

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

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

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

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

2322 {
2324 return;
2325 }
2326 if (ImpellerFailureImageDirectory.length() == 0) {
2328 if (ImpellerFailureImageDirectory.length() == 0) {
2330 return;
2331 }
2332 }
2333
2334 std::string filename = ImpellerFailureImageDirectory + "/";
2335 for (const char& ch : op_desc) {
2336 filename += (ch == ':' || ch == ' ') ? '_' : ch;
2337 }
2338 filename = filename + ".png";
2339 result->write(filename);
2340 ImpellerFailureImages.push_back(filename);
2341 FML_LOG(ERROR) << reason << ": " << filename;
2342 }
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 2296 of file dl_rendering_unittests.cc.

2296 {
2297 std::string base_dir = "./impeller_failure_images";
2298 if (CheckDir(base_dir) == DirectoryStatus::kFailed) {
2299 return;
2300 }
2301 for (int i = 0; i < 10000; i++) {
2302 std::string sub_dir = std::to_string(i);
2303 while (sub_dir.length() < 4) {
2304 sub_dir = "0" + sub_dir;
2305 }
2306 std::string try_dir = base_dir + "/" + sub_dir;
2307 switch (CheckDir(try_dir)) {
2309 break;
2312 return;
2314 return;
2315 }
2316 }
2317 FML_LOG(ERROR) << "Too many output directories for Impeller failure images";
2318 }
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 2761 of file dl_rendering_unittests.cc.

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