Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ligatures are drawn at wrong character offset #2539

Open
valleydali opened this issue May 12, 2024 · 9 comments
Open

Ligatures are drawn at wrong character offset #2539

valleydali opened this issue May 12, 2024 · 9 comments
Labels
bug Something isn't working

Comments

@valleydali
Copy link

Describe the bug
I am using the font Monaspace Neon 13 with all ligatures enabled. This text:

a//a  b==b  c->c

should be displayed as follows (this screenshot is from TextEdit):
Screenshot 2024-05-08 at 8 08 44 PM

But Neovide displays it like so:
Screenshot 2024-05-08 at 8 09 10 PM

To Reproduce
Steps to reproduce the behavior:

  1. Install the font. I installed it using Homebrew:
% brew tap homebrew/cask-fonts
% brew install --cask font-monaspace
  1. Set up config.toml to use Monaspace Neon and enable ligatures. Here is my config.toml:
[font]
normal = ["Monaspace Neon"]
size = 13

[font.features]
"Monaspace Neon" = [ "+calt", "+liga", "+ss01", "+ss02", "+ss03", "+ss04", "+ss05", "+ss06", "+ss07", "+ss08", "+ss09" ]
  1. Launch neovide and enter the test text: a//a b==b c->c

Expected behavior
The display should match the TextEdit screenshot above. Instead, as shown in the Neovide screenshot above, each ligature is drawn starting one character position to the left of where it should be drawn.

Desktop (please complete the following information):

  • OS: macOS 14.4.1 (Sonoma)
  • Neovide Version: 0.12.2, installed via Homebrew
  • Neovim Version: 0.9.5, installed via Homebrew

Please run neovide --log and paste the contents of the .log file created in the current directory here:
neovide_rCURRENT.log

@valleydali valleydali added the bug Something isn't working label May 12, 2024
@Kethku
Copy link
Member

Kethku commented May 12, 2024

Yup that looks wrong. Let me take a look

@Kethku
Copy link
Member

Kethku commented May 12, 2024

Weirdly I cant reproduce this issue on current main. Can you try building from main?

@Kethku Kethku added the status:needs-response issue or PR needs further information from author label May 12, 2024
@Kethku
Copy link
Member

Kethku commented May 12, 2024

actually i suspect this might be a bug with how swash handles ligatures from the most recent update to monaspace. Im running the initial release of the font which may explain why im not able to reproduce it.

I will update my fonts tomorrow and try again. Should be straight forward to open an upstream issue in swash if i can confirm that that is the issue.

@valleydali
Copy link
Author

It still happens when I build neovide from source.

@Kethku
Copy link
Member

Kethku commented May 12, 2024

Ok I have confirmed. This is due to the way that ligatures are rendered in the most recent version of monaspace. The v1.000 release of the font does not have this issue, so I recommend installing that version for now. In the meantime, I will report the issue to swash (the crate we use to shape text) to see about getting it fixed upstream.

@Kethku Kethku removed the status:needs-response issue or PR needs further information from author label May 12, 2024
@Kethku
Copy link
Member

Kethku commented May 13, 2024

Ok I've made a minimal repro that just uses swash and discovered that this issue is on our side after all.

Neovim expects us to render characters on a grid by unicode grapheme. We store the expected grid position in the userdata that we pass to swash when shaping. So effectively the only thing we are depending on swash for in terms of shaping is figuring out which graphemes to combine into which glyphs.

This is fundamentally a tradeoff. On the one hand, this causes neovide to render much closer to how terminal nvim would. Each character is drawn exactly on the grid. On the other, its incorrect in some cases for more advanced usages of the font rendering rewrite rules. Monaspace pushes those rules to the limit, so we run into these issues. An example of the kind of problem this approach avoids is that if you render the text exactly how the shaper expects, it is very easy to get offset from the strict grid for long runs of text. The current text renderer was arrived at to avoid that.

I will need to think about the problem a bit to figure out what the best route forward is. Its not clear to me how to both strictly follow the grid, and position ligatured glyphs correctly

@fredizzimo
Copy link
Member

fredizzimo commented May 13, 2024

Hm, I installed monaspace v1.101 from the Arch Linux repositories https://archlinux.org/packages/extra/any/otf-monaspace/, and I'm unable to reproduce the issue.

Which version of the font are you using?

Ignore that, my mistake

@fredizzimo
Copy link
Member

fredizzimo commented May 13, 2024

Edit: Ignore this as well, I looked at the wrong FiraCode font:

The problem seems to be that Monaspace uses center alignment of the ligatures, and not the alignment of the first char like all other fonts

From Fontforge:

Monaspace
image
FiraCode
image

We might be able to compensate for this.

@fredizzimo
Copy link
Member

This time I think I got it.
For FiraCode, the following glyphs are emitted;
exclam.spacer + exclam equal.liga, which are assigned glyph index 0+1 respectively.

While Monaspace does this emptyAdvanceWidth + exclamEqual, with both of them having the same index 0, which means that over code does not advance forward when rendering exclamEqual.

It might be possible to support this in combination with a grid, since Wezterm for example does it. But otherwise, one of the goals of the fractional grid size PR was to support variable size fonts, and let the shaper control the horizontal positioning. That would solve this issue as well, but it's not that easy to implement, since we need a go from a character position to grid position to support mouse clicks, for example, and the other way around to render the mouse cursor.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants