wez / wezterm

A GPU-accelerated cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust
https://wezfurlong.org/wezterm/
Other
16.78k stars 752 forks source link

MonoLisa font rendering on WezTerm is inconsistent #3919

Closed asapkep closed 7 months ago

asapkep commented 1 year ago

What Operating System(s) are you seeing this problem on?

macOS

Which Wayland compositor or X11 Window manager(s) are you using?

No response

WezTerm version

20230612-063953-baf9d970

Did you try the latest nightly build to see if the issue is better (or worse!) than your current version?

Yes, and I updated the version box above to show the version of the nightly that I tried

Describe the bug

I am a fan of the font MonoLisa and have been using it on other terminal emulators for quite some time (iTerm, Kitty, and Alacritty). On all of these terminal emulators, the font rendering is consistent. Particularly I am talking about the spacing between specific characters. However, on WezTerm the spacing between characters is inconsistent with characters being spread out further than others. In reality, the font is supposed to be monospaced. I have tried my bought version as well as the trial version of the font with the same issue arising. In the following screenshot, I have highlighted some instances of oddly spaced characters. In the second SS, I use the same font in iTerm to indicate what the rendering is supposed to look like. Screenshot 2023-07-01 at 11 47 22 AM

Screenshot 2023-07-01 at 12 03 43 PM

Usually, I would use an alternative font and would be happy, but it hurts that I paid for the font and cannot use it.

To Reproduce

Go to https://www.monolisa.dev/buy/661578 and download the trial version of the font. It looks like a purchase but if you look at the cost it is $0. You do have to provide an email id and a random zipcode, however. You can then set the font in your wezterm.lua to see it in action.

Configuration

local wezterm = require("wezterm")
local act = wezterm.action

