diff --git a/Libraries/LibWeb/HTML/Navigable.h b/Libraries/LibWeb/HTML/Navigable.h
index 83e2340975..db780500e3 100644
--- a/Libraries/LibWeb/HTML/Navigable.h
+++ b/Libraries/LibWeb/HTML/Navigable.h
@@ -172,6 +172,8 @@ public:
void set_viewport_size(CSSPixelSize);
void perform_scroll_of_viewport_scrolling_box(CSSPixelPoint position);
+ Painting::BackingStoreManager& backing_store_manager() { return *m_backing_store_manager; }
+
// https://html.spec.whatwg.org/multipage/webappapis.html#rendering-opportunity
[[nodiscard]] bool has_a_rendering_opportunity() const;
diff --git a/Libraries/LibWeb/Internals/Internals.cpp b/Libraries/LibWeb/Internals/Internals.cpp
index 4f09080421..0d11b01635 100644
--- a/Libraries/LibWeb/Internals/Internals.cpp
+++ b/Libraries/LibWeb/Internals/Internals.cpp
@@ -437,6 +437,11 @@ void Internals::set_browser_zoom(double factor)
page().client().page_did_set_browser_zoom(factor);
}
+void Internals::set_device_pixel_ratio(double ratio)
+{
+ page().client().page_did_set_device_pixel_ratio_for_testing(ratio);
+}
+
bool Internals::headless()
{
return page().client().is_headless();
diff --git a/Libraries/LibWeb/Internals/Internals.h b/Libraries/LibWeb/Internals/Internals.h
index 69824a6604..d83b04d346 100644
--- a/Libraries/LibWeb/Internals/Internals.h
+++ b/Libraries/LibWeb/Internals/Internals.h
@@ -69,6 +69,7 @@ public:
static void set_echo_server_port(u16 port);
void set_browser_zoom(double factor);
+ void set_device_pixel_ratio(double ratio);
bool headless();
diff --git a/Libraries/LibWeb/Internals/Internals.idl b/Libraries/LibWeb/Internals/Internals.idl
index e164be6ace..344ef87248 100644
--- a/Libraries/LibWeb/Internals/Internals.idl
+++ b/Libraries/LibWeb/Internals/Internals.idl
@@ -58,6 +58,7 @@ interface Internals {
unsigned short getEchoServerPort();
undefined setBrowserZoom(double factor);
+ undefined setDevicePixelRatio(double ratio);
readonly attribute boolean headless;
diff --git a/Libraries/LibWeb/Page/Page.h b/Libraries/LibWeb/Page/Page.h
index c1df05e7c2..00114d71b1 100644
--- a/Libraries/LibWeb/Page/Page.h
+++ b/Libraries/LibWeb/Page/Page.h
@@ -417,6 +417,7 @@ public:
virtual void page_did_receive_test_variant_metadata(JsonValue) { }
virtual void page_did_set_browser_zoom([[maybe_unused]] double factor) { }
+ virtual void page_did_set_device_pixel_ratio_for_testing([[maybe_unused]] double ratio) { }
virtual void page_did_change_theme_color(Gfx::Color) { }
diff --git a/Services/WebContent/PageClient.cpp b/Services/WebContent/PageClient.cpp
index 26d23f9a08..3f8ccf433d 100644
--- a/Services/WebContent/PageClient.cpp
+++ b/Services/WebContent/PageClient.cpp
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -207,6 +208,23 @@ void PageClient::set_viewport_size(Web::DevicePixelSize const& size)
page().top_level_traversable()->set_viewport_size(page().device_to_css_size(size));
}
+void PageClient::set_device_pixel_ratio(double device_pixel_ratio)
+{
+ if (m_device_pixel_ratio == device_pixel_ratio)
+ return;
+
+ m_device_pixel_ratio = device_pixel_ratio;
+
+ auto traversable = page().top_level_traversable();
+ traversable->backing_store_manager()
+ .resize_backing_stores_if_needed(Web::Painting::BackingStoreManager::WindowResizingInProgress::No);
+
+ if (auto document = traversable->active_document()) {
+ document->set_needs_media_query_evaluation();
+ document->set_needs_display(Web::InvalidateDisplayList::Yes);
+ }
+}
+
void PageClient::set_maximum_frames_per_second(u64 maximum_frames_per_second)
{
m_maximum_frames_per_second = maximum_frames_per_second;
@@ -372,6 +390,11 @@ void PageClient::page_did_set_browser_zoom(double factor)
}));
}
+void PageClient::page_did_set_device_pixel_ratio_for_testing(double ratio)
+{
+ set_device_pixel_ratio(ratio);
+}
+
void PageClient::page_did_request_context_menu(Web::CSSPixelPoint content_position)
{
client().async_did_request_context_menu(m_id, page().css_to_device_point(content_position).to_type());
diff --git a/Services/WebContent/PageClient.h b/Services/WebContent/PageClient.h
index 5fb158a7f8..8d4d5b4baa 100644
--- a/Services/WebContent/PageClient.h
+++ b/Services/WebContent/PageClient.h
@@ -58,7 +58,7 @@ public:
m_all_screen_rects = rects;
m_main_screen_index = main_screen_index;
}
- void set_device_pixel_ratio(double device_pixel_ratio) { m_device_pixel_ratio = device_pixel_ratio; }
+ void set_device_pixel_ratio(double device_pixel_ratio);
void set_zoom_level(double zoom_level) { m_zoom_level = zoom_level; }
void set_maximum_frames_per_second(u64 maximum_frames_per_second);
void set_preferred_color_scheme(Web::CSS::PreferredColorScheme);
@@ -182,6 +182,7 @@ private:
virtual void page_did_receive_reference_test_metadata(JsonValue) override;
virtual void page_did_receive_test_variant_metadata(JsonValue) override;
virtual void page_did_set_browser_zoom(double factor) override;
+ virtual void page_did_set_device_pixel_ratio_for_testing(double ratio) override;
virtual void page_did_change_theme_color(Gfx::Color color) override;
virtual void page_did_insert_clipboard_entry(Web::Clipboard::SystemClipboardRepresentation const&, StringView presentation_style) override;
virtual void page_did_request_clipboard_entries(u64 request_id) override;
diff --git a/Tests/LibWeb/Text/expected/device-pixel-ratio-media-query.txt b/Tests/LibWeb/Text/expected/device-pixel-ratio-media-query.txt
new file mode 100644
index 0000000000..6bd45c7259
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/device-pixel-ratio-media-query.txt
@@ -0,0 +1,5 @@
+Initial matches (at 1x): false
+Change event 1: matches = true
+PASS: Media query matched after DPI changed to 2x
+Change event 2: matches = false
+PASS: Media query unmatched after DPI changed back to 1x
diff --git a/Tests/LibWeb/Text/input/device-pixel-ratio-media-query.html b/Tests/LibWeb/Text/input/device-pixel-ratio-media-query.html
new file mode 100644
index 0000000000..70549c2953
--- /dev/null
+++ b/Tests/LibWeb/Text/input/device-pixel-ratio-media-query.html
@@ -0,0 +1,36 @@
+
+
+