oni2 icon indicating copy to clipboard operation
oni2 copied to clipboard

Blurred font rendering for Terminus TTF

Open mcallistertyler opened this issue 4 years ago • 17 comments

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

mcallistertyler avatar Mar 31 '20 11:03 mcallistertyler

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:

  • What operating system / version are you using?
  • What version of Terminus are you using? The one I downloaded was 4.47.0

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).

bryphe avatar Mar 31 '20 14:03 bryphe

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.

mcallistertyler avatar Mar 31 '20 16:03 mcallistertyler

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-

bryphe avatar Apr 14 '20 23:04 bryphe

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 avatar Apr 18 '20 01:04 adrian5

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?

adrian5 avatar May 21 '20 13:05 adrian5

@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?

manu-unter avatar May 22 '20 15:05 manu-unter

@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:

  • Anti-aliasing: Enabled
  • Hinting: Slight

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.

adrian5 avatar May 23 '20 20:05 adrian5

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:

  • Windows and Mac OS don't seem to provide as many configuration options, so these new properties would only have an impact on Linux systems. Chromium, as a comparison, always uses fixed values for hinting intensity on Windows and Mac OS since that property is not used on those platforms anyway. Only FreeType, i.e. Linux-based systems, will actually make use of it. There, they are however pretty important to create a seamless integration with the rest of the system.
  • This is the mapping that Chromium does on Linux: https://github.com/chromium/chromium/blob/master/ui/gfx/linux/fontconfig_util.cc
  • This is the structure that is constructed to hold this information: https://github.com/chromium/chromium/blob/master/ui/gfx/font_render_params.h

manu-unter avatar May 24 '20 00:05 manu-unter

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

manu-unter avatar May 27 '20 18:05 manu-unter

Thanks for the help @manuhornung !

bryphe avatar May 27 '20 18:05 bryphe

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 avatar May 31 '20 10:05 manu-unter

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

manu-unter avatar Jun 11 '20 09:06 manu-unter

@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.

bryphe avatar Jul 18 '20 17:07 bryphe

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

manu-unter avatar Jul 19 '20 09:07 manu-unter

@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.

p4block avatar Aug 07 '20 02:08 p4block

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.

manu-unter avatar Aug 07 '20 05:08 manu-unter

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

DoctorKnowsBetter avatar Sep 22 '22 21:09 DoctorKnowsBetter