From: Glenn Adams Date: Wed, 16 Jan 2013 23:43:53 +0000 (+0000) Subject: FOP-2188: optimize string allocation in pdf output processing X-Git-Tag: fop-2_0~244 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=3a520dbe96e9ca54e9552b3f95b56edca6260884;p=xmlgraphics-fop.git FOP-2188: optimize string allocation in pdf output processing git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1434502 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/fop/pdf/PDFNumber.java b/src/java/org/apache/fop/pdf/PDFNumber.java index e638a51b1..1c31f8e9d 100644 --- a/src/java/org/apache/fop/pdf/PDFNumber.java +++ b/src/java/org/apache/fop/pdf/PDFNumber.java @@ -83,6 +83,24 @@ public class PDFNumber extends PDFObject { return buf.toString(); } + /** + * Append a double value to a string buffer suitable for PDF. + * In this method it is possible to set the maximum + * number of decimal places to output. + * + * @param doubleDown the Double value + * @param dec the number of decimal places to output + * @param buf the string buffer to which double is formatted (appended) + * @return the string buffer + */ + public static StringBuffer doubleOut(double doubleDown, int dec, StringBuffer buf) { + if (dec < 0 || dec > 16) { + throw new IllegalArgumentException("Parameter dec must be between 1 and 16"); + } + DoubleFormatUtil.formatDouble(doubleDown, dec, dec, buf); + return buf; + } + /** {@inheritDoc} */ protected String toPDFString() { if (getNumber() == null) { diff --git a/src/java/org/apache/fop/pdf/PDFStream.java b/src/java/org/apache/fop/pdf/PDFStream.java index a0b990ec5..2801d4d1f 100644 --- a/src/java/org/apache/fop/pdf/PDFStream.java +++ b/src/java/org/apache/fop/pdf/PDFStream.java @@ -40,6 +40,7 @@ public class PDFStream extends AbstractPDFStream { protected StreamCache data; private transient Writer streamWriter; + private transient char[] charBuffer; /** * Create an empty stream object @@ -89,6 +90,34 @@ public class PDFStream extends AbstractPDFStream { } } + /** + * Append data to the stream + * + * @param sb the string buffer of PDF to add + */ + public void add(StringBuffer sb) { + try { + int nHave = sb.length(); + if (charBuffer == null) { + charBuffer = new char [ nHave * 2 ]; + } else { + int nAvail = charBuffer.length; + if (nAvail < nHave) { + int nAlloc = nAvail; + while (nAlloc < nHave) { + nAlloc *= 2; + } + charBuffer = new char [ nAlloc ]; + } + } + sb.getChars(0, nHave, charBuffer, 0); + this.streamWriter.write(charBuffer, 0, nHave); + } catch (IOException ex) { + //TODO throw the exception and catch it elsewhere + ex.printStackTrace(); + } + } + private void flush() throws IOException { this.streamWriter.flush(); } diff --git a/src/java/org/apache/fop/pdf/PDFText.java b/src/java/org/apache/fop/pdf/PDFText.java index 3cddfe426..e581800e0 100644 --- a/src/java/org/apache/fop/pdf/PDFText.java +++ b/src/java/org/apache/fop/pdf/PDFText.java @@ -205,6 +205,18 @@ public class PDFText extends PDFObject { return buf.toString(); } + /** + * Convert a char to a multibyte hex representation appending to string buffer. + * Since Java always stores strings in UTF-16, we don't have to do any conversion. + * @param c character to encode + * @param sb the string buffer to append output + */ + public static final void toUnicodeHex(char c, StringBuffer sb) { + for (int i = 0; i < 4; ++i) { + sb.append(DIGITS[(c >> (12-4*i)) & 0x0F]); + } + } + /** * Escaped a String as described in section 4.4 in the PDF 1.3 specs. * @param s String to escape diff --git a/src/java/org/apache/fop/pdf/PDFTextUtil.java b/src/java/org/apache/fop/pdf/PDFTextUtil.java index ed475fcb8..1b960ebb5 100644 --- a/src/java/org/apache/fop/pdf/PDFTextUtil.java +++ b/src/java/org/apache/fop/pdf/PDFTextUtil.java @@ -70,15 +70,26 @@ public abstract class PDFTextUtil { */ protected abstract void write(String code); + /** + * Writes PDF code. + * @param code the PDF code to write + */ + protected abstract void write(StringBuffer code); + private void writeAffineTransform(AffineTransform at, StringBuffer sb) { double[] lt = new double[6]; at.getMatrix(lt); - sb.append(PDFNumber.doubleOut(lt[0], DEC)).append(" "); - sb.append(PDFNumber.doubleOut(lt[1], DEC)).append(" "); - sb.append(PDFNumber.doubleOut(lt[2], DEC)).append(" "); - sb.append(PDFNumber.doubleOut(lt[3], DEC)).append(" "); - sb.append(PDFNumber.doubleOut(lt[4], DEC)).append(" "); - sb.append(PDFNumber.doubleOut(lt[5], DEC)); + PDFNumber.doubleOut(lt[0], DEC, sb); + sb.append(' '); + PDFNumber.doubleOut(lt[1], DEC, sb); + sb.append(' '); + PDFNumber.doubleOut(lt[2], DEC, sb); + sb.append(' '); + PDFNumber.doubleOut(lt[3], DEC, sb); + sb.append(' '); + PDFNumber.doubleOut(lt[4], DEC, sb); + sb.append(' '); + PDFNumber.doubleOut(lt[5], DEC, sb); } private static void writeChar(char ch, StringBuffer sb, boolean multibyte) { @@ -90,14 +101,14 @@ public abstract class PDFTextUtil { case '(': case ')': case '\\': - sb.append("\\"); + sb.append('\\'); break; default: } sb.append(ch); } } else { - sb.append(PDFText.toUnicodeHex(ch)); + PDFText.toUnicodeHex(ch, sb); } } @@ -160,7 +171,7 @@ public abstract class PDFTextUtil { StringBuffer sb = new StringBuffer(); writeAffineTransform(at, sb); sb.append(" cm\n"); - write(sb.toString()); + write(sb); } } @@ -171,8 +182,13 @@ public abstract class PDFTextUtil { */ public void writeTf(String fontName, double fontSize) { checkInTextObject(); - write("/" + fontName + " " + PDFNumber.doubleOut(fontSize) + " Tf\n"); - + StringBuffer sb = new StringBuffer(); + sb.append('/'); + sb.append(fontName); + sb.append(' '); + PDFNumber.doubleOut(fontSize,6,sb); + sb.append(" Tf\n"); + write(sb); this.startText = useMultiByte ? "<" : "("; this.endText = useMultiByte ? ">" : ")"; } @@ -237,7 +253,7 @@ public abstract class PDFTextUtil { StringBuffer sb = new StringBuffer(); writeAffineTransform(localTransform, sb); sb.append(" Tm "); - write(sb.toString()); + write(sb); } /** @@ -249,7 +265,7 @@ public abstract class PDFTextUtil { bufTJ = new StringBuffer(); } if (bufTJ.length() == 0) { - bufTJ.append("["); + bufTJ.append('['); bufTJ.append(startText); } writeChar(codepoint, bufTJ); @@ -277,13 +293,13 @@ public abstract class PDFTextUtil { bufTJ = new StringBuffer(); } if (bufTJ.length() == 0) { - bufTJ.append("["); + bufTJ.append('['); } else { bufTJ.append(endText); - bufTJ.append(" "); + bufTJ.append(' '); } - bufTJ.append(PDFNumber.doubleOut(adjust, DEC - 4)); - bufTJ.append(" "); + PDFNumber.doubleOut(adjust, DEC - 4, bufTJ); + bufTJ.append(' '); bufTJ.append(startText); } @@ -293,8 +309,9 @@ public abstract class PDFTextUtil { */ public void writeTJ() { if (isInString()) { - bufTJ.append(endText).append("] TJ\n"); - write(bufTJ.toString()); + bufTJ.append(endText); + bufTJ.append("] TJ\n"); + write(bufTJ); bufTJ.setLength(0); } } @@ -310,11 +327,11 @@ public abstract class PDFTextUtil { */ public void writeTd ( double x, double y ) { StringBuffer sb = new StringBuffer(); - sb.append(PDFNumber.doubleOut(x, DEC)); + PDFNumber.doubleOut(x, DEC, sb); sb.append(' '); - sb.append(PDFNumber.doubleOut(y, DEC)); - sb.append ( " Td\n" ); - write ( sb.toString() ); + PDFNumber.doubleOut(y, DEC, sb); + sb.append(" Td\n"); + write(sb); } /** @@ -323,11 +340,11 @@ public abstract class PDFTextUtil { */ public void writeTj ( char ch ) { StringBuffer sb = new StringBuffer(); - sb.append ( '<' ); - writeChar ( ch, sb, true ); - sb.append ( '>' ); - sb.append ( " Tj\n" ); - write ( sb.toString() ); + sb.append('<'); + writeChar(ch, sb, true); + sb.append('>'); + sb.append(" Tj\n"); + write(sb); } } diff --git a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java index f20339078..6235ceda9 100644 --- a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java +++ b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java @@ -80,6 +80,9 @@ public class PDFContentGenerator { protected void write(String code) { currentStream.add(code); } + protected void write(StringBuffer code) { + currentStream.add(code); + } }; this.currentState = new PDFPaintingState(); diff --git a/src/java/org/apache/fop/svg/PDFTextPainter.java b/src/java/org/apache/fop/svg/PDFTextPainter.java index 299bdc22f..ef376663f 100644 --- a/src/java/org/apache/fop/svg/PDFTextPainter.java +++ b/src/java/org/apache/fop/svg/PDFTextPainter.java @@ -90,10 +90,12 @@ class PDFTextPainter extends NativeTextPainter { final PDFGraphics2D pdf = (PDFGraphics2D)g2d; PDFTextUtil textUtil = new PDFTextUtil(pdf.fontInfo) { - @Override protected void write(String code) { pdf.currentStream.write(code); } + protected void write(StringBuffer code) { + pdf.currentStream.append(code); + } }; if (DEBUG) { diff --git a/status.xml b/status.xml index 9df7abdbc..a566da0c3 100644 --- a/status.xml +++ b/status.xml @@ -59,6 +59,9 @@ documents. Example: the fix of marks layering will be such a case when it's done. --> + + Optimize string allocation in PDF output processing. + Optimize inefficient glyph processing state update operations in CS path.