Forráskód Böngészése

LibWeb: Add Contrast preference

Luke Warlow 1 éve
szülő
commit
ee64684565

+ 2 - 0
Ladybird/AppKit/Application/ApplicationDelegate.h

@@ -12,6 +12,7 @@
 #include <Ladybird/Types.h>
 #include <LibURL/URL.h>
 #include <LibWeb/CSS/PreferredColorScheme.h>
+#include <LibWeb/CSS/PreferredContrast.h>
 #include <LibWeb/HTML/ActivateTab.h>
 #include <LibWebView/CookieJar.h>
 
@@ -46,6 +47,7 @@
 - (Ladybird::WebContentOptions const&)webContentOptions;
 - (Optional<StringView> const&)webdriverContentIPCPath;
 - (Web::CSS::PreferredColorScheme)preferredColorScheme;
+- (Web::CSS::PreferredContrast)preferredContrast;
 - (WebView::SearchEngine const&)searchEngine;
 
 @end

+ 70 - 5
Ladybird/AppKit/Application/ApplicationDelegate.mm

@@ -30,6 +30,7 @@
     Optional<StringView> m_webdriver_content_ipc_path;
 
     Web::CSS::PreferredColorScheme m_preferred_color_scheme;
+    Web::CSS::PreferredContrast m_preferred_contrast;
 
     WebView::SearchEngine m_search_engine;
 }
@@ -88,6 +89,7 @@
         }
 
         m_preferred_color_scheme = Web::CSS::PreferredColorScheme::Auto;
+        m_preferred_contrast = Web::CSS::PreferredContrast::Auto;
         m_search_engine = WebView::default_search_engine();
 
         // Reduce the tooltip delay, as the default delay feels quite long.
@@ -161,6 +163,11 @@
     return m_preferred_color_scheme;
 }
 
+- (Web::CSS::PreferredContrast)preferredContrast
+{
+    return m_preferred_contrast;
+}
+
 - (WebView::SearchEngine const&)searchEngine
 {
     return m_search_engine;
@@ -258,6 +265,38 @@
     }
 }
 
+- (void)setAutoPreferredContrast:(id)sender
+{
+    m_preferred_contrast = Web::CSS::PreferredContrast::Auto;
+    [self broadcastPreferredContrastUpdate];
+}
+
+- (void)setLessPreferredContrast:(id)sender
+{
+    m_preferred_contrast = Web::CSS::PreferredContrast::Less;
+    [self broadcastPreferredContrastUpdate];
+}
+
+- (void)setMorePreferredContrast:(id)sender
+{
+    m_preferred_contrast = Web::CSS::PreferredContrast::More;
+    [self broadcastPreferredContrastUpdate];
+}
+
+- (void)setNoPreferencePreferredContrast:(id)sender
+{
+    m_preferred_contrast = Web::CSS::PreferredContrast::NoPreference;
+    [self broadcastPreferredContrastUpdate];
+}
+
+- (void)broadcastPreferredContrastUpdate
+{
+    for (TabController* controller in self.managed_tabs) {
+        auto* tab = (Tab*)[controller window];
+        [[tab web_view] setPreferredContrast:m_preferred_contrast];
+    }
+}
+
 - (void)setSearchEngine:(id)sender
 {
     auto* item = (NSMenuItem*)sender;
@@ -394,6 +433,25 @@
                                                        keyEquivalent:@""];
     [color_scheme_menu_item setSubmenu:color_scheme_menu];
 
