flypig.co.uk

Gecko-dev Diary

Between August 2023 and September 2024 I upgrading the Sailfish OS browser from Gecko version ESR 78 to ESR 91, writing a daily blog as I went along. This page catalogues my progress, alongside the other browser-related topics I've looked in to since.

Latest code changes are in the gecko-dev sailfishos-esr91 branch.

There is an index of all posts in case you want to jump to a particular day.

Gecko RSS feed Click the icon for the Gecko-dev Diary RSS feed.

Gecko

5 most recent items

27 Jul 2024 : Day 301 #
Yesterday was all about the login manager, the service that stores and retrieves passwords for you when using the browser. The feature was completely broken, with the code failing as it attempted to use the upstream version that's build for Firefox. On Sailfish OS we have our own implementation which had to be patched in to get it to work.

Eventually it did work and to celebrate the fact Thigg (thigg) has provided another of his wonderfully evocative illustrations. Here's a pig with wings handing a big golden key to a gecko. Which is actually how the login manager works under the hood!
 
A pig with wings handing a big golden key to a gecko. Medieval woodcut

There's only one thing to rival the excitement of seeing one of Thigg's images in my Mastodon feed and that's spotting one of Leif-Jöran Olsson's (ljo) brilliant poems. So you can only imagine how thrilled I was to see both when I looked at my feed this morning.

Here's Leif-Jöran's brilliant summary of where things are at. A little ominous in places — some might say rightfully so — but with enough of a dose of optimism to last through the day!
 
The smell of decaying matter gives hope for threading remaining uncharted territory. Lingering patches opens up the ordered passage at the wormholes' gates. The sudden possibility to transition to other worlds challenges your imaginative capabilities. Flickering sight, sensory shivering. Is it epiphany? No, it its the trusted gecko! With endurance and everyday work you can change worlds of many. Cause for celebration in the month of harvest.

Sailing on this wave of artistic energy, today it's all about yin and yang. Day and night. Light and dark. The ESR 78 version of the browser was the first to support colour schemes for websites, being able to switch between Light mode, Dark mode or automatically matching the ambience of your device. Ambiences were a standout feature of Sailfish OS at launch and, while even iOS is now trying to catch up, it's remained one of the most-loved features of Sailfish OS for many users. Light ambiences were introduced in Sailfish OS 3 and since then, supporting light and dark mode in the browser always felt like a natural extension of this.

Currently switching between fixed light and dark mode through the Settings page works just fine. But when set to "Match ambience" it gets stuck in one or the other and never changes. Identifying that the ambience has changed is the job of the browser chrome. It then sends a message to the browser engine to update its internal setting.

This means there's another consideration too, which is what happens at start up. The initialisation sequence needs to be timed just right, so that the chrome sends the message early enough that pages haven't yet been rendered, but late enough that the engine is far enough along its initialisation path to accept the message.

We already have patch 0093 "Add support for prefers-color-scheme" which is supposed to do the job of sorting all this out, including adding support for automatic ambience changes. It looks like I applied most of these changes already back in August as part of the "Bring back Qt layer" megapatch. I must have (rightly, I think) combined the changes to avoid repatching some already-patched code.

But it's not working and today I plan to find out why.

First off I notice as I look through the code that the Qt nsLookAndFeel.cpp source includes some debug output in the code for handling ambience changes, as you can see in the snippet below. We should be able to configure things so that the call to MOZ_LOG() generates debug output to the console.
LazyLogModule sLookAndFeel("LookAndFeel");
[...]

NS_IMETHODIMP nsLookAndFeel::Observer::Observe(nsISupports*, const char* 
    aTopic, const char16_t* aData) {
    MOZ_ASSERT(!strcmp(aTopic, "ambience-theme-changed"));

    bool darkAmbience = false;
    nsDependentString data(aData);
    if (data.EqualsLiteral("dark")) {
        darkAmbience = true;
    }

    if (mDarkAmbience != darkAmbience) {
        mDarkAmbience = darkAmbience;
        MOZ_LOG(sLookAndFeel, LogLevel::Info, ("Ambience set to %s", 
    mDarkAmbience ? "dark" : "light"));
        if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
            NotifyChangedAllWindows(widget::ThemeChangeKind::StyleAndLayout);
        }
    }

    return NS_OK;
}
In order to have it displayed we need to set the MOZ_LOG environment variable appropriately, as described in the Working with the Browser documentation. Setting this up to include LookAndFeel:5 unlocks these logging lines, so they then output to the console:
$ MOZ_LOG=&quot;LookAndFeel:5&quot; sailfish-browser
[...]
[Parent 10403: Unnamed thread 7a78002670]: I/LookAndFeel Ambience set to dark
[Parent 10403: Unnamed thread 7a78002670]: I/LookAndFeel Ambience set to light
[Parent 10403: Unnamed thread 7a78002670]: I/LookAndFeel Ambience set to dark
[...]
This gives us an interesting insight. When the ambience is switched from light to dark, this message is printed. When the browser starts up the dark ambience is set to false by default. But the initial message sent out to update the colour scheme is either lost or ignored. As a consequence, when the next switch is made to light mode the browser thinks it's already in light mode and ignores it.

