From 0f642ecb5c64e11a4aab8b8cedd821f821db5495 Mon Sep 17 00:00:00 2001 From: Jelle Raaijmakers Date: Wed, 16 Jul 2025 09:04:19 +0200 Subject: [PATCH] LibGfx: Replace Bitmap::visually_equals() with ::diff() This produces more granural information on the actual pixel errors present between two bitmaps. It now also asserts that both bitmaps are the same size, since we should never compare two differently sized bitmaps anyway. --- Libraries/LibGfx/Bitmap.cpp | 38 ++++++++++++++++++++++++++++------ Libraries/LibGfx/Bitmap.h | 23 +++++++++++++++++++- Tests/LibWeb/test-web/main.cpp | 2 +- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/Libraries/LibGfx/Bitmap.cpp b/Libraries/LibGfx/Bitmap.cpp index f2f9f5e1185..0247b0c009f 100644 --- a/Libraries/LibGfx/Bitmap.cpp +++ b/Libraries/LibGfx/Bitmap.cpp @@ -228,21 +228,47 @@ ErrorOr Bitmap::allocate_backing_store(BitmapFormat format, IntSiz return BackingStore { data, pitch, data_size_in_bytes }; } -bool Bitmap::visually_equals(Bitmap const& other) const +Bitmap::DiffResult Bitmap::diff(Bitmap const& other) const { auto own_width = width(); auto own_height = height(); - if (other.width() != own_width || other.height() != own_height) - return false; + VERIFY(own_width == other.width() && own_height == other.height()); + DiffResult result; for (auto y = 0; y < own_height; ++y) { for (auto x = 0; x < own_width; ++x) { - if (get_pixel(x, y) != other.get_pixel(x, y)) - return false; + auto own_pixel = get_pixel(x, y); + auto other_pixel = other.get_pixel(x, y); + if (own_pixel == other_pixel) + continue; + + ++result.pixel_error_count; + + u8 red_error = abs(static_cast(own_pixel.red()) - other_pixel.red()); + u8 green_error = abs(static_cast(own_pixel.green()) - other_pixel.green()); + u8 blue_error = abs(static_cast(own_pixel.blue()) - other_pixel.blue()); + u8 alpha_error = abs(static_cast(own_pixel.alpha()) - other_pixel.alpha()); + + result.total_red_error += red_error; + result.total_green_error += green_error; + result.total_blue_error += blue_error; + result.total_alpha_error += alpha_error; + + result.maximum_red_error = max(result.maximum_red_error, red_error); + result.maximum_green_error = max(result.maximum_green_error, green_error); + result.maximum_blue_error = max(result.maximum_blue_error, blue_error); + result.maximum_alpha_error = max(result.maximum_alpha_error, alpha_error); } } - return true; + result.identical = result.pixel_error_count == 0; + result.total_error = result.total_red_error + result.total_green_error + result.total_blue_error + result.total_alpha_error; + + u8 maximum_red_green_error = max(result.maximum_red_error, result.maximum_green_error); + u8 maximum_blue_alpha_error = max(result.maximum_blue_error, result.maximum_alpha_error); + result.maximum_error = max(maximum_red_green_error, maximum_blue_alpha_error); + + return result; } void Bitmap::set_alpha_type_destructive(AlphaType alpha_type) diff --git a/Libraries/LibGfx/Bitmap.h b/Libraries/LibGfx/Bitmap.h index dd193ef9e4f..9cd4b79cad0 100644 --- a/Libraries/LibGfx/Bitmap.h +++ b/Libraries/LibGfx/Bitmap.h @@ -137,7 +137,28 @@ public: [[nodiscard]] Core::AnonymousBuffer& anonymous_buffer() { return m_buffer; } [[nodiscard]] Core::AnonymousBuffer const& anonymous_buffer() const { return m_buffer; } - [[nodiscard]] bool visually_equals(Bitmap const&) const; + struct DiffResult { + bool identical { false }; + + // Cumulative channel differences. + u64 total_red_error { 0 }; + u64 total_green_error { 0 }; + u64 total_blue_error { 0 }; + u64 total_alpha_error { 0 }; + u64 total_error { 0 }; + + // Maximum channel differences. + u8 maximum_red_error { 0 }; + u8 maximum_green_error { 0 }; + u8 maximum_blue_error { 0 }; + u8 maximum_alpha_error { 0 }; + u8 maximum_error { 0 }; + + // Number of pixels with errors. + u64 pixel_error_count { 0 }; + }; + + [[nodiscard]] DiffResult diff(Bitmap const&) const; [[nodiscard]] AlphaType alpha_type() const { return m_alpha_type; } void set_alpha_type_destructive(AlphaType); diff --git a/Tests/LibWeb/test-web/main.cpp b/Tests/LibWeb/test-web/main.cpp index dea68dd1866..bb501bc7969 100644 --- a/Tests/LibWeb/test-web/main.cpp +++ b/Tests/LibWeb/test-web/main.cpp @@ -376,7 +376,7 @@ static void run_ref_test(TestWebView& view, Test& test, URL::URL const& url, int auto handle_completed_test = [&test, url]() -> ErrorOr { VERIFY(test.ref_test_expectation_type.has_value()); auto should_match = test.ref_test_expectation_type == RefTestExpectationType::Match; - auto screenshot_matches = test.actual_screenshot->visually_equals(*test.expectation_screenshot); + auto screenshot_matches = test.actual_screenshot->diff(*test.expectation_screenshot).identical; if (should_match == screenshot_matches) return TestResult::Pass;