+    auto* contrast_menu = [[NSMenu alloc] init];
+    [contrast_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Auto"
+                                                      action:@selector(setAutoPreferredContrast:)
+                                               keyEquivalent:@""]];
+    [contrast_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Less"
+                                                      action:@selector(setLessPreferredContrast:)
+                                               keyEquivalent:@""]];
+    [contrast_menu addItem:[[NSMenuItem alloc] initWithTitle:@"More"
+                                                      action:@selector(setMorePreferredContrast:)
+                                               keyEquivalent:@""]];
+    [contrast_menu addItem:[[NSMenuItem alloc] initWithTitle:@"No Preference"
+                                                      action:@selector(setNoPreferencePreferredContrast:)
+                                               keyEquivalent:@""]];
+
+    auto* contrast_menu_item = [[NSMenuItem alloc] initWithTitle:@"Contrast"
+                                                          action:nil
+                                                   keyEquivalent:@""];
+    [contrast_menu_item setSubmenu:contrast_menu];
+
     auto* zoom_menu = [[NSMenu alloc] init];
     [zoom_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Zoom In"
                                                   action:@selector(zoomIn:)
@@ -411,6 +469,7 @@
     [zoom_menu_item setSubmenu:zoom_menu];
 
     [submenu addItem:color_scheme_menu_item];
+    [submenu addItem:contrast_menu_item];
     [submenu addItem:zoom_menu_item];
     [submenu addItem:[NSMenuItem separatorItem]];
 
@@ -622,14 +681,20 @@
 
 - (BOOL)validateMenuItem:(NSMenuItem*)item
 {
-    using enum Web::CSS::PreferredColorScheme;
-
     if ([item action] == @selector(setAutoPreferredColorScheme:)) {
-        [item setState:(m_preferred_color_scheme == Auto) ? NSControlStateValueOn : NSControlStateValueOff];
+        [item setState:(m_preferred_color_scheme == Web::CSS::PreferredColorScheme::Auto) ? NSControlStateValueOn : NSControlStateValueOff];
     } else if ([item action] == @selector(setDarkPreferredColorScheme:)) {
-        [item setState:(m_preferred_color_scheme == Dark) ? NSControlStateValueOn : NSControlStateValueOff];
+        [item setState:(m_preferred_color_scheme == Web::CSS::PreferredColorScheme::Dark) ? NSControlStateValueOn : NSControlStateValueOff];
     } else if ([item action] == @selector(setLightPreferredColorScheme:)) {
-        [item setState:(m_preferred_color_scheme == Light) ? NSControlStateValueOn : NSControlStateValueOff];
+        [item setState:(m_preferred_color_scheme == Web::CSS::PreferredColorScheme::Light) ? NSControlStateValueOn : NSControlStateValueOff];
+    } else if ([item action] == @selector(setAutoPreferredContrast:)) {
+        [item setState:(m_preferred_contrast == Web::CSS::PreferredContrast::Auto) ? NSControlStateValueOn : NSControlStateValueOff];
+    } else if ([item action] == @selector(setLessPreferredContrast:)) {
+        [item setState:(m_preferred_contrast == Web::CSS::PreferredContrast::Less) ? NSControlStateValueOn : NSControlStateValueOff];
+    } else if ([item action] == @selector(setMorePreferredContrast:)) {
+        [item setState:(m_preferred_contrast == Web::CSS::PreferredContrast::More) ? NSControlStateValueOn : NSControlStateValueOff];
+    } else if ([item action] == @selector(setNoPreferencePreferredContrast:)) {
+        [item setState:(m_preferred_contrast == Web::CSS::PreferredContrast::NoPreference) ? NSControlStateValueOn : NSControlStateValueOff];
     } else if ([item action] == @selector(setSearchEngine:)) {
         auto title = Ladybird::ns_string_to_string([item title]);
         [item setState:(m_search_engine.name == title) ? NSControlStateValueOn : NSControlStateValueOff];

+ 2 - 0
Ladybird/AppKit/UI/LadybirdWebView.h

@@ -10,6 +10,7 @@
 #include <LibGfx/Forward.h>
 #include <LibURL/Forward.h>
 #include <LibWeb/CSS/PreferredColorScheme.h>
+#include <LibWeb/CSS/PreferredContrast.h>
 #include <LibWeb/HTML/ActivateTab.h>
 #include <LibWeb/HTML/AudioPlayState.h>
 #include <LibWebView/Forward.h>
@@ -62,6 +63,7 @@
 - (void)handleVisibility:(BOOL)is_visible;
 
 - (void)setPreferredColorScheme:(Web::CSS::PreferredColorScheme)color_scheme;
+- (void)setPreferredContrast:(Web::CSS::PreferredContrast)contrast;
 
 - (void)findInPage:(NSString*)query
     caseSensitivity:(CaseSensitivity)case_sensitivity;

+ 6 - 1
Ladybird/AppKit/UI/LadybirdWebView.mm

@@ -104,7 +104,7 @@ struct HideCursor {
         // This returns device pixel ratio of the screen the window is opened in
         auto device_pixel_ratio = [[NSScreen mainScreen] backingScaleFactor];
 
-        m_web_view_bridge = MUST(Ladybird::WebViewBridge::create(move(screen_rects), device_pixel_ratio, [delegate webContentOptions], [delegate webdriverContentIPCPath], [delegate preferredColorScheme]));
+        m_web_view_bridge = MUST(Ladybird::WebViewBridge::create(move(screen_rects), device_pixel_ratio, [delegate webContentOptions], [delegate webdriverContentIPCPath], [delegate preferredColorScheme], [delegate preferredContrast]));
         [self setWebViewCallbacks];
 
         m_web_view_bridge->initialize_client();
@@ -221,6 +221,11 @@ struct HideCursor {
     m_web_view_bridge->set_preferred_color_scheme(color_scheme);
 }
 
+- (void)setPreferredContrast:(Web::CSS::PreferredContrast)contrast
+{
+    m_web_view_bridge->set_preferred_contrast(contrast);
+}
+
 - (void)debugRequest:(ByteString const&)request argument:(ByteString const&)argument
 {
     m_web_view_bridge->debug_request(request, argument);

+ 10 - 3
Ladybird/AppKit/UI/LadybirdWebViewBridge.cpp

@@ -23,16 +23,17 @@ static T scale_for_device(T size, float device_pixel_ratio)
     return size.template to_type<float>().scaled(device_pixel_ratio).template to_type<int>();
 }
 
-ErrorOr<NonnullOwnPtr<WebViewBridge>> WebViewBridge::create(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, WebContentOptions const& web_content_options, Optional<StringView> webdriver_content_ipc_path, Web::CSS::PreferredColorScheme preferred_color_scheme)
+ErrorOr<NonnullOwnPtr<WebViewBridge>> WebViewBridge::create(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, WebContentOptions const& web_content_options, Optional<StringView> webdriver_content_ipc_path, Web::CSS::PreferredColorScheme preferred_color_scheme, Web::CSS::PreferredContrast preferred_contrast)
 {
-    return adopt_nonnull_own_or_enomem(new (nothrow) WebViewBridge(move(screen_rects), device_pixel_ratio, web_content_options, move(webdriver_content_ipc_path), preferred_color_scheme));
+    return adopt_nonnull_own_or_enomem(new (nothrow) WebViewBridge(move(screen_rects), device_pixel_ratio, web_content_options, move(webdriver_content_ipc_path), preferred_color_scheme, preferred_contrast));
 }
 
-WebViewBridge::WebViewBridge(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, WebContentOptions const& web_content_options, Optional<StringView> webdriver_content_ipc_path, Web::CSS::PreferredColorScheme preferred_color_scheme)
+WebViewBridge::WebViewBridge(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, WebContentOptions const& web_content_options, Optional<StringView> webdriver_content_ipc_path, Web::CSS::PreferredColorScheme preferred_color_scheme, Web::CSS::PreferredContrast preferred_contrast)
     : m_screen_rects(move(screen_rects))
     , m_web_content_options(web_content_options)
     , m_webdriver_content_ipc_path(move(webdriver_content_ipc_path))
     , m_preferred_color_scheme(preferred_color_scheme)
+    , m_preferred_contrast(preferred_contrast)
 {
     m_device_pixel_ratio = device_pixel_ratio;
 }
@@ -74,6 +75,12 @@ void WebViewBridge::set_preferred_color_scheme(Web::CSS::PreferredColorScheme co
     client().async_set_preferred_color_scheme(m_client_state.page_index, color_scheme);
 }
 
+void WebViewBridge::set_preferred_contrast(Web::CSS::PreferredContrast contrast)
+{
+    m_preferred_contrast = contrast;
+    client().async_set_preferred_contrast(m_client_state.page_index, contrast);
+}
+
 void WebViewBridge::enqueue_input_event(Web::MouseEvent event)
 {
     event.position = to_content_position(event.position.to_type<int>()).to_type<Web::DevicePixels>();

+ 5 - 2
Ladybird/AppKit/UI/LadybirdWebViewBridge.h

@@ -13,6 +13,7 @@
 #include <LibGfx/Size.h>
 #include <LibGfx/StandardCursor.h>
 #include <LibWeb/CSS/PreferredColorScheme.h>
+#include <LibWeb/CSS/PreferredContrast.h>
 #include <LibWeb/Page/InputEvent.h>
 #include <LibWebView/ViewImplementation.h>
 
@@ -20,7 +21,7 @@ namespace Ladybird {
 
 class WebViewBridge final : public WebView::ViewImplementation {
 public:
-    static ErrorOr<NonnullOwnPtr<WebViewBridge>> create(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, WebContentOptions const&, Optional<StringView> webdriver_content_ipc_path, Web::CSS::PreferredColorScheme);
+    static ErrorOr<NonnullOwnPtr<WebViewBridge>> create(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, WebContentOptions const&, Optional<StringView> webdriver_content_ipc_path, Web::CSS::PreferredColorScheme, Web::CSS::PreferredContrast);
     virtual ~WebViewBridge() override;
 
     virtual void initialize_client(CreateNewClient = CreateNewClient::Yes) override;
@@ -41,6 +42,7 @@ public:
 
     void update_palette();
     void set_preferred_color_scheme(Web::CSS::PreferredColorScheme);
+    void set_preferred_contrast(Web::CSS::PreferredContrast);
 
     void enqueue_input_event(Web::MouseEvent);
     void enqueue_input_event(Web::KeyEvent);
@@ -55,7 +57,7 @@ public:
     Function<void()> on_zoom_level_changed;
 
 private:
-    WebViewBridge(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, WebContentOptions const&, Optional<StringView> webdriver_content_ipc_path, Web::CSS::PreferredColorScheme);
+    WebViewBridge(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, WebContentOptions const&, Optional<StringView> webdriver_content_ipc_path, Web::CSS::PreferredColorScheme, Web::CSS::PreferredContrast);
 
     virtual void update_zoom() override;
     virtual Web::DevicePixelSize viewport_size() const override;
@@ -69,6 +71,7 @@ private:
     Optional<StringView> m_webdriver_content_ipc_path;
 
     Web::CSS::PreferredColorScheme m_preferred_color_scheme { Web::CSS::PreferredColorScheme::Auto };
+    Web::CSS::PreferredContrast m_preferred_contrast { Web::CSS::PreferredContrast::Auto };
 };
 
 }

+ 59 - 0
Ladybird/Qt/BrowserWindow.cpp

@@ -19,6 +19,7 @@
 #include <Ladybird/Qt/TabBar.h>
 #include <Ladybird/Utilities.h>
 #include <LibWeb/CSS/PreferredColorScheme.h>
+#include <LibWeb/CSS/PreferredContrast.h>
 #include <LibWeb/Loader/UserAgent.h>
 #include <LibWebView/CookieJar.h>
 #include <LibWebView/UserAgent.h>
@@ -232,6 +233,36 @@ BrowserWindow::BrowserWindow(Vector<URL::URL> const& initial_urls, WebView::Cook
 
     auto_color_scheme->setChecked(true);
 
+    auto* contrast_menu = view_menu->addMenu("&Contrast");
+
+    auto* contrast_group = new QActionGroup(this);
+
+    auto* auto_contrast = new QAction("&Auto", this);
+    auto_contrast->setCheckable(true);
+    contrast_group->addAction(auto_contrast);
+    contrast_menu->addAction(auto_contrast);
+    QObject::connect(auto_contrast, &QAction::triggered, this, &BrowserWindow::enable_auto_contrast);
+
+    auto* less_contrast = new QAction("&Less", this);
+    less_contrast->setCheckable(true);
+    contrast_group->addAction(less_contrast);
+    contrast_menu->addAction(less_contrast);
+    QObject::connect(less_contrast, &QAction::triggered, this, &BrowserWindow::enable_less_contrast);
+
+    auto* more_contrast = new QAction("&More", this);
+    more_contrast->setCheckable(true);
+    contrast_group->addAction(more_contrast);
+    contrast_menu->addAction(more_contrast);
+    QObject::connect(more_contrast, &QAction::triggered, this, &BrowserWindow::enable_more_contrast);
+
+    auto* no_preference_contrast = new QAction("&No Preference", this);
+    no_preference_contrast->setCheckable(true);
+    contrast_group->addAction(no_preference_contrast);
+    contrast_menu->addAction(no_preference_contrast);
+    QObject::connect(no_preference_contrast, &QAction::triggered, this, &BrowserWindow::enable_no_preference_contrast);
+
+    auto_contrast->setChecked(true);
+
     auto* show_menubar = new QAction("Show &Menubar", this);
     show_menubar->setCheckable(true);
     show_menubar->setChecked(Settings::the()->show_menubar());
@@ -895,6 +926,34 @@ void BrowserWindow::enable_dark_color_scheme()
     });
 }
 
+void BrowserWindow::enable_auto_contrast()
+{
+    for_each_tab([](auto& tab) {
+        tab.view().set_preferred_contrast(Web::CSS::PreferredContrast::Auto);
+    });
+}
+
+void BrowserWindow::enable_less_contrast()
+{
+    for_each_tab([](auto& tab) {
+        tab.view().set_preferred_contrast(Web::CSS::PreferredContrast::Less);
+    });
+}
+
+void BrowserWindow::enable_more_contrast()
+{
+    for_each_tab([](auto& tab) {
+        tab.view().set_preferred_contrast(Web::CSS::PreferredContrast::More);
+    });
+}
+
+void BrowserWindow::enable_no_preference_contrast()
+{
+    for_each_tab([](auto& tab) {
+        tab.view().set_preferred_contrast(Web::CSS::PreferredContrast::NoPreference);
+    });
+}
+
 void BrowserWindow::zoom_in()
 {
     if (!m_current_tab)

+ 4 - 0
Ladybird/Qt/BrowserWindow.h

@@ -120,6 +120,10 @@ public slots:
     void enable_auto_color_scheme();
     void enable_light_color_scheme();
     void enable_dark_color_scheme();
+    void enable_auto_contrast();
+    void enable_less_contrast();
+    void enable_more_contrast();
+    void enable_no_preference_contrast();
     void zoom_in();
     void zoom_out();
     void reset_zoom();

+ 1 - 0
Ladybird/Qt/WebContentView.h

@@ -17,6 +17,7 @@
 #include <LibGfx/StandardCursor.h>
 #include <LibURL/URL.h>
 #include <LibWeb/CSS/PreferredColorScheme.h>
+#include <LibWeb/CSS/PreferredContrast.h>
 #include <LibWeb/CSS/Selector.h>
 #include <LibWeb/Forward.h>
 #include <LibWeb/HTML/ActivateTab.h>

+ 1 - 0
Meta/gn/secondary/Userland/Libraries/LibWeb/CSS/BUILD.gn

@@ -46,6 +46,7 @@ source_set("CSS") {
     "ParsedFontFace.cpp",
     "PercentageOr.cpp",
     "PreferredColorScheme.cpp",
+    "PreferredContrast.cpp",
     "Ratio.cpp",
     "Resolution.cpp",
     "ResolvedCSSStyleDeclaration.cpp",

+ 1 - 0
Userland/Libraries/LibWeb/CMakeLists.txt

@@ -83,6 +83,7 @@ set(SOURCES
     CSS/ParsedFontFace.cpp
     CSS/PercentageOr.cpp
     CSS/PreferredColorScheme.cpp
+    CSS/PreferredContrast.cpp
     CSS/Ratio.cpp
     CSS/Resolution.cpp
     CSS/ResolvedCSSStyleDeclaration.cpp

+ 37 - 0
Userland/Libraries/LibWeb/CSS/PreferredContrast.cpp

@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2024, the Ladybird developers.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibWeb/CSS/PreferredContrast.h>
+
+namespace Web::CSS {
+
+PreferredContrast preferred_contrast_from_string(StringView value)
+{
+    if (value.equals_ignoring_ascii_case("less"sv))
+        return PreferredContrast::Less;
+    if (value.equals_ignoring_ascii_case("more"sv))
+        return PreferredContrast::More;
+    if (value.equals_ignoring_ascii_case("no-preference"sv))
+        return PreferredContrast::NoPreference;
+    return PreferredContrast::Auto;
+}
+
+StringView preferred_contrast_to_string(PreferredContrast value)
+{
+    switch (value) {
+    case PreferredContrast::Auto:
+        return "auto"sv;
+    case PreferredContrast::Less:
+        return "less"sv;
+    case PreferredContrast::More:
+        return "more"sv;
+    case PreferredContrast::NoPreference:
+        return "no-preference"sv;
+    }
+    VERIFY_NOT_REACHED();
+}
+
+}

+ 23 - 0
Userland/Libraries/LibWeb/CSS/PreferredContrast.h

@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2024, the Ladybird developers.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/StringView.h>
+
+namespace Web::CSS {
+
+enum class PreferredContrast {
+    Auto,
+    Less,
+    More,
+    NoPreference,
+};
+
+PreferredContrast preferred_contrast_from_string(StringView);
+StringView preferred_contrast_to_string(PreferredContrast);
+
+}

+ 12 - 2
Userland/Libraries/LibWeb/HTML/Window.cpp

@@ -338,8 +338,18 @@ Optional<CSS::MediaFeatureValue> Window::query_media_feature(CSS::MediaFeatureID
         }
     }
     case CSS::MediaFeatureID::PrefersContrast:
-        // FIXME: Make this a preference
-        return CSS::MediaFeatureValue(CSS::ValueID::NoPreference);
+        switch (page().preferred_contrast()) {
+        case CSS::PreferredContrast::Less:
+            return CSS::MediaFeatureValue(CSS::ValueID::Less);
+        case CSS::PreferredContrast::More:
+            return CSS::MediaFeatureValue(CSS::ValueID::More);
+        case CSS::PreferredContrast::NoPreference:
+            return CSS::MediaFeatureValue(CSS::ValueID::NoPreference);
+        case CSS::PreferredContrast::Auto:
+        default:
+            // FIXME: Fallback to system settings
+            return CSS::MediaFeatureValue(CSS::ValueID::NoPreference);
+        }
     case CSS::MediaFeatureID::PrefersReducedData:
         // FIXME: Make this a preference
         return CSS::MediaFeatureValue(CSS::ValueID::NoPreference);

+ 5 - 0
Userland/Libraries/LibWeb/Page/Page.cpp

@@ -112,6 +112,11 @@ CSS::PreferredColorScheme Page::preferred_color_scheme() const
     return m_client->preferred_color_scheme();
 }
 
+CSS::PreferredContrast Page::preferred_contrast() const
+{
+    return m_client->preferred_contrast();
+}
+
 CSSPixelPoint Page::device_to_css_point(DevicePixelPoint point) const
 {
     return {

+ 3 - 0
Userland/Libraries/LibWeb/Page/Page.h

@@ -25,6 +25,7 @@
 #include <LibJS/Heap/Heap.h>
 #include <LibURL/URL.h>
 #include <LibWeb/CSS/PreferredColorScheme.h>
+#include <LibWeb/CSS/PreferredContrast.h>
 #include <LibWeb/CSS/Selector.h>
 #include <LibWeb/Cookie/Cookie.h>
 #include <LibWeb/Forward.h>
@@ -102,6 +103,7 @@ public:
     Gfx::Palette palette() const;
     CSSPixelRect web_exposed_screen_area() const;
     CSS::PreferredColorScheme preferred_color_scheme() const;
+    CSS::PreferredContrast preferred_contrast() const;
 
     bool is_same_origin_policy_enabled() const { return m_same_origin_policy_enabled; }
     void set_same_origin_policy_enabled(bool b) { m_same_origin_policy_enabled = b; }
@@ -275,6 +277,7 @@ public:
     virtual DevicePixelRect screen_rect() const = 0;
     virtual double device_pixels_per_css_pixel() const = 0;
     virtual CSS::PreferredColorScheme preferred_color_scheme() const = 0;
+    virtual CSS::PreferredContrast preferred_contrast() const = 0;
     virtual void paint_next_frame() = 0;
     virtual void paint(DevicePixelRect const&, Gfx::Bitmap&, PaintOptions = {}) = 0;
     virtual void page_did_change_title(ByteString const&) { }

+ 1 - 0
Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.h

@@ -72,6 +72,7 @@ public:
     virtual DevicePixelRect screen_rect() const override { return {}; }
     virtual double device_pixels_per_css_pixel() const override { return 1.0; }
     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 void request_file(FileRequest) override { }
     virtual void paint_next_frame() override { }
     virtual void paint(DevicePixelRect const&, Gfx::Bitmap&, Web::PaintOptions = {}) override { }

+ 5 - 0
Userland/Libraries/LibWebView/ViewImplementation.cpp

@@ -157,6 +157,11 @@ void ViewImplementation::set_preferred_color_scheme(Web::CSS::PreferredColorSche
     client().async_set_preferred_color_scheme(page_id(), color_scheme);
 }
 
+void ViewImplementation::set_preferred_contrast(Web::CSS::PreferredContrast contrast)
+{
+    client().async_set_preferred_contrast(page_id(), contrast);
+}
+
 ByteString ViewImplementation::selected_text()
 {
     return client().get_selected_text(page_id());

+ 1 - 0
Userland/Libraries/LibWebView/ViewImplementation.h

@@ -62,6 +62,7 @@ public:
     void did_finish_handling_input_event(Badge<WebContentClient>, bool event_was_accepted);
 
     void set_preferred_color_scheme(Web::CSS::PreferredColorScheme);
+    void set_preferred_contrast(Web::CSS::PreferredContrast);
 
     ByteString selected_text();
     Optional<String> selected_text_with_whitespace_collapsed();

+ 6 - 0
Userland/Services/WebContent/ConnectionFromClient.cpp

@@ -933,6 +933,12 @@ void ConnectionFromClient::set_preferred_color_scheme(u64 page_id, Web::CSS::Pre
         page->set_preferred_color_scheme(color_scheme);
 }
 
+void ConnectionFromClient::set_preferred_contrast(u64 page_id, Web::CSS::PreferredContrast const& contrast)
+{
+    if (auto page = this->page(page_id); page.has_value())
+        page->set_preferred_contrast(contrast);
+}
+
 void ConnectionFromClient::set_has_focus(u64 page_id, bool has_focus)
 {
     if (auto page = this->page(page_id); page.has_value())

+ 2 - 0
Userland/Services/WebContent/ConnectionFromClient.h

@@ -15,6 +15,7 @@
 #include <LibJS/Forward.h>
 #include <LibJS/Heap/Handle.h>
 #include <LibWeb/CSS/PreferredColorScheme.h>
+#include <LibWeb/CSS/PreferredContrast.h>
 #include <LibWeb/Forward.h>
 #include <LibWeb/Loader/FileRequest.h>
 #include <LibWeb/Page/InputEvent.h>
@@ -88,6 +89,7 @@ private:
     virtual void set_autoplay_allowlist(u64 page_id, Vector<String> const& allowlist) override;
     virtual void set_proxy_mappings(u64 page_id, Vector<ByteString> const&, HashMap<ByteString, size_t> const&) override;
     virtual void set_preferred_color_scheme(u64 page_id, Web::CSS::PreferredColorScheme const&) override;
+    virtual void set_preferred_contrast(u64 page_id, Web::CSS::PreferredContrast const&) override;
     virtual void set_has_focus(u64 page_id, bool) override;
     virtual void set_is_scripting_enabled(u64 page_id, bool) override;
     virtual void set_device_pixels_per_css_pixel(u64 page_id, float) override;

+ 7 - 0
Userland/Services/WebContent/PageClient.cpp

@@ -155,6 +155,13 @@ void PageClient::set_preferred_color_scheme(Web::CSS::PreferredColorScheme color
         document->invalidate_style();
 }
 
+void PageClient::set_preferred_contrast(Web::CSS::PreferredContrast contrast)
+{
+    m_preferred_contrast = contrast;
+    if (auto* document = page().top_level_browsing_context().active_document())
+        document->invalidate_style();
+}
+
 void PageClient::set_is_scripting_enabled(bool is_scripting_enabled)
 {
     page().set_is_scripting_enabled(is_scripting_enabled);

+ 3 - 0
Userland/Services/WebContent/PageClient.h

@@ -48,6 +48,7 @@ public:
     void set_screen_rects(Vector<Web::DevicePixelRect, 4> const& rects, size_t main_screen_index) { m_screen_rect = rects[main_screen_index]; }
     void set_device_pixels_per_css_pixel(float device_pixels_per_css_pixel) { m_device_pixels_per_css_pixel = device_pixels_per_css_pixel; }
     void set_preferred_color_scheme(Web::CSS::PreferredColorScheme);
+    void set_preferred_contrast(Web::CSS::PreferredContrast);
     void set_should_show_line_box_borders(bool b) { m_should_show_line_box_borders = b; }
     void set_has_focus(bool);
     void set_is_scripting_enabled(bool);
@@ -94,6 +95,7 @@ private:
     virtual Gfx::Palette palette() const override;
     virtual Web::DevicePixelRect screen_rect() const override { return m_screen_rect; }
     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 void page_did_request_cursor_change(Gfx::StandardCursor) override;
     virtual void page_did_layout() override;
     virtual void page_did_change_title(ByteString const&) override;
@@ -179,6 +181,7 @@ private:
     PaintState m_paint_state { PaintState::Ready };
 
     Web::CSS::PreferredColorScheme m_preferred_color_scheme { Web::CSS::PreferredColorScheme::Auto };
+    Web::CSS::PreferredContrast m_preferred_contrast { Web::CSS::PreferredContrast::NoPreference };
 
     RefPtr<WebDriverConnection> m_webdriver;
 

+ 2 - 0
Userland/Services/WebContent/WebContentServer.ipc

@@ -4,6 +4,7 @@
 #include <LibGfx/Rect.h>
 #include <LibGfx/ShareableBitmap.h>
 #include <LibWeb/CSS/PreferredColorScheme.h>
+#include <LibWeb/CSS/PreferredContrast.h>
 #include <LibWeb/CSS/Selector.h>
 #include <LibWeb/HTML/ColorPickerUpdateState.h>
 #include <LibWeb/HTML/SelectedFile.h>
@@ -77,6 +78,7 @@ endpoint WebContentServer
     set_autoplay_allowlist(u64 page_id, Vector<String> allowlist) =|
     set_proxy_mappings(u64 page_id, Vector<ByteString> proxies, HashMap<ByteString, size_t> mappings) =|
     set_preferred_color_scheme(u64 page_id, Web::CSS::PreferredColorScheme color_scheme) =|
+    set_preferred_contrast(u64 page_id, Web::CSS::PreferredContrast contrast) =|
     set_has_focus(u64 page_id, bool has_focus) =|
     set_is_scripting_enabled(u64 page_id, bool is_scripting_enabled) =|
     set_device_pixels_per_css_pixel(u64 page_id, float device_pixels_per_css_pixel) =|

+ 5 - 0
Userland/Services/WebWorker/PageHost.cpp

@@ -67,6 +67,11 @@ Web::CSS::PreferredColorScheme PageHost::preferred_color_scheme() const
     return Web::CSS::PreferredColorScheme::Auto;
 }
 
+Web::CSS::PreferredContrast PageHost::preferred_contrast() const
+{
+    return Web::CSS::PreferredContrast::Auto;
+}
+
 void PageHost::paint(Web::DevicePixelRect const&, Gfx::Bitmap&, Web::PaintOptions)
 {
 }

+ 1 - 0
Userland/Services/WebWorker/PageHost.h

@@ -29,6 +29,7 @@ public:
     virtual Web::DevicePixelRect screen_rect() const override;
     virtual double device_pixels_per_css_pixel() const override;
     virtual Web::CSS::PreferredColorScheme preferred_color_scheme() const override;
+    virtual Web::CSS::PreferredContrast preferred_contrast() const override;
     virtual void paint_next_frame() override {};
     virtual void paint(Web::DevicePixelRect const&, Gfx::Bitmap&, Web::PaintOptions = {}) override;
     virtual void request_file(Web::FileRequest) override;