Plan 9: Emoji

 

Noto Emoji Font

Note: Noto Color emoji needs Color Bitmap Data (CBDT) or COLR/CPAL support.

 

Four independent bugs, spanning truetypefs.c, hint.c, and head.c:

1. assert(gs[i] != nil) crash in compilesub (truetypefs.c)
ttffindchar returning glyph 0 for a rune inside a declared cmap segment (a genuine gap, not just the NUL special-case) skipped the retry-via-notdef path entirely. If the font's own .notdef then also failed to rasterize, the assert took the whole fileserver down. Fixed by replacing the assert with a synthesized blank placeholder as the last resort in the fallback chain.

2. No bounds checking on glyph geometry before blit() (truetypefs.c)
blit() has zero validation of its own; compilesub sized the destination strip from the font's declared ascentpx + descentpx but never checked that an individual glyph's actual rendered width/height/vertical position fit inside that buffer. A decorative font (architectsdaughter) reporting ink extents past its declared metrics caused blit to write past the buffer, corrupting the heap. Fixed with badglyph(), gating every glyph — primary TTF, bitmap fallback, and notdef — before it's ever blitted.

3. Unbounded native recursion in the hinting interpreter (hint.c)
h_call/h_loopcall implement the TrueType CALL/LOOPCALL instructions via genuine recursive C calls to run(), with an h->level counter that was tracked but never actually checked against any bound. A font with a deeply-nested fpgm/prep program (Noto Sans; architectsdaughter's trivial/absent hinting never touched this) blew the real process stack — this is what produced the sys: trap/suicide crashes and, separately, the reported "stack overflow" text. Fixed with a MAXLEVEL cap (64) in both instructions, failing cleanly via the existing herror()/longjmp path instead of faulting.

4. assert() on the interpreter's own operand-stack bounds in push()/pop() (hint.c)
Same failure class as #1, different subsystem: a bytecode-driven condition (NPUSHB/NPUSHW pushing more values than the stack's declared capacity) wired to abort() instead of the graceful herror() path already used everywhere else in the file. Fixed by converting both to bounds checks that call herror().

5. maxp.maxStackElements trusted at face value (head.c)
Once #4 stopped crashing, it surfaced a real data problem underneath: Noto Sans's own declared stack-size field is smaller than what its hinting program actually needs — a well-documented unreliability in real-world fonts' maxp tables, not a parsing bug (the field order was verified correct against the TrueType spec). Fixed by flooring u->maxStackElements to 512 right after parsing, so both the stack allocation and the runtime bound check in runpg — which both read that same field — get the padding for free from one edit.

Net effect: architectsdaughter was never actually broken by any of this — it just never had a hinting program complex enough to reach bugs #3–5, and never had a glyph malformed enough to reach #2. Noto Sans routed through all four in sequence, one crash at a time, until it renders cleanly with #5.

 

Color Emoji, Ligatures and Text Shaping

Color emojis are supported under three specifications - COLR+CPAL, SVG+CPAL, and CBLC+CBDT. This code implements COLR+CPAL without gradients and the demo uses Noto Color Emoji.
  

Also, added a simple API to view the glyph for a codepoint. Emojis can be combined with restrictions (glyph must be available in the font) using Zero Width Joiners (ZWJ) FE0F. This process is called Text Shaping. Text shaping is also used for ligatures (using GSUB) and combining in languages like Devanagari (using GPOS and FeatureList/LangSys).

page /n/ttf/notocoloremoji-regular.ttf.32/glyph/1f970
 
# Combined emoji (Keycap 1)
page /n/ttf/notocoloremoji-regular.ttf.128/glyph/0031-FE0F-20E3
 
# Ligature
page /n/ttf/dejavusans.ttf.128/glyph/66-66-69 
 


Text shaping for Devanagari script using NotoSansDevanagari-Regular.ttf. 

# matra 
page /n/ttf/notosansdevanagari-regular.ttf.320/glyph/93f-915 
 
# rakar 
page /n/ttf/notosansdevanagari-regular.ttf.320/glyph/915-94d-930 
 
# reph 
page /n/ttf/notosansdevanagari-regular.ttf.320/glyph/930-94d-915 

Unicode Coverage with Truetype Font


Combine multiple Truetype font files for complete Unicode coverage.

Note: 

  1. You can manually generate the font file too - follow the Notation section. Do ensure that you avoid any range overlaps.
  2. You want the ASCII range (0-128) to be rendered by a text font. e.g. NotoColorEmoji.ttf has a very wide space and misaligned numbers in relation to Dejavusans.ttf. 
term% echo 'myfont dejavusans.ttf notosansdevanagari-regular.ttf notoemoji-regular.ttf' > /n/ttf/ctl
 
term% cat /n/ttf/ctl
myfont    dejavusans.ttf notosansdevanagari-regular.ttf notoemoji-regular.ttf 
mine    dejavusans.ttf notosansdevanagari-regular.ttf notoemoji-regular.ttf 
 
term% font=/n/ttf/myfont/32/font acme
 

Notation

# font file: height, ascent followed by ranges [min max [optional offset] subfont]
cat /n/ttf/notosansdevanagari-regular.ttf.320/font
611    432
0x0000    0x00ff    s.0000-00ff
0x0100    0x01ff    s.0100-01ff
0x0200    0x02ff    s.0200-02ff
 
 
# subfont bitmap
cat /n/ttf/notosansdevanagari-regular.ttf.320/s.d700-d7ff
         k1           0           0       14112         611 <binary data> 
 

 

Color Emoji with libdraw


Color Emoji with libdraw

/shapeable and /shape APIs are exposed by Truetype file server to help with text shaping. These are ONLY used for composition and/or color emojis. If the font doesn't support these features, it falls back to font(6) architecture.

  •  GSUB - font has substitution/ligature shaping support
  • GPOS - font has mark positioning support
  • CTX    - context chaining support (unused)
  • COLR - font has a COLR table
  •  

    # Returns four values - GSUB GPOS CTX COLR 
    cat /n/ttf/notosansdevanagari-regular.ttf.320/shapeable 
     
    # Value represents the number of runes forming a cluster. 
    # Sequence is limited by MAXCLUSTER=8 
    cat /n/ttf/notosansdevanagari-regular.ttf.320/shape/930-94d-915-20
      

    Note: ZWJ clustering is not handled. 
     
    Devanagari support

    Sample Devanagari text 

    कर्मण्येवाधिकारस्ते मा फलेषु कदाचन ।
    मा कर्मफलहेतुर्भूर्मा ते सङ्गोऽस्त्वकर्मणि ॥

    धर्म क्षीर स्त्री ड़ाल कार्तिक
    कर्म क्रम
      


    Emoji Picker


    Insert emoji in the active window using a picker (uses /dev/cons). Use left click to select and right click to quit.


    Font Awesome Icons

     

    Download the Web zip (fontawesome-free-<version>-web.zip). The webfonts/ directory has fa-solid-900.ttf, fa-regular-400.ttf, and fa-brands-400.ttf, with TrueType glyf outlines. Regular is a subset of solid font.

    If you're using it with Dejavu font, note that Dejavu will claim f000-f003 if it's higher in the priority.


    Unicode Command

    Print a unicode character for a hex value.

    unicode 2211
    ∑
     
    # All the Math symbols
    unicode 2200-22ff 
      


    Code

     

    Comments

    Popular posts from this blog

    Plan 9 : The Infinity Notebook

    Plan 9: Quick Boot with UEFI

    Plan 9: Key Visualizer