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)

Reply via email to