diff --git a/fop-core/src/main/java/org/apache/fop/render/pdf/PDFPainter.java b/fop-core/src/main/java/org/apache/fop/render/pdf/PDFPainter.java index 3ac5505fc66..c6524d8de82 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pdf/PDFPainter.java +++ b/fop-core/src/main/java/org/apache/fop/render/pdf/PDFPainter.java @@ -672,7 +672,14 @@ private void drawTextWithDP(int x, int y, String text, FontTriplet triplet, double yd = (yo - yoLast) / 1000f; tu.writeTd(xd, yd); tu.writeTj(mp, tf.isMultiByte(), true); - xc += xa + pa[2]; + // Each glyph is placed by its own Td, so the Tc character spacing set above never + // reaches the next glyph as it does inside the TJ array of drawTextWithDX. The + // letter spacing is added to the advance here, for every glyph including spaces and + // the last one, which is what Tc does on the other path and what the layout's word + // space adjustment assumes (TextLayoutManager.addMappingAreas). Without it a + // letter-spaced word in a font that positions (GPOS kerning) was painted at its + // bare advances while its area kept the letter spaces. + xc += xa + pa[2] + letterSpacing; yc += ya + pa[3]; xoLast = xo; yoLast = yo; diff --git a/fop-core/src/test/java/org/apache/fop/render/pdf/PDFPainterTestCase.java b/fop-core/src/test/java/org/apache/fop/render/pdf/PDFPainterTestCase.java index bd6cf5b2488..adeb3dc2114 100644 --- a/fop-core/src/test/java/org/apache/fop/render/pdf/PDFPainterTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/render/pdf/PDFPainterTestCase.java @@ -448,6 +448,36 @@ public void testDrawDpTextWithMultiByteFont() throws IFException { + "<0001> Tj\n", output.toString()); } + /** + * The position-adjustment path places every glyph with its own Td, so the Tc it sets has no + * effect on the next glyph's position; the letter spacing has to go into the advance, as it + * does through Tc on the TJ path. Two zero-width glyphs, a kern of -100 and a letter spacing + * of 500: the second glyph sits at 400, not at -100. + */ + @Test + public void testDrawDpTextKeepsLetterSpacing() throws IFException { + StringBuilder output = new StringBuilder(); + PDFDocumentHandler pdfDocumentHandler = makePDFDocumentHandler(output); + MultiByteFont font = new MultiByteFont(null, null); + font.setWidthArray(new int[10]); + font.setCMap(new CMapSegment[]{new CMapSegment(128169, 128169, 1)}); + FontInfo fi = new FontInfo(); + fi.addFontProperties("f1", new FontTriplet("a", "normal", 400)); + fi.addMetrics("f1", font); + pdfDocumentHandler.setFontInfo(fi); + MyPDFPainter pdfPainter = new MyPDFPainter(pdfDocumentHandler, null); + pdfPainter.setFont("a", "normal", 400, null, 12, null); + int[][] dp = new int[][] {{0, 0, -100, 0}, {0, 0, 0, 0}}; + pdfPainter.drawText(0, 0, 500, 0, dp, "Hi"); + assertEquals("BT\n" + + "1 0 0 -1 0 0 Tm /f1 0.012 Tf\n" + + "0 0 Td\n" + + "<0000> Tj\n" + + "0.4 0 Td\n" + + "<0000> Tj\n", output.toString()); + verify(pdfContentGenerator).updateCharacterSpacing(0.5f); + } + private PDFDocumentHandler makePDFDocumentHandler(final StringBuilder sb) throws IFException { FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); foUserAgent = fopFactory.newFOUserAgent();