Jason Harrop created FOP-3344:
---------------------------------
Summary: letter-spacing is not painted on text that carries glyph
position adjustments (GPOS kerning): the word is drawn at its bare advances
inside an area that keeps the letter spaces
Key: FOP-3344
URL: https://issues.apache.org/jira/browse/FOP-3344
Project: FOP
Issue Type: Bug
Components: renderer/pdf
Affects Versions: 2.11
Reporter: Jason Harrop
PDFPainter.drawText takes one of two paths. With no position adjustments, or
adjustments that are DX-only, drawTextWithDX writes the word as one TJ array
and sets Tc to the letter spacing, which the PDF viewer adds after every glyph.
With general adjustments (a GPOS kern produces an x-advance adjustment, so
IFUtil.isDPOnlyDX is false), drawTextWithDP writes each glyph with its own Td
and Tj and advances by
{noformat}
xc += xa + pa[2];
{noformat}
that is, the glyph width plus the advance adjustment. It sets 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 reaches the next glyph.
The layout side is consistent with the first path. TextLayoutManager puts the
letter spaces into the word's Knuth elements and the TextArea, 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" (its own comment). So a letter-spaced word in a font that
positions is measured with its letter spaces and painted without them, and the
gap to the next word absorbs the difference: negative letter spacing opens the
gap, positive closes it, to the point of overprinting.
Reproducer: Arimo (or any font whose GPOS kern applies; Liberation, DejaVu
Serif, Noto), kerning="true", 11pt,
{noformat}
<fo:block font-family="Arimo">During <fo:inline
letter-spacing="-0.417pt">repair,</fo:inline> if however</fo:block>
{noformat}
Per-glyph steps read back with mutool draw -F stext, 2.11:
{noformat}
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
{noformat}
Every step is the bare advance (r>, carries the kern), and the space after the
comma is 2.5 pt narrower than the same text without kerning, where the steps
are 3.246 5.699 5.699 5.699 2.025 3.246 and the gap 5.549. On the docx4j corpus
the collapsed gap made pdftotext read "repair, if" as "repair,if"; with
positive letter spacing the words overprint.
h3. Fix
PDFPainter.drawTextWithDP: add the letter spacing to the advance of every
glyph, spaces and the last glyph included, which is what Tc does on the other
path and what the layout's word-space adjustment assumes:
{noformat}
xc += xa + pa[2] + letterSpacing;
{noformat}
Java2DPainter and PCLPainter already add letterSpacing per glyph in their dp
loops; PSPainter applies it through ATJ; AFPPainter converts dp to dx. Only the
PDF painter was missing it.
After the fix, same sample: 3.246 5.699 5.699 5.699 2.025 2.641, gap 5.549; the
last step is the advance less the letter spacing less the kern.
Test: PDFPainterTestCase.testDrawDpTextKeepsLetterSpacing, two zero-width
glyphs with a kern of -100 and a letter spacing of 500; the second glyph's Td
must be 0.4, not -0.1.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)