SerenityOS / serenity

The Serenity Operating System 🐞
https://serenityos.org
BSD 2-Clause "Simplified" License
30.69k stars 3.19k forks source link

LibWeb: Support CSS unicode-ranges and per-glyph font fallback #21213

Closed ADKaster closed 11 months ago

ADKaster commented 1 year ago

https://awesomekling.substack.com/p/welcoming-shopify-as-a-ladybird-sponsor

Produces some .. interesting glyphs

image

It appears that the text is supposed to have computed style font-family of:

"Spectral", serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"

Which is wahat we end up resolving, FWIW. It seems that whichever font is actually chosen (probably this "Spectral" one? isn't decoded properly at all.

Funding

Fund with Polar

awesomekling commented 1 year ago

Looks like missing support for CSS unicode-ranges. Multiple fonts are loaded for the same family name but with different unicode ranges, and we just ignore the ranges when matching fonts.

AtkinsSJ commented 1 year ago

Yeah there's generally meant to be per-code-point fallback. unicode-range is part of that, it says to only use that font for the given code points, but even without it we should fall back to later fonts if the code point isn't present.

Wait I didn't read Andreas's message properly. That makes things even more complicated.

aduerig commented 1 year ago

Edit: This comment was wrong. Only read if you want context for Andreas's response.

Putting this here for anyone else debugging. This .html produces the bogus glyphs above after a delay.

<style>
    @font-face {
        font-family: 'Spectral';
        src: url(https://fonts.gstatic.com/s/spectral/v13/rnCt-xNNww_2s0amA9M8on7mTNmnUHowCw.woff2) format('woff2');
    }
    body {
        font-family: 'Spectral';
    }
</style>
Hello

The bogus glyphs appear sometime after both the WOFF2 font is loaded and this function is run: https://github.com/SerenityOS/serenity/blob/f5771a5789836637cd72f13613915e21d086dbe4/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp#L1566

The .html code above is after I took out the css "unicode-ranges" property, and it still produces the bad glyphs. I'm not sure if that's because the property is being added back automatically after download, or there's multiple bugs or missing code to render the glyphs correctly.

awesomekling commented 1 year ago

The issue is that they're loading multiple character sets of the same typeface by spreading them across multiple @font-face rules. So they use unicode-ranges to say "this woff2 file is Spectral with the cyrillic alphabet, this other woff2 file is Spectral with the latin alphabet, etc".

LibWeb currently does not currently honor unicode-ranges at all, so we just render glyphs from one of the font files, and if it's the wrong file, it won't have the right glyphs in it :)

aduerig commented 1 year ago

The issue is that they're loading multiple character sets of the same typeface by spreading them across multiple @font-face rules. So they use unicode-ranges to say "this woff2 file is Spectral with the cyrillic alphabet, this other woff2 file is Spectral with the latin alphabet, etc".

LibWeb currently does not currently honor unicode-ranges at all, so we just render glyphs from one of the font files, and if it's the wrong file, it won't have the right glyphs in it :)

Ahhhh, that makes sense. My .html was bugged because I just happend to pick one of the random @font-face spectral rules, which happened to NOT contain the correct (code points? glyphs?). A more correct minimized example to debug could be:

<style>
        @font-face {
            font-family: 'Spectral';
            src: url(https://fonts.gstatic.com/s/spectral/v13/rnCs-xNNww_2s0amA9vmtm3PafaPWnIIMrY.woff2) format('woff2');
            unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF
        }
        @font-face {
            font-family: 'Spectral';
            src: url(https://fonts.gstatic.com/s/spectral/v13/rnCs-xNNww_2s0amA9vmtm3BafaPWnII.woff2) format('woff2');
            unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD
        }
    body {
        font-family: 'Spectral';
    }
</style>
Hello

When the bottom font-face is chosen the page renders correctly. When the top is chosen it renders wrong. I'll edit my comment above to not lead anyone astray.