onivim / oni2

Native, lightweight modal code editor
https://v2.onivim.io
MIT License
7.77k stars 274 forks source link

Blurred font rendering for Terminus TTF #1532

Open mcallistertyler opened 4 years ago

mcallistertyler commented 4 years ago

Hi thanks for making this editor, I'm trying to integrate it into my daily usage but I'm having some issues with my font of choice (Terminus) and would like some help.

The font appears to be quite blurry compared to what I'm used to seeing in VSCode or my terminal:

2020-03-31_13-41

Subpixel-antialiasing didn't seem to make any difference to the image above. And by turning off font smoothing altogether the font appears quite broken. 2020-03-31_13-43

bryphe commented 4 years ago

Hi @mcallistertyler95 , thanks for logging the issue!

That is strange - indeed, you want to turn off font smoothing for Terminus - since it's primarily a bitmap font. I tested this version on OSX - and it looked much better than your "none" screenshot: image

A couple questions:

There definitely does seem to be an issue with font rendering with "none" in your case - It could be specific to Skia's font rendering / loading strategy for a particular platform (each one is different between Windows, Mac, and Linux).

mcallistertyler commented 4 years ago

I'm using Arch Linux with both Onivim2 and Terminus 4.47.0 from the AUR. I also tried the one you linked and got the same result.

bryphe commented 4 years ago

I suspect this might be related to differences in the hinting via FreeType / FontConfig - I'm adding some additional hooks to Skia to investigate this. Alternatively, we are setting setLCDRenderText, and that might be causing issues with this particular bitmap font. Still looking into this-

adrian5 commented 4 years ago

I want to mention that the font rendering (even with editor.fontSmoothing set to subpixel-antialiasing) still doesn't fully match what the rest of the system looks like (Linux). The glyphs have slightly more weight to them, and look less crisp.

I tend to take programs like Firefox as reference, as they had to sort this out in the past. My terminal, and even Atom (editor) look equally good. One of the few applications where this also diverged was QtCreator. If I remember it right, this was related to fontconfig; in the end, it might just require a minor tweak.

adrian5 commented 4 years ago

Below a screenshot of Atom (top) and Oni2:

atom-oni2-subpixel-rendering

Atom has nice crisp glyphs, probably as good as you can get at that DPI. Oni2 glyphs have a chubbier look to them, which imo looks unpolished/crowded and does not improve legibility.

I know that in the future – thanks to HiDPI displays – subpixel rendering will likely be ditched again, simplifying these concerns. For the time being though, many users don't use 4K displays. I definitely don't see myself having a HiDPI laptop for many years to come.

I believe Atom, Firefox etc. all have Skia in their rendering stack, so maybe it would be possible to replicate their behavior?

manu-unter commented 4 years ago

@adrian5 I'm assuming you're also running this on Linux? Can you please share your system-wide fontconfig? On Arch, for example, this would be done as explained here.

If this is not possible for any reason, could you share which hinting setting you have in your system configuration? In GNOME Tweak Tools, if you are running GNOME, this would be one of "None", "Slight", "Medium" or "Full". I'm assuming you're running "Slight"?

I agree that this is most likely related to different hinting strategies being used and we don't seem to pick up the system-wide one for some reason. It would be helpful to find out what's happening on your side to be sure!

Regarding the original issue that @mcallistertyler95 mentioned, I think we probably have some kind of fractional offset somewhere in our layout and that's what messes up the edges of the bitmap font. Maybe we need some rounding strategy for bitmap fonts to avoid this kind of bleeding?

adrian5 commented 4 years ago

@manuhornung Yes, I'm using Xubuntu (Xfce). My fontconfig settings appear to be in /etc/fonts/conf.d/. The settings there correspond to what I set via Xfce's config GUI:

I couldn't find another location being used that might conflict with those.

I tired the suggestion of starting applications with FC_DEBUG set, to see how the fontconfig is being loaded. That didn't give feedback for Atom or Oni2, presumably because they detach from the terminal when launched.

manu-unter commented 4 years ago

Great, thanks for the information! This is in line with what I expected: your system, like many modern Linux distros, uses slight hinting. Unfortunately, we don't correctly forward that setting into FreeType after reading it from FontConfig, which is why Skia defaults to medium hinting instead. That's why all text looks heavier in oni than in all other applications.

