mapbox / mapbox-gl-native

Interactive, thoroughly customizable maps in native Android, iOS, macOS, Node.js, and Qt applications, powered by vector tiles and OpenGL
https://mapbox.com/mobile
Other
4.35k stars 1.33k forks source link

Use HarfBuzz for text shaping #7528

Open ChrisLoer opened 7 years ago

ChrisLoer commented 7 years ago

Addressing complex text rendering requires us to be able to do complex text shaping on the client side. This issue tracks our evaluation of HarfBuzz as a potential cross-platform solution. Desiderata include:

HarfBuzz was originally targeted at supporting OpenType fonts. It currently supports Apple Advanced Typography (AAT) features by passing through to Core Text on macOS/iOS.

To use HarfBuzz, we would modify node-fontnik to provide an interface for requesting glyphs based on font-specific glyph IDs (instead of the current interface based on Unicode code points). We would also have to send down to the client a minimal set of tables for the desired font in order to perform shaping.

HarfBuzz font data requirements

I performed a quick audit of the HarfBuzz code to determine which data tables need to be passed to the client in order to successfully perform shaping.

Necessary tables

Table Purpose
cmap Code point to glyph ID
head Font header
hhea Header for horizontal metrics
hmtx Horizontal metrics
GDEF Auxiliary glyph definitions (composition rules, etc.) [OpenType]
GPOS Glyph repositioning rules.[OpenType]
GSUB Glyph substitution rules. [OpenType]
maxp Memory allocation information to help processor. Should be small, probably necessary.
os/2 Like the Microsoft version of hhea. If included, may be necessary?
kern Kerning information. [TrueType only?]
vhea Header for vertical metrics
vmtx Vertical metrics

Unnecessary tables

Table Purpose
glyf Glyphs (usually biggest)
loca Pointers to glyph descriptions. Should be able to strip?
name Font naming information.
post Postscript support
JSTF Justification rules (expand or contract text with glyph substitutions/insertions). Probably can strip. [OpenType]
MATH Typesetting for mathematical formulae. Probably can strip? [OpenType]

Tables conditional on Core Text support

Table Purpose
mort Old version of morx
morx Finite automata for glyph substitution and repositioning rules
... it looks like other AAT tables get passed through to Core Text in this case without HarfBuzz knowing anything about them

Unsupported tables

My assumption is that tables not listed above are not supported by HarfBuzz and are safe to strip. I verified that the following (somewhat common) tables are not loaded by HarfBuzz:

VORG, BASE, cvt, fpgm, prep, CFF (PostScript glyphs), LTSH, acnt, bdat, EBDT, gasp, cvar, Zapf

Needs investigation

Fonts with 'silf' table, supported by Graphite

cc @jfirebaugh @tmpsantos @1ec5

tmpsantos commented 7 years ago

@ChrisLoer do you see we going similar path on JS using something like an emscript'ed version of HarfBuzz?

ChrisLoer commented 7 years ago

@tmpsantos Yes, I think so -- or at least it's the most full-featured solution I'm aware of. It will depend in part on whether we're willing to accept the bundle-size impact of loading all of an emscript'ed HarfBuzz. One of the things on my todo list is to make a relatively stripped down emscripten build of HarfBuzz to see how large it ends up being.

ChrisLoer commented 7 years ago

I've been experimenting with stripping out the "unnecessary tables" listed above in Arial Unicode MS. The base font is 24.4 MB in TTF format. Stripping out most of glyf, loca, and post gets it to a 359KB TTF, and HarfBuzz can still perform shaping using the stubbed out font.

The 359KB font compresses down to 103KB with gzip, or 72KB using WOFF2. WOFF2 uses the brotli compression algorithm, which may give some improvement over gzip, but it also has compression optimizations specifically designed for the hmtx table. On the GL-JS side, the cost of implementing WOFF2 decompression will almost certainly overwhelm the savings.

Using language-specific fonts, the sizes get even smaller. For instance, Noto Sans Devanagari is only 145KB, and strips down to 60KB with glyphs removed.

behdad commented 6 years ago

I'm also very interested to see how an emscriptened HarfBuzz performs, and help trim down the size as needed.

mdakram commented 5 years ago

Is this still into consideration?

ChrisLoer commented 5 years ago

This is still something we'd like to do, but unfortunately it's a large project that hasn't come to the top of our backlog, and I can't predict when it will other than to say "not in the next six months".

stale[bot] commented 5 years ago

This issue has been automatically detected as stale because it has not had recent activity and will be archived. Thank you for your contributions.