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:34:42 UTC

[PR] FOP-3340: A CJK ideograph sharing a glyph with a Kangxi radical is written to ToUnicode as the radical [xmlgraphics-fop]

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

   Fixes [FOP-3340](https://issues.apache.org/jira/browse/FOP-3340).
   
   With complex script features enabled, CJK text is painted correctly but extracts,
   searches and reads out as the Kangxi radicals which share the ideographs' glyphs.
   One FO, one font (Source Han Sans CN), stock FOP, only the complex-script flag
   changed:
   
   ```
       features on   0003=U+2F63 0004=U+2F45 0005=U+2F08 0006=U+FF0C 0007=U+724B
       features off  0003=U+751F 0004=U+65B9 0005=U+4EBA 0006=U+FF0C 0007=U+724B
   ```
   
   The glyphs drawn are identical either way - glyph 3,4,5,6,7 at x=0,12,24,36,48,
   advance 1 each. U+724B, which no radical shares, is right either way: the control.
   
   MultiByteFont.performSubstitution runs the font's layout tables over characters -
   chars to glyphs, GSUB, then mapGlyphsToChars - and mapGlyphsToChars takes each
   glyph's character from findCharacterFromGlyphIndex, which returns the first code
   point in the cmap mapped to that glyph ("if more than one correspondence exists,
   then the first one is returned"). A CJK font maps a radical and the ideograph it
   is the radical of to one glyph: in Source Han Sans CN, U+2F63 and U+751F are both
   glyph 18742, U+2F45 and U+65B9 are both 14819, U+2F08 and U+4EBA are both 8966.
   The radical is the lower code point, so the reverse lookup hands back the radical,
   and that is what reaches the PDF's ToUnicode.
   
   mapGlyphsToChars now prefers the character the glyph came from, which the
   GlyphSequence already carries in its CharAssociation, wherever the substitution
   left the glyph alone - the association covers exactly one character and the
   character map maps that character to this same glyph. Anything the substitution
   did produce, a ligature or a glyph with no character of its own, still goes
   through findCharacterFromGlyphIndex as before, and a supplementary plane
   character still comes back as its surrogate pair.
   
   MultiByteFontTestCase covers all four cases against a hand-built character map
   holding the three radical/ideograph pairs above, so it needs no font installed.
   Without the fix its first case fails with the radicals for the ideographs, which
   is the defect above.
   
   🤖 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