PDFBOX-5143: reuse Type2CharStringParser instead of recreating it for every char

git-svn-id: https://svn.apache.org/repos/asf/pdfbox/trunk@1892942 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/fontbox/src/main/java/org/apache/fontbox/cff/CFFCIDFont.java b/fontbox/src/main/java/org/apache/fontbox/cff/CFFCIDFont.java
index a23797f..695856d 100644
--- a/fontbox/src/main/java/org/apache/fontbox/cff/CFFCIDFont.java
+++ b/fontbox/src/main/java/org/apache/fontbox/cff/CFFCIDFont.java
@@ -21,6 +21,7 @@
 import java.io.IOException;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import org.apache.fontbox.type1.Type1CharStringReader;
@@ -43,6 +44,7 @@
 
     private final Map<Integer, CIDKeyedType2CharString> charStringCache =
             new ConcurrentHashMap<>();
+    private Type2CharStringParser charStringParser = null;
 
     private final PrivateType1CharStringReader reader = new PrivateType1CharStringReader();
 
@@ -232,8 +234,8 @@
             {
                 bytes = charStrings[0]; // .notdef
             }
-            Type2CharStringParser parser = new Type2CharStringParser(getName(), cid);
-            List<Object> type2seq = parser.parse(bytes, globalSubrIndex, getLocalSubrIndex(gid));
+            List<Object> type2seq = getParser().parse(bytes, globalSubrIndex,
+                    getLocalSubrIndex(gid), String.format(Locale.US, "%04x", cid));
             type2 = new CIDKeyedType2CharString(reader, getName(), cid, gid, type2seq,
                                                 getDefaultWidthX(gid), getNominalWidthX(gid));
             charStringCache.put(cid, type2);
@@ -241,6 +243,15 @@
         return type2;
     }
 
+    private Type2CharStringParser getParser()
+    {
+        if (charStringParser == null)
+        {
+            charStringParser = new Type2CharStringParser(getName());
+        }
+        return charStringParser;
+    }
+
     @Override
     public GeneralPath getPath(String selector) throws IOException
     {
diff --git a/fontbox/src/main/java/org/apache/fontbox/cff/CFFType1Font.java b/fontbox/src/main/java/org/apache/fontbox/cff/CFFType1Font.java
index 55e2283..43b68b0 100644
--- a/fontbox/src/main/java/org/apache/fontbox/cff/CFFType1Font.java
+++ b/fontbox/src/main/java/org/apache/fontbox/cff/CFFType1Font.java
@@ -40,6 +40,7 @@
             new ConcurrentHashMap<>();
 
     private final PrivateType1CharStringReader reader = new PrivateType1CharStringReader();
+    private Type2CharStringParser charStringParser = null;
 
     private int defaultWidthX = Integer.MIN_VALUE;
     private int nominalWidthX = Integer.MIN_VALUE;
@@ -135,8 +136,8 @@
                 // .notdef
                 bytes = charStrings[0];
             }
-            Type2CharStringParser parser = new Type2CharStringParser(getName(), name);
-            List<Object> type2seq = parser.parse(bytes, globalSubrIndex, getLocalSubrIndex());
+            List<Object> type2seq = getParser().parse(bytes, globalSubrIndex, getLocalSubrIndex(),
+                    name);
             type2 = new Type2CharString(reader, getName(), name, gid, type2seq, getDefaultWidthX(),
                     getNominalWidthX());
             charStringCache.put(gid, type2);
@@ -144,6 +145,15 @@
         return type2;
     }
 
+    private Type2CharStringParser getParser()
+    {
+        if (charStringParser == null)
+        {
+            charStringParser = new Type2CharStringParser(getName());
+        }
+        return charStringParser;
+    }
+
     /**
      * Returns the private dictionary.
      *
diff --git a/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java b/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java
index b5c01fd..1e82192 100644
--- a/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java
+++ b/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java
@@ -19,7 +19,6 @@
 import java.io.IOException;

 import java.util.ArrayList;

 import java.util.List;

-import java.util.Locale;

 

 import org.apache.fontbox.cff.CharStringCommand.Type2KeyWord;

 

@@ -29,7 +28,6 @@
  */

 public class Type2CharStringParser

 {

-

     // 1-byte commands

     private static final int CALLSUBR = 10;

     private static final int CALLGSUBR = 29;

@@ -37,33 +35,17 @@
     private int hstemCount;

     private int vstemCount;

     private final List<Object> sequence = new ArrayList<>();

-    @SuppressWarnings("unused")

     private final String fontName;

-    @SuppressWarnings("unused")

-    private final String glyphName;

+    private String currentGlyph;

 

     /**

      * Constructs a new Type1CharStringParser object for a Type 1-equivalent font.

      *

      * @param fontName font name

-     * @param glyphName glyph name

      */

-    public Type2CharStringParser(String fontName, String glyphName)

+    public Type2CharStringParser(String fontName)

     {

         this.fontName = fontName;

-        this.glyphName = glyphName;

-    }

-

-    /**

-     * Constructs a new Type1CharStringParser object for a CID-Keyed font.

-     *

-     * @param fontName font name

-     * @param cid CID

-     */

-    public Type2CharStringParser(String fontName, int cid)

-    {

-        this.fontName = fontName;

-        this.glyphName = String.format(Locale.US, "%04x", cid); // for debugging only

     }

 

     /**

@@ -75,12 +57,14 @@
      * @return the Type2 sequence

      * @throws IOException if an error occurs during reading

      */

-    public List<Object> parse(byte[] bytes, byte[][] globalSubrIndex, byte[][] localSubrIndex) throws IOException

+    public List<Object> parse(byte[] bytes, byte[][] globalSubrIndex, byte[][] localSubrIndex,

+            String glyphName) throws IOException

     {

         // reset values if the parser is used multiple times

         hstemCount = 0;

         vstemCount = 0;

         sequence.clear();

+        currentGlyph = glyphName;

         return parseSequence(bytes, globalSubrIndex, localSubrIndex);

     }

 

@@ -126,7 +110,7 @@
         if (subrNumber < localSubrIndex.length)

         {

             byte[] subrBytes = localSubrIndex[subrNumber];

-            parse(subrBytes, globalSubrIndex, localSubrIndex);

+            parseSequence(subrBytes, globalSubrIndex, localSubrIndex);

             Object lastItem = sequence.get(sequence.size() - 1);

             if (lastItem instanceof CharStringCommand

                     && Type2KeyWord.RET == ((CharStringCommand) lastItem).getType2KeyWord())

@@ -145,7 +129,7 @@
         if (subrNumber < globalSubrIndex.length)

         {

             byte[] subrBytes = globalSubrIndex[subrNumber];

-            parse(subrBytes, globalSubrIndex, localSubrIndex);

+            parseSequence(subrBytes, globalSubrIndex, localSubrIndex);

             Object lastItem = sequence.get(sequence.size() - 1);

             if (lastItem instanceof CharStringCommand

                     && Type2KeyWord.RET == ((CharStringCommand) lastItem).getType2KeyWord())

@@ -262,4 +246,10 @@
         }

         return count;

     }

+

+    @Override

+    public String toString()

+    {

+        return fontName + ", current glpyh " + currentGlyph;

+    }

 }