Improvements for glyph_stream_provider with TTF fonts
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
On Sat, Aug 07, 2021 at 10:43:35AM +0200, luigi scarso wrote:
On Sat, Aug 7, 2021 at 2:30 AM Marcel Fabian Krüger
wrote: An example implementation is attached.
$> dos2unix streamprovider3.patch
$> patch
hm, different source files ?
No, just an odd diff. I applied it locally with patch and got the same fuzz. The result is correct though. I'll attach a fixed patch file anyway. (It's probably caused by attempts to make the patch more readable by moving lines around. Not quite sure what exactly caused it. I had only checked patch with `git apply` before which seems to be more tolerant.) Best, Marcel
Patch is now ok, but I am perplexed by this line - 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); It's not clear why now we use 2. Perhaps it's better to introduce another variable, i.e. int actual_streamprovider ; if actual_streamprovider>2 { actual_streamprovider=2; } run_callback(callback_id, "ddd->L", tex_font, g->gd[i].gid, actual_streamprovider, &result); Or add a comment before , something like /* The streamprovider here is always 2 because... */ -- luigi
Hi, On Sun, Aug 08, 2021 at 12:19:36PM +0200, luigi scarso wrote:
Patch is now ok, but I am perplexed by this line
- 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);
It's not clear why now we use 2.
Basically this call is always compatible with the call made if the streamprovider were 2, so 2 is passed to differentiate it from the second call which actually provides behavior specific to streamprovider 3 and therefore uses streamprovider 3. We could also do this differently, e.g. by letting the Lua code determine it automatically by looking at the number of arguments passed to the callback or using different callback names, but since I would assume that most implementations would want to treat the callback from streamprovider 2 and the streamprovider 2 compatible call from streamprovider 3 identically anyway I considered this nicer.
Perhaps it's better to introduce another variable, i.e. int actual_streamprovider ; if actual_streamprovider>2 { actual_streamprovider=2; } run_callback(callback_id, "ddd->L", tex_font, g->gd[i].gid, actual_streamprovider, &result);
Or add a comment before , something like /* The streamprovider here is always 2 because... */
Suggested comment: /* The streamprovider here is always 2, even when we actually have streamprovider == 3, to differentiate this call which behaves exactly like the call in the streamprovider == 2 case from the streamprovider == 3 specific call earlier. */ Best regards, Marcel
-- luigi
_______________________________________________ dev-luatex mailing list dev-luatex@ntg.nl https://mailman.ntg.nl/mailman/listinfo/dev-luatex
On Sun, Aug 8, 2021 at 1:27 PM Marcel Fabian Krüger
/* The streamprovider here is always 2, even when we actually have streamprovider == 3, to differentiate this call which behaves exactly like the call in the streamprovider == 2 case from the streamprovider == 3 specific call earlier. */
ok. -- luigi
On Sun, Aug 8, 2021 at 1:32 PM luigi scarso
On Sun, Aug 8, 2021 at 1:27 PM Marcel Fabian Krüger
wrote: /* The streamprovider here is always 2, even when we actually have streamprovider == 3, to differentiate this call which behaves exactly like the call in the streamprovider == 2 case from the streamprovider == 3 specific call earlier. */
ok.
Committed revision 7449. -- luigi
On Sun, Aug 08, 2021 at 06:22:02PM +0200, luigi scarso wrote:
On Sun, Aug 8, 2021 at 1:32 PM luigi scarso
wrote: On Sun, Aug 8, 2021 at 1:27 PM Marcel Fabian Krüger
wrote: /* The streamprovider here is always 2, even when we actually have streamprovider == 3, to differentiate this call which behaves exactly like the call in the streamprovider == 2 case from the streamprovider == 3 specific call earlier. */
ok.
Committed revision 7449.
Thank you :) -- Marcel
participants (2)
-
luigi scarso
-
Marcel Fabian Krüger