You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xmlgraphics.apache.org by "plutext (via GitHub)" <gi...@apache.org> on 2026/10/02 21:36:05 UTC

[PR] FOP-3347: A format character the font has a zero-width glyph for stays in the text layer [xmlgraphics-fop]

plutext opened a new pull request, #117:
URL: https://github.com/apache/xmlgraphics-fop/pull/117

   Fixes [FOP-3347](https://issues.apache.org/jira/browse/FOP-3347).
   
   MultiByteFont.performSubstitution maps characters to glyphs, runs GSUB, and then, unless
   retainControls (which TextLayoutManager never sets), elides every glyph whose characters
   are all "elidable controls": C0 and C1 controls, U+200B to U+200F, U+2028 to U+202E,
   U+2060, U+2066 to U+206F. The glyph and its association are gone, so the character never
   reaches the CID subset or the ToUnicode CMap, and text extraction loses it. The single-byte
   path keeps such a character (it maps it and draws the font's zero-width glyph), so one
   document extracted differently depending on how its font was declared.
   
   The elision is right for a font with no glyph for the character, which would otherwise be
   drawn as the missing-character glyph. But common fonts carry a real, zero-width glyph for
   exactly these characters (Arimo, Tinos and DejaVu Sans map U+200C, U+200D and U+206A to
   glyphs of advance 0), and for those the character can simply stay: it costs no space,
   draws nothing, and gets a subset selector and a ToUnicode entry of its own.
   
   elideControls now keeps an association of exactly one format character (U+2000 to U+206F)
   whose glyph is the one the character map gives it and whose advance is zero, unless it is
   a bidi control (U+200E, U+200F, U+202A to U+202E, U+2066 to U+2069). The bidi controls
   stay out on purpose: the text layer is written in visual order, after FOP's own bidi
   resolution, so a control there has done its work and a reader applies it a second time (a
   first cut that kept them had pdftotext wrap each kept mark in U+202B and U+202C). A
   character with no glyph, a glyph with an advance, and the C0 and C1 controls are elided as
   before.
   
   Measured on this branch, Arimo 12pt: "abc<U+206A>def" extracted as "abcdef" before and
   keeps the U+206A after, with every word box identical (56.69 to 92.70 pt);
   "abc<U+200F>def ghi" extracts as "abcdef ghi" before and after. A kept format glyph is in
   the sequence during GSUB and GPOS, so a ZWNJ between f and i blocks the ligature, which is
   its purpose, and a format character between two kerned letters blocks the pair.
   
   MultiByteFontFormatCharacterTestCase: five cases on a hand-built character map and width
   array.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@xmlgraphics.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: commits-help@xmlgraphics.apache.org