Subsequent switches do trigger the debug output as intended.

Nevertheless, these messages are getting so far and then stopping, because the actual switch to light or dark mode never happens. To try to get a better idea about what's going on, I've added a breakpoint to a few methods: notifyColorSchemeChanged(), nsLookAndFeel::Observer::Observe() and nsLookAndFeel::nsLookAndFeel(). The last of these is where the observer is configured, so this needs to be called before the very first notification is sent from the front end.

Here are the breakpoints I've added to try to find out the ordering at start-up:
(gdb) info break
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   <MULTIPLE>         
        breakpoint already hit 1 time
1.1                         y     0x0000007ff7f50c14 <SailfishOS::
    WebEngineSettings::notifyColorSchemeChanged()@plt+4>
1.2                         y     0x0000007ff7f52fb0 in SailfishOS::
    WebEngineSettings::notifyColorSchemeChanged() at webenginesettings.cpp:220
2       breakpoint     keep y   0x0000007ff3e99514 in nsLookAndFeel::Observer::
    Observe(nsISupports*, char const*, char16_t const*) 
                                                   at widget/qt/
    nsLookAndFeel.cpp:81
        breakpoint already hit 1 time
3       breakpoint     keep y   0x0000007ff3e9c18c in nsLookAndFeel::
    nsLookAndFeel() 
                                                   at widget/qt/
    nsLookAndFeel.cpp:62
        breakpoint already hit 1 time
In terms of actual execution, the running order exposed using these breakpoints turns out to be instructive. Clearly the creation of nsLookAndFeel is happening too late — or maybe the message is being sent too early — but either way the message is being lost before anything can be received.
Thread 1 &quot;sailfish-browse&quot; hit Breakpoint 1, SailfishOS::
    WebEngineSettings::notifyColorSchemeChanged (
    this=0x7ff7f67470 <(anonymous namespace)::Q_QGS_webEngineSettingsInstance::
    innerFunction()::holder>) at webenginesettings.cpp:220
220         Silica::Theme *silicaTheme = Silica::Theme::instance();
(gdb) c
Continuing.
[LWP 11896 exited]
[Switching to LWP 11862]

Thread 10 &quot;GeckoWorkerThre&quot; hit Breakpoint 3, nsLookAndFeel::
    nsLookAndFeel (this=0x7fb87dbc50)
    at widget/qt/nsLookAndFeel.cpp:62
62      nsLookAndFeel::nsLookAndFeel()
(gdb) c
Continuing.
[New LWP 11897]

Thread 10 &quot;GeckoWorkerThre&quot; hit Breakpoint 2, nsLookAndFeel::Observer:
    :Observe (this=0x7fb8b25d90, aTopic=0x555601d728 
    &quot;ambience-theme-changed&quot;, 
    aData=0x7fb8cddf88 u&quot;dark&quot;)
    at widget/qt/nsLookAndFeel.cpp:81
81      NS_IMETHODIMP nsLookAndFeel::Observer::Observe(nsISupports*, const 
    char* aTopic, const char16_t* aData) {
(gdb) n
85          nsDependentString data(aData);
(gdb) 
86          if (data.EqualsLiteral(&quot;dark&quot;)) {
(gdb) 
90          if (mDarkAmbience != darkAmbience) {
(gdb) p mDarkAmbience
$5 = false
(gdb) p darkAmbience
$6 = true
(gdb) c
Continuing.
[Parent 11843: Unnamed thread 7fb8002670]: I/LookAndFeel Ambience set to dark
The other problem seems to relate to how nsLookAndFeel.cpp and nsXPLookAndFeel.cpp work with one another. When the notification is received the integer preference related to the colour mode doesn't seem to be getting changed. This is all code that's changed quite significantly since ESR 78 and I'm going to need a bit more time to decipher it.

I've managed to make a bit of progress with this today, but not as much as I'd hoped. I still don't have all of the answers and so I'm going to have to pick this up again tomorrow to try to get to the bottom of it.

If you'd like to read any of my other gecko diary entries, they're all available on my Gecko-dev Diary page.

Comments

Uncover Disqus comments