From 8dfeb67f8ceee2491615e11895f87e5172a7eae4 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 25 Nov 2022 17:07:19 +0000 Subject: LibWeb+WebContent+headless-browser: Make Page aware of the display scale For now, we just report it as "1" everywhere. Replaced `screen_rect()` with `web_exposed_screen_area()` from the spec. --- Userland/Libraries/LibWeb/CSS/Screen.cpp | 8 ++- Userland/Libraries/LibWeb/HTML/Window.cpp | 4 +- Userland/Libraries/LibWeb/Page/Page.cpp | 62 +++++++++++++++++++++- Userland/Libraries/LibWeb/Page/Page.h | 15 ++++-- .../Services/WebContent/ConnectionFromClient.cpp | 6 +-- Userland/Services/WebContent/PageHost.cpp | 14 ++--- Userland/Services/WebContent/PageHost.h | 17 +++--- .../Services/WebContent/WebDriverConnection.cpp | 4 +- Userland/Utilities/headless-browser.cpp | 22 +++++--- 9 files changed, 118 insertions(+), 34 deletions(-) (limited to 'Userland') diff --git a/Userland/Libraries/LibWeb/CSS/Screen.cpp b/Userland/Libraries/LibWeb/CSS/Screen.cpp index 35fee91694..b066b744c7 100644 --- a/Userland/Libraries/LibWeb/CSS/Screen.cpp +++ b/Userland/Libraries/LibWeb/CSS/Screen.cpp @@ -33,7 +33,13 @@ void Screen::visit_edges(Cell::Visitor& visitor) Gfx::IntRect Screen::screen_rect() const { - return window().page()->screen_rect(); + auto screen_rect_in_css_pixels = window().page()->web_exposed_screen_area(); + return { + screen_rect_in_css_pixels.x().value(), + screen_rect_in_css_pixels.y().value(), + screen_rect_in_css_pixels.width().value(), + screen_rect_in_css_pixels.height().value() + }; } } diff --git a/Userland/Libraries/LibWeb/HTML/Window.cpp b/Userland/Libraries/LibWeb/HTML/Window.cpp index 2314e854cd..f4d39a476a 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.cpp +++ b/Userland/Libraries/LibWeb/HTML/Window.cpp @@ -673,12 +673,12 @@ Optional Window::query_media_feature(CSS::MediaFeatureID // FIXME: device-aspect-ratio case CSS::MediaFeatureID::DeviceHeight: if (auto* page = this->page()) { - return CSS::MediaFeatureValue(CSS::Length::make_px(page->screen_rect().height())); + return CSS::MediaFeatureValue(CSS::Length::make_px(page->web_exposed_screen_area().height().value())); } return CSS::MediaFeatureValue(0); case CSS::MediaFeatureID::DeviceWidth: if (auto* page = this->page()) { - return CSS::MediaFeatureValue(CSS::Length::make_px(page->screen_rect().width())); + return CSS::MediaFeatureValue(CSS::Length::make_px(page->web_exposed_screen_area().width().value())); } return CSS::MediaFeatureValue(0); case CSS::MediaFeatureID::DisplayMode: diff --git a/Userland/Libraries/LibWeb/Page/Page.cpp b/Userland/Libraries/LibWeb/Page/Page.cpp index 0377bb58ee..b38956699b 100644 --- a/Userland/Libraries/LibWeb/Page/Page.cpp +++ b/Userland/Libraries/LibWeb/Page/Page.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Andreas Kling + * Copyright (c) 2022, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -54,9 +55,17 @@ Gfx::Palette Page::palette() const return m_client.palette(); } -Gfx::IntRect Page::screen_rect() const +// https://w3c.github.io/csswg-drafts/cssom-view-1/#web-exposed-screen-area +CSSPixelRect Page::web_exposed_screen_area() const { - return m_client.screen_rect(); + auto device_pixel_rect = m_client.screen_rect(); + auto scale = client().device_pixels_per_css_pixel(); + return { + device_pixel_rect.x().value() / scale, + device_pixel_rect.y().value() / scale, + device_pixel_rect.width().value() / scale, + device_pixel_rect.height().value() / scale + }; } CSS::PreferredColorScheme Page::preferred_color_scheme() const @@ -64,6 +73,55 @@ CSS::PreferredColorScheme Page::preferred_color_scheme() const return m_client.preferred_color_scheme(); } +CSSPixelPoint Page::device_to_css_point(DevicePixelPoint point) const +{ + return { + point.x().value() / client().device_pixels_per_css_pixel(), + point.y().value() / client().device_pixels_per_css_pixel(), + }; +} + +DevicePixelPoint Page::css_to_device_point(CSSPixelPoint point) const +{ + return { + point.x().value() * client().device_pixels_per_css_pixel(), + point.y().value() * client().device_pixels_per_css_pixel(), + }; +} + +CSSPixelRect Page::device_to_css_rect(DevicePixelRect rect) const +{ + auto scale = client().device_pixels_per_css_pixel(); + return { + rect.x().value() / scale, + rect.y().value() / scale, + rect.width().value() / scale, + rect.height().value() / scale + }; +} + +DevicePixelRect Page::enclosing_device_rect(CSSPixelRect rect) const +{ + auto scale = client().device_pixels_per_css_pixel(); + return { + floorf(rect.x().value() * scale), + floorf(rect.y().value() * scale), + ceilf(rect.width().value() * scale), + ceilf(rect.height().value() * scale) + }; +} + +DevicePixelRect Page::rounded_device_rect(CSSPixelRect rect) const +{ + auto scale = client().device_pixels_per_css_pixel(); + return { + roundf(rect.x().value() * scale), + roundf(rect.y().value() * scale), + roundf(rect.width().value() * scale), + roundf(rect.height().value() * scale) + }; +} + bool Page::handle_mousewheel(Gfx::IntPoint position, unsigned button, unsigned buttons, unsigned modifiers, int wheel_delta_x, int wheel_delta_y) { return top_level_browsing_context().event_handler().handle_mousewheel(position, button, buttons, modifiers, wheel_delta_x, wheel_delta_y); diff --git a/Userland/Libraries/LibWeb/Page/Page.h b/Userland/Libraries/LibWeb/Page/Page.h index 8e8418c1d0..dde45bf915 100644 --- a/Userland/Libraries/LibWeb/Page/Page.h +++ b/Userland/Libraries/LibWeb/Page/Page.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2020-2021, Andreas Kling * Copyright (c) 2021-2022, Linus Groh + * Copyright (c) 2022, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -25,6 +26,7 @@ #include #include #include +#include namespace Web { @@ -54,6 +56,12 @@ public: void load_html(StringView, const AK::URL&); + CSSPixelPoint device_to_css_point(DevicePixelPoint) const; + DevicePixelPoint css_to_device_point(CSSPixelPoint) const; + CSSPixelRect device_to_css_rect(DevicePixelRect) const; + DevicePixelRect enclosing_device_rect(CSSPixelRect) const; + DevicePixelRect rounded_device_rect(CSSPixelRect) const; + bool handle_mouseup(Gfx::IntPoint, unsigned button, unsigned buttons, unsigned modifiers); bool handle_mousedown(Gfx::IntPoint, unsigned button, unsigned buttons, unsigned modifiers); bool handle_mousemove(Gfx::IntPoint, unsigned buttons, unsigned modifiers); @@ -64,7 +72,7 @@ public: bool handle_keyup(KeyCode, unsigned modifiers, u32 code_point); Gfx::Palette palette() const; - Gfx::IntRect screen_rect() const; + CSSPixelRect web_exposed_screen_area() const; CSS::PreferredColorScheme preferred_color_scheme() const; bool is_same_origin_policy_enabled() const { return m_same_origin_policy_enabled; } @@ -139,9 +147,10 @@ public: virtual Page const& page() const = 0; virtual bool is_connection_open() const = 0; virtual Gfx::Palette palette() const = 0; - virtual Gfx::IntRect screen_rect() const = 0; + virtual DevicePixelRect screen_rect() const = 0; + virtual float device_pixels_per_css_pixel() const = 0; virtual CSS::PreferredColorScheme preferred_color_scheme() const = 0; - virtual void paint(Gfx::IntRect const&, Gfx::Bitmap&) = 0; + virtual void paint(DevicePixelRect const&, Gfx::Bitmap&) = 0; virtual void page_did_change_title(DeprecatedString const&) { } virtual void page_did_request_navigate_back() { } virtual void page_did_request_navigate_forward() { } diff --git a/Userland/Services/WebContent/ConnectionFromClient.cpp b/Userland/Services/WebContent/ConnectionFromClient.cpp index 5774c46f94..bc56decb02 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.cpp +++ b/Userland/Services/WebContent/ConnectionFromClient.cpp @@ -149,7 +149,7 @@ void ConnectionFromClient::paint(Gfx::IntRect const& content_rect, i32 backing_s void ConnectionFromClient::flush_pending_paint_requests() { for (auto& pending_paint : m_pending_paint_requests) { - m_page_host->paint(pending_paint.content_rect, *pending_paint.bitmap); + m_page_host->paint(pending_paint.content_rect.to_type(), *pending_paint.bitmap); async_did_paint(pending_paint.content_rect, pending_paint.bitmap_id); } m_pending_paint_requests.clear(); @@ -461,9 +461,9 @@ Messages::WebContentServer::TakeDocumentScreenshotResponse ConnectionFromClient: return { {} }; auto const& content_size = m_page_host->content_size(); - Gfx::IntRect rect { { 0, 0 }, content_size }; + Web::DevicePixelRect rect { { 0, 0 }, content_size }; - auto bitmap = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, rect.size()).release_value_but_fixme_should_propagate_errors(); + auto bitmap = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, rect.size().to_type()).release_value_but_fixme_should_propagate_errors(); m_page_host->paint(rect, *bitmap); return { bitmap->to_shareable_bitmap() }; diff --git a/Userland/Services/WebContent/PageHost.cpp b/Userland/Services/WebContent/PageHost.cpp index 4f5a83c303..7275b7d111 100644 --- a/Userland/Services/WebContent/PageHost.cpp +++ b/Userland/Services/WebContent/PageHost.cpp @@ -104,10 +104,10 @@ Web::Layout::InitialContainingBlock* PageHost::layout_root() return document->layout_node(); } -void PageHost::paint(Gfx::IntRect const& content_rect, Gfx::Bitmap& target) +void PageHost::paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap& target) { Gfx::Painter painter(target); - Gfx::IntRect bitmap_rect { {}, content_rect.size() }; + Gfx::IntRect bitmap_rect { {}, content_rect.size().to_type() }; if (auto* document = page().top_level_browsing_context().active_document()) document->update_layout(); @@ -118,9 +118,9 @@ void PageHost::paint(Gfx::IntRect const& content_rect, Gfx::Bitmap& target) return; } - Web::PaintContext context(painter, palette(), content_rect.top_left()); + Web::PaintContext context(painter, palette(), content_rect.top_left().to_type()); context.set_should_show_line_box_borders(m_should_show_line_box_borders); - context.set_viewport_rect(content_rect); + context.set_viewport_rect(content_rect.to_type()); context.set_has_focus(m_has_focus); layout_root->paint_all_phases(context); } @@ -152,10 +152,10 @@ void PageHost::page_did_layout() auto* layout_root = this->layout_root(); VERIFY(layout_root); if (layout_root->paint_box()->has_overflow()) - m_content_size = enclosing_int_rect(layout_root->paint_box()->scrollable_overflow_rect().value()).size(); + m_content_size = page().enclosing_device_rect(layout_root->paint_box()->scrollable_overflow_rect().value().to_type()).size(); else - m_content_size = enclosing_int_rect(layout_root->paint_box()->absolute_rect()).size(); - m_client.async_did_layout(m_content_size); + m_content_size = page().enclosing_device_rect(layout_root->paint_box()->absolute_rect().to_type()).size(); + m_client.async_did_layout(m_content_size.to_type()); } void PageHost::page_did_change_title(DeprecatedString const& title) diff --git a/Userland/Services/WebContent/PageHost.h b/Userland/Services/WebContent/PageHost.h index ad494c05f8..94c8749b4a 100644 --- a/Userland/Services/WebContent/PageHost.h +++ b/Userland/Services/WebContent/PageHost.h @@ -9,6 +9,7 @@ #include #include +#include #include namespace WebContent { @@ -26,11 +27,12 @@ public: virtual Web::Page& page() override { return *m_page; } virtual Web::Page const& page() const override { return *m_page; } - virtual void paint(Gfx::IntRect const& content_rect, Gfx::Bitmap&) override; + virtual void paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap&) override; void set_palette_impl(Gfx::PaletteImpl const&); void set_viewport_rect(Gfx::IntRect const&); - void set_screen_rects(Vector const& rects, size_t main_screen_index) { m_screen_rect = rects[main_screen_index]; }; + void set_screen_rects(Vector const& rects, size_t main_screen_index) { m_screen_rect = rects[main_screen_index].to_type(); } + void set_screen_display_scale(float device_pixels_per_css_pixel) { m_screen_display_scale = device_pixels_per_css_pixel; } void set_preferred_color_scheme(Web::CSS::PreferredColorScheme); void set_should_show_line_box_borders(bool b) { m_should_show_line_box_borders = b; } void set_has_focus(bool); @@ -38,7 +40,7 @@ public: void set_window_position(Gfx::IntPoint); void set_window_size(Gfx::IntSize); - Gfx::IntSize content_size() const { return m_content_size; } + Web::DevicePixelSize content_size() const { return m_content_size; } ErrorOr connect_to_webdriver(DeprecatedString const& webdriver_ipc_path); @@ -50,7 +52,8 @@ private: // ^PageClient virtual bool is_connection_open() const override; virtual Gfx::Palette palette() const override; - virtual Gfx::IntRect screen_rect() const override { return m_screen_rect; } + virtual Web::DevicePixelRect screen_rect() const override { return m_screen_rect; } + virtual float device_pixels_per_css_pixel() const override { return m_screen_display_scale; } virtual Web::CSS::PreferredColorScheme preferred_color_scheme() const override { return m_preferred_color_scheme; } virtual void page_did_invalidate(Gfx::IntRect const&) override; virtual void page_did_change_selection() override; @@ -104,8 +107,10 @@ private: ConnectionFromClient& m_client; NonnullOwnPtr m_page; RefPtr m_palette_impl; - Gfx::IntRect m_screen_rect; - Gfx::IntSize m_content_size; + Web::DevicePixelRect m_screen_rect; + Web::DevicePixelSize m_content_size; + // FIXME: Actually set this based on the device's pixel ratio. + float m_screen_display_scale { 1.0f }; bool m_should_show_line_box_borders { false }; bool m_has_focus { false }; diff --git a/Userland/Services/WebContent/WebDriverConnection.cpp b/Userland/Services/WebContent/WebDriverConnection.cpp index 94bc6990d7..7244fea996 100644 --- a/Userland/Services/WebContent/WebDriverConnection.cpp +++ b/Userland/Services/WebContent/WebDriverConnection.cpp @@ -1521,7 +1521,7 @@ Messages::WebDriverClient::TakeScreenshotResponse WebDriverConnection::take_scre auto root_rect = calculate_absolute_rect_of_element(m_page_client.page(), *document->document_element()); auto encoded_string = TRY(Web::WebDriver::capture_element_screenshot( - [&](auto const& rect, auto& bitmap) { m_page_client.paint(rect, bitmap); }, + [&](auto const& rect, auto& bitmap) { m_page_client.paint(rect.template to_type(), bitmap); }, m_page_client.page(), *document->document_element(), root_rect)); @@ -1554,7 +1554,7 @@ Messages::WebDriverClient::TakeElementScreenshotResponse WebDriverConnection::ta auto element_rect = calculate_absolute_rect_of_element(m_page_client.page(), *element); auto encoded_string = TRY(Web::WebDriver::capture_element_screenshot( - [&](auto const& rect, auto& bitmap) { m_page_client.paint(rect, bitmap); }, + [&](auto const& rect, auto& bitmap) { m_page_client.paint(rect.template to_type(), bitmap); }, m_page_client.page(), *element, element_rect)); diff --git a/Userland/Utilities/headless-browser.cpp b/Userland/Utilities/headless-browser.cpp index bed46ac996..598af2bd89 100644 --- a/Userland/Utilities/headless-browser.cpp +++ b/Userland/Utilities/headless-browser.cpp @@ -73,23 +73,24 @@ public: page().load(url); } - virtual void paint(Gfx::IntRect const& content_rect, Gfx::Bitmap& target) override + virtual void paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap& target) override { Gfx::Painter painter(target); + Gfx::IntRect int_content_rect { content_rect.x().value(), content_rect.y().value(), content_rect.width().value(), content_rect.height().value() }; if (auto* document = page().top_level_browsing_context().active_document()) document->update_layout(); - painter.fill_rect({ {}, content_rect.size() }, palette().base()); + painter.fill_rect({ {}, int_content_rect.size() }, palette().base()); auto* layout_root = this->layout_root(); if (!layout_root) { return; } - Web::PaintContext context(painter, palette(), content_rect.top_left()); + Web::PaintContext context(painter, palette(), int_content_rect.top_left()); context.set_should_show_line_box_borders(false); - context.set_viewport_rect(content_rect); + context.set_viewport_rect(int_content_rect); context.set_has_focus(true); layout_root->paint_all_phases(context); } @@ -104,7 +105,7 @@ public: page().top_level_browsing_context().set_viewport_rect(viewport_rect); } - void set_screen_rect(Gfx::IntRect screen_rect) + void set_screen_rect(Web::DevicePixelRect screen_rect) { m_screen_rect = screen_rect; } @@ -141,11 +142,16 @@ public: return Gfx::Palette(*m_palette_impl); } - virtual Gfx::IntRect screen_rect() const override + virtual Web::DevicePixelRect screen_rect() const override { return m_screen_rect; } + virtual float device_pixels_per_css_pixel() const override + { + return 1.0f; + } + virtual Web::CSS::PreferredColorScheme preferred_color_scheme() const override { return m_preferred_color_scheme; @@ -259,7 +265,7 @@ private: NonnullOwnPtr m_page; RefPtr m_palette_impl; - Gfx::IntRect m_screen_rect { 0, 0, 800, 600 }; + Web::DevicePixelRect m_screen_rect { 0, 0, 800, 600 }; Web::CSS::PreferredColorScheme m_preferred_color_scheme { Web::CSS::PreferredColorScheme::Auto }; RefPtr m_webdriver; @@ -699,7 +705,7 @@ static void load_page_for_screenshot_and_exit(HeadlessBrowserPageClient& page_cl auto output_file = MUST(Core::Stream::File::open(output_file_path, Core::Stream::OpenMode::Write)); auto output_rect = page_client.screen_rect(); - auto output_bitmap = MUST(Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRx8888, output_rect.size())); + auto output_bitmap = MUST(Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRx8888, output_rect.size().to_type())); page_client.paint(output_rect, output_bitmap); -- cgit v1.2.3