Skip to content

FOP-3344: letter-spacing is painted on text that carries glyph position adjustments - #113

Open
plutext wants to merge 1 commit into
apache:mainfrom
plutext:FOP-3344
Open

plutext wants to merge 1 commit into
apache:mainfrom
plutext:FOP-3344

Conversation

@plutext

@plutext plutext commented Oct 2, 2026

Copy link
Copy Markdown

Fixes FOP-3344.

PDFPainter.drawText takes one of two paths. With no position adjustments, or DX-only ones,
drawTextWithDX writes the word as one TJ array and sets Tc to the letter spacing, which the
viewer adds after every glyph. With general adjustments (a GPOS kern is an x-advance
adjustment, so IFUtil.isDPOnlyDX is false) drawTextWithDP writes each glyph with its own Td
and Tj and advanced by the glyph width plus the adjustment. It set Tc too, but Tc acts only
between glyphs inside a TJ array; with one glyph per Tj and an explicit Td before each, the
letter spacing never reached the next glyph.

The layout is consistent with the first path: TextLayoutManager puts the letter spaces into
the word's elements and its area, and addMappingAreas computes the word-space adjustment on
the assumption that the renderer adds the character spacing "even to the last character of
a word and to space characters". So a letter-spaced word in a font that positions was
measured with its letter spaces and painted without them, and the gap to the next word
absorbed the difference: negative letter spacing opens the gap, positive closes it, to the
point of overprinting.

The letter spacing is now added to the advance on this path, for every glyph, spaces and
the last one included, which is what Tc does on the other. Java2DPainter and PCLPainter
already add it per glyph in their dp loops, PSPainter applies it through ATJ, AFPPainter
converts dp to dx; only the PDF painter was missing it.

Measured on this branch, Arimo 11pt, kerning on,
"During <fo:inline letter-spacing="-0.417pt">repair,</fo:inline> if however", per-glyph
steps read back with mutool draw -F stext:

  before   r>e 3.663 e>p 6.116 p>a 6.116 a>i 6.116 i>r 2.442 r>, 3.058   comma>space 3.047
  after    r>e 3.246 e>p 5.699 p>a 5.699 a>i 5.699 i>r 2.025 r>, 2.641   comma>space 5.549

After: each step is the advance less 0.417, and r>, carries the kern (-55/1000 em) too.
PDFPainterTestCase.testDrawDpTextKeepsLetterSpacing: two zero-width glyphs, a kern of -100
and a letter spacing of 500; the second Td must be 0.4, not -0.1.

🤖 Generated with Claude Code

…on adjustments

PDFPainter.drawText takes one of two paths. With no position adjustments, or DX-only ones,
drawTextWithDX writes the word as one TJ array and sets Tc to the letter spacing, which the
viewer adds after every glyph. With general adjustments (a GPOS kern is an x-advance
adjustment, so IFUtil.isDPOnlyDX is false) drawTextWithDP writes each glyph with its own Td
and Tj and advanced by the glyph width plus the adjustment. It set Tc too, but Tc acts only
between glyphs inside a TJ array; with one glyph per Tj and an explicit Td before each, the
letter spacing never reached the next glyph.

The layout is consistent with the first path: TextLayoutManager puts the letter spaces into
the word's elements and its area, and addMappingAreas computes the word-space adjustment on
the assumption that the renderer adds the character spacing "even to the last character of
a word and to space characters". So a letter-spaced word in a font that positions was
measured with its letter spaces and painted without them, and the gap to the next word
absorbed the difference: negative letter spacing opens the gap, positive closes it, to the
point of overprinting.

The letter spacing is now added to the advance on this path, for every glyph, spaces and
the last one included, which is what Tc does on the other. Java2DPainter and PCLPainter
already add it per glyph in their dp loops, PSPainter applies it through ATJ, AFPPainter
converts dp to dx; only the PDF painter was missing it.

Measured on this branch, Arimo 11pt, kerning on,
"During <fo:inline letter-spacing="-0.417pt">repair,</fo:inline> if however", per-glyph
steps read back with mutool draw -F stext:

  before   r>e 3.663 e>p 6.116 p>a 6.116 a>i 6.116 i>r 2.442 r>, 3.058   comma>space 3.047
  after    r>e 3.246 e>p 5.699 p>a 5.699 a>i 5.699 i>r 2.025 r>, 2.641   comma>space 5.549

After: each step is the advance less 0.417, and r>, carries the kern (-55/1000 em) too.
PDFPainterTestCase.testDrawDpTextKeepsLetterSpacing: two zero-width glyphs, a kern of -100
and a letter spacing of 500; the second Td must be 0.4, not -0.1.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant