LibWeb: Implement Screen.isExtended attribute

- Add WindowManagement to PolicyControlledFeature enum
- Add screen_count() virtual method to PageClient
- Store all screen rects in WebContent::PageClient, derive both
  screen_rect() and screen_count() from stored data
- Implement screen_count() overrides in SVGPageClient and PageHost
- Replace FIXME stub in Screen.cpp with spec-compliant implementation
This commit is contained in:
Adam Colvin 2025-12-27 16:34:26 +00:00 committed by Jelle Raaijmakers
parent 259e10a28a
commit 3a6d82245b
9 changed files with 35 additions and 5 deletions

View file

@ -95,8 +95,13 @@ GC::Ref<ScreenOrientation> Screen::orientation()
// https://w3c.github.io/window-management/#dom-screen-isextended
bool Screen::is_extended() const
{
dbgln("FIXME: Unimplemented Screen::is_extended");
return false;
// 1. If this's relevant global object's associated Document is not allowed to use
// the policy-controlled feature named "window-management", return false.
if (!window().associated_document().is_allowed_to_use_feature(DOM::PolicyControlledFeature::WindowManagement))
return false;
// 2. Return true if the device has more than one screen, and false otherwise.
return window().page().client().screen_count() > 1;
}
// https://w3c.github.io/window-management/#dom-screen-onchange

View file

@ -4528,6 +4528,9 @@ bool Document::is_allowed_to_use_feature(PolicyControlledFeature feature) const
case PolicyControlledFeature::Gamepad:
// FIXME: Implement allowlist for this.
return true;
case PolicyControlledFeature::WindowManagement:
// FIXME: Implement allowlist for this.
return true;
}
// 4. Return false.

View file

@ -176,6 +176,7 @@ enum class PolicyControlledFeature : u8 {
EncryptedMedia,
FocusWithoutUserActivation,
Gamepad,
WindowManagement,
};
class WEB_API Document

View file

@ -341,6 +341,7 @@ public:
virtual CSS::PreferredColorScheme preferred_color_scheme() const = 0;
virtual CSS::PreferredContrast preferred_contrast() const = 0;
virtual CSS::PreferredMotion preferred_motion() const = 0;
virtual size_t screen_count() const = 0;
virtual Queue<QueuedInputEvent>& input_event_queue() = 0;
virtual void report_finished_handling_input_event(u64 page_id, EventResult event_was_handled) = 0;
virtual void page_did_change_title(Utf16String const&) { }

View file

@ -85,6 +85,7 @@ public:
virtual CSS::PreferredColorScheme preferred_color_scheme() const override { return m_host_page->client().preferred_color_scheme(); }
virtual CSS::PreferredContrast preferred_contrast() const override { return m_host_page->client().preferred_contrast(); }
virtual CSS::PreferredMotion preferred_motion() const override { return m_host_page->client().preferred_motion(); }
virtual size_t screen_count() const override { return 1; }
virtual void request_file(FileRequest) override { }
virtual Queue<QueuedInputEvent>& input_event_queue() override { VERIFY_NOT_REACHED(); }
virtual void report_finished_handling_input_event([[maybe_unused]] u64 page_id, [[maybe_unused]] EventResult event_was_handled) override { }

View file

@ -53,7 +53,11 @@ public:
void set_palette_impl(Gfx::PaletteImpl&);
void set_viewport_size(Web::DevicePixelSize const&);
void set_screen_rects(Vector<Web::DevicePixelRect, 4> const& rects, size_t main_screen_index) { m_screen_rect = rects[main_screen_index]; }
void set_screen_rects(Vector<Web::DevicePixelRect> const& rects, size_t main_screen_index)
{
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_zoom_level(double zoom_level) { m_zoom_level = zoom_level; }
void set_maximum_frames_per_second(u64 maximum_frames_per_second);
@ -110,7 +114,8 @@ private:
virtual bool is_url_suitable_for_same_process_navigation(URL::URL const& current_url, URL::URL const& target_url) const override;
virtual void request_new_process_for_navigation(URL::URL const&) override;
virtual Gfx::Palette palette() const override;
virtual Web::DevicePixelRect screen_rect() const override { return m_screen_rect; }
virtual Web::DevicePixelRect screen_rect() const override { return m_all_screen_rects[m_main_screen_index]; }
virtual size_t screen_count() const override { return m_all_screen_rects.size(); }
virtual Web::CSS::PreferredColorScheme preferred_color_scheme() const override { return m_preferred_color_scheme; }
virtual Web::CSS::PreferredContrast preferred_contrast() const override { return m_preferred_contrast; }
virtual Web::CSS::PreferredMotion preferred_motion() const override { return m_preferred_motion; }
@ -194,7 +199,8 @@ private:
PageHost& m_owner;
GC::Ref<Web::Page> m_page;
RefPtr<Gfx::PaletteImpl> m_palette_impl;
Web::DevicePixelRect m_screen_rect;
Vector<Web::DevicePixelRect> m_all_screen_rects { Web::DevicePixelRect {} };
size_t m_main_screen_index { 0 };
double m_device_pixel_ratio { 1.0 };
double m_zoom_level { 1.0 };
double m_maximum_frames_per_second { 60.0 };

View file

@ -34,6 +34,7 @@ public:
virtual Web::CSS::PreferredColorScheme preferred_color_scheme() const override;
virtual Web::CSS::PreferredContrast preferred_contrast() const override;
virtual Web::CSS::PreferredMotion preferred_motion() const override;
virtual size_t screen_count() const override { return 1; }
virtual String page_did_request_cookie(URL::URL const&, Web::Cookie::Source) override;
virtual void request_file(Web::FileRequest) override;
virtual Web::DisplayListPlayerType display_list_player_type() const override { VERIFY_NOT_REACHED(); }

View file

@ -0,0 +1,3 @@
typeof screen.isExtended: boolean
screen.isExtended: false

View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<script src="include.js"></script>
<script>
test(() => {
println(`typeof screen.isExtended: ${typeof screen.isExtended}`);
println(`screen.isExtended: ${screen.isExtended}`);
});
</script>