[HN Gopher] Adventures in Text Rendering: Kerning and Glyph Atlases
       ___________________________________________________________________
        
       Adventures in Text Rendering: Kerning and Glyph Atlases
        
       Author : zachlloyd
       Score  : 50 points
       Date   : 2022-07-27 15:46 UTC (7 hours ago)
        
 (HTM) web link (www.warp.dev)
 (TXT) w3m dump (www.warp.dev)
        
       | billconan wrote:
       | I have a question,
       | 
       | How to do font fallback? For example, a user uses an English font
       | "Arial", and suddenly she types a Chinese character. the
       | character doesn't present in Arial, so we need to find a fallback
       | font that does.
       | 
       | Let's say we find one, but the fallback font has different
       | sizing. How to scale the character to match the other font? What
       | about kerning and other positioning issues?
       | 
       | And also, is your cache ever increasing? Imagine a user zooms in,
       | do you retire those small glyphs?
        
         | vorporeal wrote:
         | Blog post author here - great questions.
         | 
         | My understanding is that some, but not all, shaping libraries
         | will handle fallback fonts. For example, I believe Core Text
         | (on MacOS) will specify which sections of a laid-out line
         | should be rendered using which fonts, factoring in fallback
         | font selections. Kerning should work within a run of a single
         | font, but I'm not sure there's any way to "properly" kern a
         | glyph pair from two separate fonts - there wouldn't be any
         | information available about proper alignment (as kerning data
         | is part of a font file). In terms of sizing, one would hope
         | that font creators all respect the em-square when constructing
         | glyph vectors, leading to two different fonts using the same
         | point size having comparably-sized glyphs. If one doesn't want
         | to rely on that, font metrics like ascent and descent could be
         | utilized in an attempt to normalize sizing across different
         | fonts.
         | 
         | In terms of cache size: at the moment, we rarely empty out the
         | cache (but we should do it more often). I have some ideas
         | around triggers for emptying the cache and letting it get
         | rebuilt (e.g.: changes to font size, changes to font family),
         | but haven't wired it up yet. In addition, we could consider
         | clearing the cache periodically when the application is sitting
         | in the background (allowing us to re-rasterize the needed
         | glyphs without blocking painting a frame). So tl;dr: we don't
         | currently but we should and will do so in the future.
        
           | billconan wrote:
           | Thank you for the answers! I built a rust lib to generate
           | multi-channel signed distance field font texture. I wanted to
           | make it a text rendering lib. But after learning how complex
           | it is, I guess I should give up and simply use core text...
        
       | gumby wrote:
       | What an excellent introduction.
        
       | pseudosavant wrote:
       | It is always great to see an excellent post on keming like this.
        
         | actually_a_dog wrote:
         | See https://www.reddit.com/r/keming/ for examples in the wild
        
       | deathanatos wrote:
       | > _For monospace fonts, used by Warp for terminal input and
       | output, glyph advance is a constant - a fixed amount of spacing
       | is used between all pairs of glyphs._
       | 
       | It's more complicated than that, too. (But just about every
       | terminal I've ever used at one point or another has made that
       | buggy assumption!) Emoji and wide CJK characters typically take
       | two terminal cells.
       | 
       | For example (and HN will corrupt the output of this command, as
       | it will remove the emoji):                 >> python3 -c
       | 'print("1234567890\n\N{PILE OF POO}x\u4e09x")'       1234567890
       | xSan x
       | 
       | The second "x" should align under the 6. 4 glyphs, 6 cells.
       | 
       | (I am a bit curious about the subpixel stuff. I've done font
       | atlases, but IME Harfbuzz -- the shaping engine I've used -- only
       | seems to emit integral advances? (Although I'm now wanting to re-
       | test that assumption.) And I'm not entirely sure I know how to
       | ask FreeType to render a glyph with an offset, either.)
        
         | kevin_thibedeau wrote:
         | Unfortunately many of the grandfathered symbols in the emoji
         | block have ambiguous width and there is little recourse for
         | applications to determine the terminal display width of any
         | particular codepoint. Gnome VTE gives you a setting to force
         | them one way or another but that can interact badly with fonts
         | that expect a different width.
        
           | deathanatos wrote:
           | I think this is for the codepoints that have both an emoji
           | form and a non-emoji form? (And yeah, that's admittedly
           | confusing for the app.)
           | 
           | I think Unicode does specify a way to force those codepoints
           | to either the emoji form or the non-emoji form, but there is
           | still an encoding that is ambiguous by spec, I think.
           | 
           | E.g., the "TM" symbol falls into this; on macOS if you open
           | the character selector and search "trade", you will get both
           | variants.
           | 
           | Edit: this:
           | https://unicode.org/reports/tr51/#Presentation_Style
        
         | vorporeal wrote:
         | Good call-out - definitely a bit of a simplification there. We
         | account for this in our terminal grid by allocating an empty
         | cell following any double-width glyphs (e.g.: emoji and wide
         | chars, as you mentioned).
         | 
         | Tried out your example in Warp, and the alignment is as you
         | described: https://i.ibb.co/Jcwcnwn/image.png
         | 
         | Core Text supports rasterizing at sub-pixel offsets (though
         | some configuration of the graphics context is necessary to do
         | so properly) by applying a transformation to the graphics
         | context before the rasterization call. I'll definitely have to
         | figure out the FreeType angle when we start working on Linux
         | support; if I uncover anything (and remember this comment
         | thread), I'll report back with my findings. :)
        
       | skavi wrote:
       | Opening this website significantly degrades scrolling performance
       | in Edge (Chromium). This impacts all my open tabs. Scrolling
       | becomes fast again when the Warp tab is closed.
       | 
       | Doesn't exactly instill confidence in the advertised product.
        
       | boywitharupee wrote:
       | I'm fascinated by text rendering and just scratching the surface
       | to learn more.
       | 
       | A few questions I have:
       | 
       | 1. Is the pixel grid global to the the screen? or is it specific
       | to application? Can different applications on OS have different
       | pixel grids? Not sure where pixel grids come from
       | 
       | 2. Sounds painful to write your own font rendering system. Why
       | doesn't Warp use OS level libs CoreText, etc?
       | 
       | 3. I know there are many font rendering techniques such as
       | texture, distance and geometry based. The most recent one is
       | pathfinder technique, which is geometry based? Which one does
       | Warp uses?
       | 
       | 4. In which step the font rendering pipeline spends most time? Is
       | it the shaping? rasterization? font file parsing?
        
       ___________________________________________________________________
       (page generated 2022-07-27 23:02 UTC)