[Dev-luatex] Improvements for glyph_stream_provider with TTF fonts

Marcel Fabian Kr├╝ger tex at 2krueger.de
Sat Aug 7 02:30:09 CEST 2021


Hi,

while working with the glyph_stream_provider callback I noticed that it
has some issues, especially around TTF fonts.

Especially LuaTeX analyzes the glyph streams *before* the callback get
involved to identify composite glyphs. If composite glyphs are found,
the corresponding components get added to the subset bug get new glyph
ids. Later, when glyph_stream_provider is called to get the glyph
streams, the parameters are the new glyph ids which are assigned by
LuaTeX and the mapping is not made available.

This leads to two issues:

  - When glyph_stream_provider is used, composite glyphs can't be
    preserved but have to be expanded since the callback has no way of
    knowing the final (remapped) glyph ids of the components.
    This can not only make the file bigger, it can also invalidate hinting
    instructions.
  - Even though the remapped components can't be found from the composite
    glyphs, they still trigger a call to the callback which can't be
    distinguished from normal calls and therefore still lead to
    something being added to the embedded font. Since only the remapped
    GID is made available, this will not even be the correct component
    glyph which happens to be in the slot described by the glyph id the
    component got mapped to (typically glyphs 1, 2, etc. since the
    remapping maps to the smallest unused glyph ids).
    This mostly just makes the embedded font bigger and it's confusing
    when looking at these subsetted fonts with weird glyphs included in
    the subset.
  - Somewhat independently, this current code does not allow the side
    bearings and advance widths to be modified which means that some
    table values can get inconsistent for variable fonts which change
    these values.

This this is used by existing code and mostly just causes inefficiencies
and not outright errors, the existing behavior should probably be kept
available for compatibility, so I suggest the following addition:

  When a font has font_streamprovider set to 3, behave exactly as if the
  streamprovider was 2, except that before the "normal"
  glyph_stream_provider provider calls for a font happen (with arguments
  fontid, (remapped) gid, 2) call the `glyph_stream_provider` once for
  every glyph with the four arguments
  (fontid, remapped gid, 3, original gid) and expect four return values,
  corresponding to horizontal advance width, left side bearing, vertical
  advance width and top side bearing.

This ensures that when the glyphstreams are generated, the callback code
is aware of the full mapping between original and remapping GIDs and can
therefore use these remapped GIDs correctly.

An example implementation is attached.

Best regards,
Marcel
-------------- next part --------------
diff --git a/source/texk/web2c/luatexdir/font/tt_glyf.c b/source/texk/web2c/luatexdir/font/tt_glyf.c
index 750e126aa..17a72c8e4 100644
--- a/source/texk/web2c/luatexdir/font/tt_glyf.c
+++ b/source/texk/web2c/luatexdir/font/tt_glyf.c
@@ -163,7 +163,7 @@ int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
     int tex_font = fd->tex_font;
     int streamprovider = 0;
     int callback_id = 0 ;
-    if ((tex_font > 0) && (font_streamprovider(tex_font) == 2)) {
+    if ((tex_font > 0) && (font_streamprovider(tex_font) == 2 || font_streamprovider(tex_font) == 3)) {
         streamprovider = font_streamprovider(tex_font);
         callback_id = callback_defined(glyph_stream_provider_callback);
     }
@@ -230,14 +230,23 @@ int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
             formatted_error("ttf","invalid glyph index (gid %u)", gid);
         loc = location[gid];
         len = location[gid + 1] - loc;
+        if (callback_id > 0 && streamprovider == 3) {
+            int advw, lsb, advh, tsb;
+            run_callback(callback_id, "dddd->dddd", tex_font, g->gd[i].gid, 3, gid, &advw, &lsb, &advh, &tsb);
+            g->gd[i].advw = advw;
+            g->gd[i].lsb = lsb;
+            g->gd[i].advh = advh;
+            g->gd[i].tsb = tsb;
+        } else {
-        g->gd[i].advw = hmtx[gid].advance;
-        g->gd[i].lsb = hmtx[gid].sideBearing;
-        if (vmtx) {
-            g->gd[i].advh = vmtx[gid].advance;
-            g->gd[i].tsb = vmtx[gid].sideBearing;
-        } else {
-            g->gd[i].advh = g->default_advh;
-            g->gd[i].tsb = g->default_tsb;
-        }
+            g->gd[i].advw = hmtx[gid].advance;
+            g->gd[i].lsb = hmtx[gid].sideBearing;
+            if (vmtx) {
+                g->gd[i].advh = vmtx[gid].advance;
+                g->gd[i].tsb = vmtx[gid].sideBearing;
+            } else {
+                g->gd[i].advh = g->default_advh;
+                g->gd[i].tsb = g->default_tsb;
+            }
+        }
         g->gd[i].length = len;
         g->gd[i].data = NULL;
@@ -402,7 +411,7 @@ int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
             if (callback_id > 0) {
                 lstring * result;
                 long size = 0;
-                run_callback(callback_id, "ddd->L", tex_font, g->gd[i].gid, streamprovider, &result);
+                run_callback(callback_id, "ddd->L", tex_font, g->gd[i].gid, 2, &result);
                 padlen = (int) ((result->l % 4) ? (4 - (result->l % 4)) : 0);
                 size = (size_t) result->l + (ULONG) padlen;
                 if (glyf_table_used + size >= glyf_table_size) {


More information about the dev-luatex mailing list