LibWeb+WebContent: Instantly update DPI for painting and media queries
If our UI informed the page of a DPI change, we would store the new device pixel ratio and leave it at that. It would take a layout/style update (e.g. by clicking the page) to actually render the page using the new DPI. This is very visible on macOS when moving the Ladybird window from a 1x resolution monitor to a HiDPI 2x monitor. We now instantly update the backing stores and mark media queries for reevaluation. Moving the Ladybird window on macOS now immediately updates the page when dragging it to a HiDPI monitor.
This commit is contained in:
parent
12ba454a5b
commit
c56c933014
9 changed files with 76 additions and 1 deletions
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ interface Internals {
|
|||
unsigned short getEchoServerPort();
|
||||
|
||||
undefined setBrowserZoom(double factor);
|
||||
undefined setDevicePixelRatio(double ratio);
|
||||
|
||||
readonly attribute boolean headless;
|
||||
|
||||
|
|
|
|||
|
|
@ -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) { }
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <LibWeb/HTML/HTMLLinkElement.h>
|
||||
#include <LibWeb/HTML/Scripting/ClassicScript.h>
|
||||
#include <LibWeb/HTML/TraversableNavigable.h>
|
||||
#include <LibWeb/InvalidateDisplayList.h>
|
||||
#include <LibWeb/Layout/Viewport.h>
|
||||
#include <LibWeb/Painting/PaintableBox.h>
|
||||
#include <LibWebView/SiteIsolation.h>
|
||||
|
|
@ -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<int>());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
36
Tests/LibWeb/Text/input/device-pixel-ratio-media-query.html
Normal file
36
Tests/LibWeb/Text/input/device-pixel-ratio-media-query.html
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="include.js"></script>
|
||||
<script>
|
||||
asyncTest(done => {
|
||||
const mql = window.matchMedia("(resolution: 2dppx)");
|
||||
println(`Initial matches (at 1x): ${mql.matches}`);
|
||||
|
||||
let changeCount = 0;
|
||||
|
||||
mql.addEventListener("change", (event) => {
|
||||
changeCount++;
|
||||
println(`Change event ${changeCount}: matches = ${event.matches}`);
|
||||
|
||||
if (changeCount === 1) {
|
||||
// First change: 1x -> 2x, should now match.
|
||||
if (event.matches) {
|
||||
println("PASS: Media query matched after DPI changed to 2x");
|
||||
} else {
|
||||
println("FAIL: Media query should match at 2x DPI");
|
||||
}
|
||||
internals.setDevicePixelRatio(1);
|
||||
} else if (changeCount === 2) {
|
||||
// Second change: 2x -> 1x, should no longer match.
|
||||
if (!event.matches) {
|
||||
println("PASS: Media query unmatched after DPI changed back to 1x");
|
||||
} else {
|
||||
println("FAIL: Media query should not match at 1x DPI");
|
||||
}
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
// Change to 2x DPI - this should trigger the first change event.
|
||||
internals.setDevicePixelRatio(2);
|
||||
});
|
||||
</script>
|
||||
Loading…
Reference in a new issue