This might also be the root cause for the blurry bitmap fonts, but it could also be unrelated. We will probably need to wire everything up correctly to find out.

@bryphe thinking in terms of solutions: do you think it makes sense to extend the FontDescriptor with properties for hinting, enabling of bitmap font features, subpixel antialiasing and maybe others?

Chromium separates them into two distinct structs but I'm not sure why. They still query all those parameters from FontConfig for every single font...

Edit: A few more thoughts on this topic:

manu-unter commented 4 years ago

I'll draft something up in the direction of what I suggested inside https://github.com/revery-ui/reason-font-manager

bryphe commented 4 years ago

Thanks for the help @manuhornung !

manu-unter commented 4 years ago

I found out a few other points regarding what you reported about Terminus, @mcallistertyler95: querying my own fontconfig with fc-match on my Manjaro setup yielded the following output:

09:45:12 in /etc/fonts/conf.d 
[I] ➜ fc-match terminus -v
Pattern has 39 elts (size 48)
    family: "Terminus"(s)
    familylang: "en"(s)
    style: "Medium"(s)
    stylelang: "en"(s)
    fullname: "Terminus Medium"(s)
    fullnamelang: "en"(s)
    slant: 0(i)(s)
    weight: 100(f)(s)
    width: 100(f)(s)
    size: 12(f)(s)
    pixelsize: 12(f)(s)
    spacing: 110(i)(w)
    foundry: "PfEd"(w)
    antialias: False(w)
    hintstyle: 1(i)(w)
    hinting: True(s)
    verticallayout: False(s)
    autohint: False(s)
    globaladvance: True(s)
    file: "/usr/share/fonts/misc/ter-u12n.otb"(w)
    index: 0(i)(w)
    outline: False(w)
    scalable: False(w)
    dpi: 75(f)(s)
    scale: 1(f)(s)
    charset:
    0000: 00000000 ffffffff ffffffff 7fffffff 00000000 ffffffff ffffffff ffffffff
    0001: ffffffff ffffffff ffffffff ffffffff 6005c040 00e00000 001fe000 f031fffc
    0002: 0f000000 008c0000 0b100000 00040000 00040000 38000000 3b0000c0 00000000
    0003: 00001dff 00000200 00000000 00000000 ffffd7f0 fffffffb 00227fff 007f0000
    0004: ffffffff ffffffff ffffffff 00000c0c 3fff0000 0fcfcc3f ffff8007 033ffffc
    0005: 00000000 00000000 00000000 00000000 00000000 00000000 ffff0000 000007ff
    001e: 00003000 00f00000 000000ff 00003000 00000000 33000000 00003c00 03000030
    0020: ffffffff 560d0047 00000000 fff30000 05ff7fff 00005480 00000000 00000000
    0021: 2460c004 00200054 00000000 00000000 003f0000 08200150 003f1800 00000000
    0022: c67c3ff9 000007a0 00000100 00000c33 000000cc 00000020 0000000c 00000000
    0023: 02010f05 00000003 00000000 00000000 f8000000 3c00fbff 00010000 00000000
    0024: 00003e00 00000010 00000000 00000000 00000000 00000000 00000000 00000000
    0025: ffffff0f ffffffff ffff0fff ffffffff ffcfffff 14445001 03008c51 00000000
    0026: 00000000 1c000000 00000005 00000c69 00000000 00000000 00000000 00000000
    0027: 01980000 00000000 00000000 00000000 00000000 00000000 00000000 00000f00
    0028: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
    002e: 00000000 00001000 00000000 00000000 00000000 00000000 00000000 00000000
    00e0: 00000000 00000000 00000000 00000000 00000000 000f0007 00000000 00000000
    00f6: 00000000 00000000 00000000 00000000 00000000 40000000 00000000 00000000
    00ff: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 20000000
(w)
    lang: aa|af|av|ay|az-az|ba|bm|be|bg|bi|bin|br|bs|bua|ca|ce|ch|chm|co|cs|cv|da|de|el|en|eo|es|et|eu|fi|fj|fo|fr|fur|fy|gd|gl|gn|gv|haw|he|ho|hr|hu|ia|ig|id|ie|ik|io|is|it|kaa|ki|kk|kl|kum|kv|kw|ky|la|lb|lez|ln|lt|lv|mg|mh|mi|mk|mo|mt|nb|nds|nl|nn|no|nr|nso|ny|oc|om|os|pl|pt|rm|ro|ru|sah|se|sel|sh|sk|sl|sm|sma|smj|smn|sms|so|sq|sr|ss|st|sv|sw|tg|tk|tl|tn|to|tr|ts|tt|tw|tyv|uk|uz|vo|vot|wa|wen|wo|xh|yap|yi|zu|ak|an|crh|csb|fat|fil|hsb|ht|jv|kj|ku-tr|kwm|lg|li|mn-mn|ms|na|ng|nv|pap-an|pap-aw|rn|rw|sc|sg|sn|su|ty|za(s)
    fontversion: 65536(i)(s)
    fontformat: "TrueType"(w)
    embeddedbitmap: True(s)
    decorative: False(s)
    namelang: "en"(s)
    prgname: "fc-match"(s)
    postscriptname: "TerminusMedium"(w)
    color: False(w)
    symbol: False(s)
    variable: False(s)
    pixelsizefixupfactor: 1(f)(w)
    scalingnotneeded: True(w)

This yields a lot of info, but most important are probably antialias, scalable and outline being falseand embeddedbitmap and scalingnotneeded true - We don't forward any of this to skia for rendering, and the defaults are the opposite in our standard settings: We will use antialiasing and we will not use embedded bitmaps. See these default flags here. This is probably why you're seeing the blurry edges on Terminus. We'll have to do some additional wiring here to fix this.

manu-unter commented 4 years ago

I made a bit of progress here. It looks like if we want to support embedded bitmaps in fonts on Linux systems, we will need to query fontconfig once for each combination of family, size, weight, slant (italic or not) and possibly others. Only then we get the correctly-sized bitmaps for drawing.

As an example: We seem to get the default 12pt bitmaps right now when querying fontconfig, and if we draw some text with 12pt size, we get this result: image (ignore the upscaled blur in the full-size version that GitHub seems to introduce by compressing the file - it is 100% sharp)

This will make sense to go along with querying font-specific configuration for hinting, autohinting, antialiasing etc. - We can probably pick up the cache that chromium uses and implement something similar in revery. Then we can avoid querying fontconfig for every render

bryphe commented 4 years ago

@manuhornung - I think you mentioned that switching to the skia font manager helped here? @zbaylin merged in his change https://github.com/onivim/oni2/pull/2113 to use skia font manager as opposed to reason-font-manager (which seems to be better about pulling in some of the default font-specific configuration). I'm wondering if there is anything else we need to do here, though.

manu-unter commented 4 years ago

That's right, @bryphe! I think the main issue mentioned in the issue title should be fixed once we use that new revery version. Would probably be good to verify that though, just to be sure.

There was also the other point about the hinting defaulting to medium on Linux. On popular distros, the hinting is often set to slight, and that makes fonts appear heavier in revery than in other UI. I'm not sure right now how to tackle this in the most sensible way. We could try to read the settings from the desktop environment or from fontconfig, for example.

Maybe an 80/20 workaround could also be setting our default to slight hinting, to fix the most common cases?

We might want to split that up into a different issue in any case

p4block commented 4 years ago

@manuhornung Thanks to your comment on "embedded bitmaps" I found how to fix Terminus's TTF version blurryness on NixOS. Fontconfig needs to be allowed to use embedded bitmaps if present, and then it just works. Any program that uses Terminus at the correct size will work and render pixel perfect.

The issue with Terminus (TTF) is that it's a really, really bad font that was basically autoported into being TTF, and it's only TTF because it needs to be. GTK apps haven't supported non-ttf fonts for a while.

It doesn't really work at all. It should only be used at the specific sizes where it can fall back to bitmap rendering!

A "fun" effect I've found is that the magic size can vary between toolkits, and that I sometimes need to try numbers 8..12 until I find the correct ones.

manu-unter commented 4 years ago

Wow, thanks for the detailed explanation, @p4block ! I'm not entirely sure if @mcallistertyler95 had the same issue though, since he reported that other applications were rendering terminus sharply already. I'm hoping for this to be fixed with the new show font management in any case, so this should be fixed already.

I'll try to find some time over the weekend, too, so I can verify myself and also to check the hinting point after the updates.

DoctorKnowsBetter commented 1 year ago

I fixed this crap :) https://github.com/DoctorKnowsBetter/TerminessNerdFont-FixBlur