Bug 254135 - [GTK] User contrast preference for high contrast not reflected in prefers-contrast CSS media query
Summary: [GTK] User contrast preference for high contrast not reflected in prefers-con...
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebKitGTK (show other bugs)
Version: WebKit Nightly Build
Hardware: PC Linux
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-03-19 07:24 PDT by Patrick H. Lauke
Modified: 2024-07-07 17:51 PDT (History)
6 users (show)

See Also:


Attachments
Screenshot showing Epiphany (Webkit-based) and Firefox on Ubuntu with high contrast setting enabled - note the difference in which prefers-contrast value evaluates to true (593.02 KB, image/png)
2023-03-19 07:24 PDT, Patrick H. Lauke
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Patrick H. Lauke 2023-03-19 07:24:27 PDT
Created attachment 465504 [details]
Screenshot showing Epiphany (Webkit-based) and Firefox on Ubuntu with high contrast setting enabled - note the difference in which prefers-contrast value evaluates to true

# Steps to reproduce the problem:

1. In Linux's settings, enable high contrast (in my case, in Ubuntu, this is under Settings > Accessibility > Seeing > High Contrast)
2. Open https://codepen.io/patrickhlauke/full/NWyajBN which tests the various user preference media features of MQ Level 5 (tested using Epiphany)
3. Check the reported "prefers-contrast" values

# Problem Description:

The expectation is that once High Contrast is enabled, the "prefers-contrast: more" media feature should evaluate to true. Instead, that currently evaluates to false and "prefers-contrast: no-preference" evaluates to true. I.e. Epiphany is not picking up on the OS-level preference. Note that this works as expected in Firefox/Linux (but fails the same way in Chrome/Linux - see https://bugs.chromium.org/p/chromium/issues/detail?id=1425734)

Tested in Epiphany 42.4 (the latest available from the Ubuntu software manager)

Relates to support for https://www.w3.org/TR/mediaqueries-5/#mf-user-preferences
Comment 1 Patrick H. Lauke 2023-03-19 07:24:58 PDT
Copied over from https://gitlab.gnome.org/GNOME/epiphany/-/issues/2001#note_1701623
Comment 2 Alice Mikhaylenko 2023-03-19 07:47:37 PDT
High contrast is a bit hard atm...

Using GSettings alone won't work in Flatpak.

Libadwaita has a fairly complicated logic to fetch it atm, I'm afraid WebKit may need to copy that...

Otherwise - when using libadwaita it can hook into it directly - it's not impossible, and everything you need here is accessible via properties so it can be done without a hard dependency. And honestly - when not using libadwaita you can just check gtk-theme-name instead.
Comment 3 Michael Catanzaro 2023-03-19 07:53:50 PDT
(In reply to Alexander Mikhaylenko from comment #2)
> Libadwaita has a fairly complicated logic to fetch it atm, I'm afraid WebKit
> may need to copy that...

Why aren't these settings exposed via settings portal? I think we should just look at the gsetting (carefully, to ensure we don't crash if not installed) and if it's not propagated by the portal then too bad. Desktop-wide settings that applications would be expected to read should be readable.

There's also a reduced motion accessibility setting that we should propagate as well (InternalSettings.h). (The other accessibility settings there don't have equivalents in GNOME.)
Comment 4 Alice Mikhaylenko 2023-03-19 07:56:59 PDT
It is exposed by the settings portal. How would it work in other apps otherwise? ;)

That's what libadwaita uses. Poratl + gsettings + deriving from gtk-theme-name on GdkDisplay + separate codepaths for macOS and Windows. But that's a lot of pretty fragile logic, do you really want to have it all in WebKit?
Comment 5 Alice Mikhaylenko 2023-03-19 07:58:54 PDT
Oh, forgot about those parts. There is also an env variable to override it on startup that Builder uses for its run -> accessibility -> high contrast toggle, and there's a toggle in inspector.
Comment 6 Patrick Griffis 2023-05-07 18:34:55 PDT
I did some initial work on this in https://github.com/WebKit/WebKit/pull/13558

It doesn't cover all situations and it is only for GTK3 but I think it is still valuable for some users.

I looked into using libadwaita to determine high-contrast on GTK4 but the complicated part is WebKit proxies over all GtkSettings to the WebProcess, but this isn't a GtkSetting, so we'd have to proxy it another way.

Otherwise just dynamically loading libadwaita wasn't too much effort and should work fine.
Comment 7 Michael Catanzaro 2023-05-07 21:09:00 PDT
Loading libadwaita only makes sense if the UI process is actually using libadwaita, though.

How do you check whether you're in high contrast mode with libadwaita?
Comment 8 Patrick Griffis 2023-05-08 09:00:58 PDT
(In reply to Michael Catanzaro from comment #7)
> Loading libadwaita only makes sense if the UI process is actually using
> libadwaita, though.

Yes. I was using `adw_is_initialized()` to conditionally check if we should respect libadwaita.

> How do you check whether you're in high contrast mode with libadwaita?

AdwStyleManager:high-contrast
Comment 9 Michael Catanzaro 2023-05-08 12:23:33 PDT
(In reply to Patrick Griffis from comment #8)
> Yes. I was using `adw_is_initialized()` to conditionally check if we should
> respect libadwaita.

Bah, I guess that is indeed a good reason to dlopen libadwaita, if you want to be able to do this check without having WebKit actually depend on libadwaita.

> > How do you check whether you're in high contrast mode with libadwaita?
> 
> AdwStyleManager:high-contrast

Hm, I know we are WebKitGTK and not WebKitAdwaita, but maybe it would be easiest to just link to libadwaita after all. Dunno. Well, if using dlopen is not too hard, I suppose that's fine.
Comment 10 Adrian Perez 2023-05-08 12:44:29 PDT
(In reply to Michael Catanzaro from comment #9)
> (In reply to Patrick Griffis from comment #8)
> > Yes. I was using `adw_is_initialized()` to conditionally check if we should
> > respect libadwaita.
> 
> Bah, I guess that is indeed a good reason to dlopen libadwaita, if you want
> to be able to do this check without having WebKit actually depend on
> libadwaita.
> 
> > > How do you check whether you're in high contrast mode with libadwaita?
> > 
> > AdwStyleManager:high-contrast
> 
> Hm, I know we are WebKitGTK and not WebKitAdwaita, but maybe it would be
> easiest to just link to libadwaita after all. Dunno. Well, if using dlopen
> is not too hard, I suppose that's fine.

Why not using the settings portal directly? We only need to watch the
property “high-contrast” of the “org.gnome.desktop.a11y.interface”, and
fallback to disabled if the interface is not available.

I would rather not link libadwaita at all, and avoid dlopening it as well
if possible. Alternatively, if we want to try libadwaita first, and fallback
to the portal, we can:

  typedef struct _AdwStyleManager AdwStyleManager;

  void* handle = dlopen(NULL, RTLD_NOW);
  gboolean (*adwaitaIsInitialized)(void) =
      dlsym(handle, "adw_is_initialized");
  AdwStyleManager (*adwaitaGetDefaultStyleManager)(void) =
      dlsym(handle, "adw_style_manager_get_default");

  if (adwaitaIsInitialized && adwaitaGetDefaultStyleManager && adwaitaIsInitialized()) {
      // Proceed as before, but now we reach this code only iff the application
      // had already loaded libadwaita, without needing to load it ourselves.
      AdwStyleManager* styleManager = adwGetDefaultStyleManager();
      g_signal_connect(styleManager, "notify::high-contrast", G_CALLBACK(...), ...);
  } else {
      // Assume high-contrast always off, or directly use DBus.
  }
Comment 11 Patrick Griffis 2023-05-08 12:52:19 PDT
(In reply to Adrian Perez from comment #10)
> Why not using the settings portal directly? We only need to watch the
> property “high-contrast” of the “org.gnome.desktop.a11y.interface”, and
> fallback to disabled if the interface is not available.

Any of these approaches are fine. We just have to proxy it similar to GtkSettingsManagerProxy.
Comment 12 Alice Mikhaylenko 2023-05-09 06:07:01 PDT
FWIW portal is an implementation detail, libadwaita does not guarantee that HC will be read from there at all. In fact, there are quite a few situations where it's not, like there is an environment variable to override it, there's a toggle in inspector that overrides it and so on.

One thing you can do without having to load libadwaita is: when AdwApplication is used, you can get the application, access the style-manager property, access the high-contrast property. That can be done in runtime, without linking or dlopening anything.

That won't work if adw_init() was used without AdwApplication though, but that's not recommended to begin with.
Comment 13 Michael Catanzaro 2023-05-09 12:09:49 PDT
(In reply to Alice Mikhaylenko from comment #12)
> One thing you can do without having to load libadwaita is: when
> AdwApplication is used, you can get the application, access the
> style-manager property, access the high-contrast property. That can be done
> in runtime, without linking or dlopening anything.

Oh wow, so this works because it's GObjects all the way down? That's actually a really cool idea.

We'd have to make sure the property actually exists before trying to get it using g_object_get(), to avoid criticals if the property doesn't exist, but I think that can be done by using G_OBJECT_GET_CLASS() then g_object_class_find_property().
Comment 14 Alice Mikhaylenko 2023-05-10 00:13:12 PDT
Yup. An upside of GObject properties existing entirely in runtime.

But yeah, there's still the case where you're not using AdwApplication. :(