-- A helper function for my fallback fonts
return {
    color_scheme = "nordic",
    -- font = wezterm.font({ "MonoLisa Nerd Font Mono" }),
    -- font = wezterm.font({
    --  family = "JetBrainsMonoNL Nerd Font Mono",
    --  weight = "Regular",
    --  harfbuzz_features = { "liga=1" },
    -- }),
    font = wezterm.font({
        -- family = "FiraCode Nerd Font Mono",
        -- family = "MonoLisa Nerd Font",
        family = "Liga SFMono Nerd Font",
        -- family = "MonoLisa Trial",
        weight = "Regular",
        harfbuzz_features = { "liga=1" },
    }),
    front_end = "WebGpu",
    font_size = 13.8,
    window_background_opacity = 0.95,
    scrollback_lines = 5000,

    term = "xterm-256color",
    -- Window decorations
    hide_tab_bar_if_only_one_tab = true,
    use_fancy_tab_bar = true,
    window_padding = {
        left = 0,
        right = 0,
        -- top = 0,
        -- bottom = 0,
    },
    -- Keybindings
    --

    keys = {
        -- Split vertically
        {
            key = "v",
            mods = "CTRL|SHIFT",
            action = act.SplitHorizontal({ domain = "CurrentPaneDomain" }),
        },

        -- Split horizontal
        {
            key = "s",
            mods = "CTRL|SHIFT",
            action = act.SplitVertical({ domain = "CurrentPaneDomain" }),
        },

        -- Jump to bottom pane
        {
            key = "k",
            mods = "CTRL",
            action = act.ActivatePaneDirection("Up"),
        },
        {
            key = "j",
            mods = "CTRL",
            action = act.ActivatePaneDirection("Down"),
        },
        { key = "UpArrow", mods = "SHIFT", action = act.ScrollByLine(-1) },

        -- Scroll down 1 line
        { key = "DownArrow", mods = "SHIFT", action = act.ScrollByLine(1) },
        { key = "Tab", mods = "ALT|SHIFT", action = act.ActivateTabRelative(-1) },
        { key = "Tab", mods = "ALT", action = act.ActivateTabRelative(1) },
    },
    -- Shell
    --
    -- MOUSE BINDINGS
    mouse_bindings = {
        -- Paste with right click
        {
            event = {
                Up = {
                    streak = 1,
                    button = "Right",
                },
            },
            mods = "NONE",
            action = act.PasteFrom("PrimarySelection"),
        },
    },
    -- make clickable hyperlinks work
    hyperlink_rules = {

        -- Linkify things that look like URLs and the host has a TLD name.
        -- Compiled-in default. Used if you don't specify any hyperlink_rules.
        {
            regex = "\\b\\w+://[\\w.-]+\\.[a-z]{2,15}\\S*\\b",
            format = "$0",
        },

        -- linkify email addresses
        -- Compiled-in default. Used if you don't specify any hyperlink_rules.
        {
            regex = [[\b\w+@[\w-]+(\.[\w-]+)+\b]],
            format = "mailto:$0",
        },

        -- file:// URI
        -- Compiled-in default. Used if you don't specify any hyperlink_rules.
        {
            regex = [[\bfile://\S*\b]],
            format = "$0",
        },

        -- Linkify things that look like URLs with numeric addresses as hosts.
        -- E.g. http://127.0.0.1:8000 for a local development server,
        -- or http://192.168.1.1 for the web interface of many routers.
        {
            regex = [[\b\w+://(?:[\d]{1,3}\.){3}[\d]{1,3}\S*\b]],
            format = "$0",
        },
    },
}

Expected Behavior

The font rendering should be monospaced.

Logs

Debug Overlay wezterm version: 20230612-063953-baf9d970 aarch64-apple-darwin Window Environment: macOS 13.4 (22F66) WebGPU: name=Apple M1 Pro, device_type=IntegratedGpu, backend=Metal, vendor=0, device=0 Enter lua statements or expressions and hit Enter. Press ESC or CTRL-D to exit

Anything else?

No response

asapkep commented 1 year ago

EDIT: I found that if I move the terminal back to my mbp retina display the spacing between the font is normal but if I put the terminal on my 1080p external display then the spacing is off.

murasakiwano commented 1 year ago

Hi! I also had some issues with the MonoLisa font a while back, and was able to fix it by setting freetype_load_flags = 'NO_HINTING'. The default was messing up some characters. For more info checkout https://wezfurlong.org/wezterm/config/lua/config/freetype_load_flags.html?h=freetype_

Lunaphied commented 1 year ago

Disabling hinting is a fairly strong move though — I'd like to understand why this font triggers issues better, since I've noticed similar issues in Kitty/Alacritty in the past with the font

wez commented 1 year ago

When working with the GPU, its coordinate space is floating point ranging from -1.0 to 1.0 in each direction. Perfect integer pixel positions don't really exist there. You can contrive for the math to align nicely when you run full screen with a display size that is, say, a power of 2, but that is not the case for arbitrarily sized windows.

Fonts are not sized by perfect integer pixel amounts either, so when you apply the font size, the display DPI (modified by display scaling) you will typically end up with fractional dimensions.

Rounding up to integer pixel dimensions in the wrong place can lead to display artifacts because strokes can get misaligned.

Font hinting is a step in rasterization where strokes are artificially moved so that they will fall into a pixel boundary.

At certain font and canvas size combinations, the hinting can cause or exaggerate similar pixel alignment issues. Furthermore, glyphs are pre-rasterized and cached in a texture atlas. While that cached a glyph (for example) might happen to have hinting that works in a certain column of the display, it may be wrong for a different column of the display, because we don't re-rasterize a different version of it for a different column.

I'm increasingly feeling as though direct-to-gpu applications that run in arbitrarily sized windows should probably default to disabling hinting when rasterizing fonts.

wez commented 1 year ago

also worth saying: some fonts have hinting information provided at design time by the font designer. freetype allows using that, or using an auto-hinting algorithm that tries to guess the right way to apply hinting. Due to variations in the quality of those designed vs. automated hints, it seems reasonable that you will see different degrees of artifacts around this stuff for different fonts.

wez commented 1 year ago

and also: I've noticed that folks that are typically running into this are operating on hi-dpi displays. Since that tends to be implemented as a 2x multiplier on the DPI, it will magnify any pixel misalignment issues by a similar amount. That would explain why the issue is more acutely noticeable on hi-dpi displays than regular displays: you just can't notice the difference at typical terminal font sizes at regular DPI because the error falls within a pixel boundary, rather than spills over a pixel boundary.

murasakiwano commented 1 year ago

Yes, that's exactly my case. I guess since macOS doesn't use anti-aliasing (as far as I can tell) and MonoLisa is not bitmap, I couldn't tell the difference between NO_HINTING and NO_AUTOHINT. Don't know how it relates to what Wez said

wez commented 1 year ago

@murasakiwano that suggests that there is no designer-provided hinting in that particular font, and that the automatic hinting algorithm used by freetype makes the wrong decisions in this context, because it doesn't know that there is no guaranteed integer pixel alignment.

murasakiwano commented 1 year ago

Hmm makes sense. Thanks @wez!

wez commented 7 months ago

The current release automatically sets NO_HINTING when the display dpi is >= 100, so I'm considering this issue to be closed.

github-actions[bot] commented 6 months ago

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.