summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Steiner <ssteiner@apache.org>2022-04-21 13:48:07 +0000
committerSimon Steiner <ssteiner@apache.org>2022-04-21 13:48:07 +0000
commitc2922dc45884758f516eca126e669c6e98c491e2 (patch)
tree6471307e0cc77730c1733e094494be98a8a995ca
parent1c35037f340df7ad112da5af646c878d2cf927c9 (diff)
downloadxmlgraphics-fop-c2922dc45884758f516eca126e669c6e98c491e2.tar.gz
xmlgraphics-fop-c2922dc45884758f516eca126e669c6e98c491e2.zip
FOP-2977: Array index out of bounds with glyph position adjustments and surrogate pairs
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1900111 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/GlyphMapping.java6
-rw-r--r--fop-core/src/main/java/org/apache/fop/pdf/PDFTextUtil.java2
-rw-r--r--fop-core/src/main/java/org/apache/fop/render/pdf/PDFPainter.java13
-rw-r--r--fop-core/src/test/java/org/apache/fop/render/pdf/PDFPainterTestCase.java28
4 files changed, 43 insertions, 6 deletions
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/GlyphMapping.java b/fop-core/src/main/java/org/apache/fop/fonts/GlyphMapping.java
index dce045c2c..8eedafffa 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/GlyphMapping.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/GlyphMapping.java
@@ -157,7 +157,9 @@ public class GlyphMapping {
// 6. compute word ipd based on final position adjustments.
MinOptMax ipd = MinOptMax.ZERO;
- for (int i = 0, n = mcs.length(); i < n; i++) {
+
+ // The gpa array is sized by code point count
+ for (int i = 0, cpi = 0, n = mcs.length(); i < n; i++, cpi++) {
int c = mcs.charAt(i);
if (CharUtilities.containsSurrogatePairAt(mcs, i)) {
@@ -169,7 +171,7 @@ public class GlyphMapping {
w = 0;
}
if (gpa != null) {
- w += gpa[i][GlyphPositioningTable.Value.IDX_X_ADVANCE];
+ w += gpa[cpi][GlyphPositioningTable.Value.IDX_X_ADVANCE];
}
ipd = ipd.plus(w);
}
diff --git a/fop-core/src/main/java/org/apache/fop/pdf/PDFTextUtil.java b/fop-core/src/main/java/org/apache/fop/pdf/PDFTextUtil.java
index 552864d96..6ebdfd9b6 100644
--- a/fop-core/src/main/java/org/apache/fop/pdf/PDFTextUtil.java
+++ b/fop-core/src/main/java/org/apache/fop/pdf/PDFTextUtil.java
@@ -348,7 +348,7 @@ public abstract class PDFTextUtil {
* Writes a "Tj" command with specified character code.
* @param ch character code to write
*/
- public void writeTj(char ch, boolean multibyte, boolean cid) {
+ public void writeTj(int ch, boolean multibyte, boolean cid) {
StringBuffer sb = new StringBuffer();
sb.append(startText);
writeChar(ch, sb, multibyte, cid);
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 bf5f67894..fc137c330 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
@@ -577,7 +577,14 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
tu.updateTf(fk, fsPoints, tf.isMultiByte(), true);
generator.updateCharacterSpacing(letterSpacing / 1000f);
for (int i = 0, n = text.length(); i < n; i++) {
- char ch = text.charAt(i);
+ int ch = text.charAt(i);
+ int mp;
+ if (CharUtilities.containsSurrogatePairAt(text, i)) {
+ ch = Character.toCodePoint((char) ch, text.charAt(++i));
+ mp = f.mapCodePoint(ch);
+ } else {
+ mp = f.mapChar((char)ch);
+ }
int[] pa = ((i >= dp.length) || (dp[i] == null)) ? paZero : dp[i];
double xo = xc + pa[0];
double yo = yc + pa[1];
@@ -586,7 +593,7 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
double xd = (xo - xoLast) / 1000f;
double yd = (yo - yoLast) / 1000f;
tu.writeTd(xd, yd);
- tu.writeTj(f.mapChar(ch), tf.isMultiByte(), true);
+ tu.writeTj(mp, tf.isMultiByte(), true);
xc += xa + pa[2];
yc += ya + pa[3];
xoLast = xo;
@@ -596,7 +603,7 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
}
}
- private double maybeWordOffsetX(double wox, char ch, Direction dir) {
+ private double maybeWordOffsetX(double wox, int ch, Direction dir) {
if ((wox != 0)
&& CharUtilities.isAdjustableSpace(ch)
&& ((dir == null) || dir.isHorizontal())) {
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 9fe1972a1..41747c72d 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
@@ -54,6 +54,7 @@ import org.apache.fop.apps.FopFactory;
import org.apache.fop.events.Event;
import org.apache.fop.events.EventListener;
import org.apache.fop.fo.Constants;
+import org.apache.fop.fonts.CMapSegment;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.MultiByteFont;
@@ -243,6 +244,33 @@ public class PDFPainterTestCase {
assertEquals("BT\n/f1 0.012 Tf\n1 0 0 -1 0 0 Tm [<" + expectedHex + ">] TJ\n", output.toString());
}
+ @Test
+ public void testDrawDpTextWithMultiByteFont() throws IFException {
+ StringBuilder output = new StringBuilder();
+ PDFDocumentHandler pdfDocumentHandler = makePDFDocumentHandler(output);
+ String text = "Hi\uD83D\uDCA9";
+ 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[1][0];
+ dp[0] = new int[]{0, 1, 2, 3};
+ pdfPainter.drawText(0, 0, 0, 0, dp, text);
+ assertEquals("BT\n"
+ + "1 0 0 -1 0 0 Tm /f1 0.012 Tf\n"
+ + "0 0.001 Td\n"
+ + "<0000> Tj\n"
+ + "0.002 0.002 Td\n"
+ + "<0000> Tj\n"
+ + "0 0 Td\n"
+ + "<0001> Tj\n", output.toString());
+ }
+
private PDFDocumentHandler makePDFDocumentHandler(final StringBuilder sb) throws IFException {
FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
foUserAgent = fopFactory.newFOUserAgent();