]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
FOP-2188: optimize string allocation in pdf output processing
authorGlenn Adams <gadams@apache.org>
Wed, 16 Jan 2013 23:43:53 +0000 (23:43 +0000)
committerGlenn Adams <gadams@apache.org>
Wed, 16 Jan 2013 23:43:53 +0000 (23:43 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1434502 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/fop/pdf/PDFNumber.java
src/java/org/apache/fop/pdf/PDFStream.java
src/java/org/apache/fop/pdf/PDFText.java
src/java/org/apache/fop/pdf/PDFTextUtil.java
src/java/org/apache/fop/render/pdf/PDFContentGenerator.java
src/java/org/apache/fop/svg/PDFTextPainter.java
status.xml

index e638a51b1ecd93ba4e00f13de891394ec4b6a49d..1c31f8e9dfb76bf2cec82f06d120afb79dbeaf13 100644 (file)
@@ -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) {
index a0b990ec5a18746a13d4cf1f74f2d9dd75deda16..2801d4d1f8664d985105aa25eea48a1aa1fe287b 100644 (file)
@@ -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();
     }
index 3cddfe4267f0b53bd901ed22522c0619fa84c246..e581800e0d5c63972122f8b55de4d6533e14009c 100644 (file)
@@ -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
index ed475fcb84a7ff6661bc7db9d2c1ac4c699179fb..1b960ebb5af4813b4c581ba3950127edd23c5baf 100644 (file)
@@ -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);
     }
 
 }
index f2033907894e7f0fc59ba8ff597be3f8d345e058..6235ceda9de375270a74c3a7b844a3049047b69a 100644 (file)
@@ -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();
index 299bdc22f0bc3940dbb426644ad378bb1bde954a..ef376663fb961ed0945415f20bfacf1429b2c11a 100644 (file)
@@ -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) {
index 9df7abdbc30c5368d5723ef36697805f2e4026ae..a566da0c3d3c19c1ead9d460ed48fe9bb0dc9076 100644 (file)
@@ -59,6 +59,9 @@
       documents. Example: the fix of marks layering will be such a case when it's done.
     -->
     <release version="FOP Trunk" date="TBD">
+      <action context="Renderers" dev="GA" type="fix" fixes-bug="FOP-2188">
+       Optimize string allocation in PDF output processing.
+      </action>
       <action context="Renderers" dev="GA" type="fix" fixes-bug="FOP-2186">
        Optimize inefficient glyph processing state update operations in CS path.
       </action>