Index: fontbox/src/main/java/org/apache/fontbox/cff/AFMFormatter.java
===================================================================
--- fontbox/src/main/java/org/apache/fontbox/cff/AFMFormatter.java	(revision 1555455)
+++ fontbox/src/main/java/org/apache/fontbox/cff/AFMFormatter.java	(working copy)
@@ -116,16 +116,14 @@
     private static List<CharMetric> renderFont(CFFFont font) throws IOException
     {
         List<CharMetric> metrics = new ArrayList<CharMetric>();
-        CharStringRenderer renderer = font.createRenderer();
         Collection<CFFFont.Mapping> mappings = font.getMappings();
         for (CFFFont.Mapping mapping : mappings)
         {
             CharMetric metric = new CharMetric();
             metric.code = mapping.getCode();
             metric.name = mapping.getName();
-            renderer.render(mapping.toType1Sequence());
-            metric.width = renderer.getWidth();
-            metric.bounds = renderer.getBounds();
+            metric.width = mapping.getType1CharString().getWidth();
+            metric.bounds = mapping.getType1CharString().getBounds();
             metrics.add(metric);
         }
         return metrics;
Index: fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java
===================================================================
--- fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java	(revision 1555455)
+++ fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java	(working copy)
@@ -17,13 +17,7 @@
 package org.apache.fontbox.cff;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import org.apache.fontbox.cff.charset.CFFCharset;
 import org.apache.fontbox.cff.encoding.CFFEncoding;
@@ -32,11 +26,10 @@
  * This class represents a CFF/Type2 Font.
  * 
  * @author Villu Ruusmann
- * 
+ * @author John Hewson
  */
 public class CFFFont
 {
-
     private String fontname = null;
     private Map<String, Object> topDict = new LinkedHashMap<String, Object>();
     private Map<String, Object> privateDict = new LinkedHashMap<String, Object>();
@@ -45,6 +38,7 @@
     private Map<String, byte[]> charStringsDict = new LinkedHashMap<String, byte[]>();
     private IndexData globalSubrIndex = null;
     private IndexData localSubrIndex = null;
+    private Map<String, Type2CharString> charStringCache = new HashMap<String, Type2CharString>();
 
     /**
      * The name of the font.
@@ -220,44 +214,25 @@
     /**
      * Return the Width value of the given Glyph identifier.
      * 
-     * @param SID
+     * @param sid SID
      * @return -1 if the SID is missing from the Font.
      * @throws IOException if something went wrong
      * 
      */
-    public int getWidth(int SID) throws IOException
+    public int getWidth(int sid) throws IOException
     {
-        int nominalWidth = privateDict.containsKey("nominalWidthX") ? ((Number) privateDict.get("nominalWidthX"))
-                .intValue() : 0;
-        int defaultWidth = privateDict.containsKey("defaultWidthX") ? ((Number) privateDict.get("defaultWidthX"))
-                .intValue() : 1000;
-
         for (Mapping m : getMappings())
         {
-            if (m.getSID() == SID)
+            if (m.getSID() == sid)
             {
-
-                CharStringRenderer csr = null;
-                if (((Number) getProperty("CharstringType")).intValue() == 2)
-                {
-                    List<Object> lSeq = m.toType2Sequence();
-                    csr = new CharStringRenderer(false);
-                    csr.render(lSeq);
-                }
-                else
-                {
-                    List<Object> lSeq = m.toType1Sequence();
-                    csr = new CharStringRenderer();
-                    csr.render(lSeq);
-                }
-
-                // ---- If the CharString has a Width nominalWidthX must be added,
-                // otherwise it is the default width.
-                return csr.getWidth() != 0 ? csr.getWidth() + nominalWidth : defaultWidth;
+                Type1CharString charstring = m.getType1CharString();
+                return charstring.getWidth();
             }
         }
 
-        // ---- SID Width not found, return the nodef width
+        // SID not found, return the nodef width
+        int nominalWidth = getNominalWidthX(sid);
+        int defaultWidth = getDefaultWidthX(sid);
         return getNotDefWidth(defaultWidth, nominalWidth);
     }
 
@@ -271,23 +246,8 @@
      */
     protected int getNotDefWidth(int defaultWidth, int nominalWidth) throws IOException
     {
-        CharStringRenderer csr;
-        byte[] glyphDesc = this.getCharStringsDict().get(".notdef");
-        if (((Number) getProperty("CharstringType")).intValue() == 2)
-        {
-            Type2CharStringParser parser = new Type2CharStringParser();
-            List<Object> lSeq = parser.parse(glyphDesc, getGlobalSubrIndex(), getLocalSubrIndex());
-            csr = new CharStringRenderer(false);
-            csr.render(lSeq);
-        }
-        else
-        {
-            Type1CharStringParser parser = new Type1CharStringParser();
-            List<Object> lSeq = parser.parse(glyphDesc, getLocalSubrIndex());
-            csr = new CharStringRenderer();
-            csr.render(lSeq);
-        }
-        return csr.getWidth() != 0 ? csr.getWidth() + nominalWidth : defaultWidth;
+        Type1CharString charstring = getType1CharString(".notdef");
+        return charstring.getWidth() != 0 ? charstring.getWidth() + nominalWidth : defaultWidth;
     }
 
     /**
@@ -331,6 +291,25 @@
     }
 
     /**
+     * Returns the SID for a given glyph name
+     * @param name glyph name
+     * @return SID
+     */
+    private int getSIDForName(String name)
+    {
+        int sid = 0; // .notdef
+        for (Mapping m : getMappings())
+        {
+            if (m.getName().equals(name))
+            {
+                sid = m.getSID();
+                break;
+            }
+        }
+      return sid;
+    }
+
+    /**
      * Returns the character strings dictionary.
      * 
      * @return the dictionary
@@ -341,28 +320,66 @@
     }
 
     /**
-     * Creates a CharStringConverter for this font.
-     * 
-     * @return the new CharStringConverter
+     * Returns the Type 1 CharString for the character with the given name
+     *
+     * @return Type 1 CharString
      */
-    public CharStringConverter createConverter()
+    public Type1CharString getType1CharString(String name) throws IOException
     {
-        Number defaultWidthX = (Number) getProperty("defaultWidthX");
-        Number nominalWidthX = (Number) getProperty("nominalWidthX");
-        return new CharStringConverter(defaultWidthX.intValue(), nominalWidthX.intValue());
+        return getType1CharString(name, getSIDForName(name));
     }
 
     /**
-     * Creates a CharStringRenderer for this font.
-     * 
-     * @return the new CharStringRenderer
+     * Returns the Type 1 CharString for the character with the given name and SID
+     *
+     * @return Type 1 CharString
      */
-    public CharStringRenderer createRenderer()
+    private Type1CharString getType1CharString(String name, int sid) throws IOException
     {
-        return new CharStringRenderer();
+        Type2CharString type2 = charStringCache.get(name);
+        if (type2 == null)
+        {
+            Type2CharStringParser parser = new Type2CharStringParser();
+            List<Object> type2seq = parser.parse(charStringsDict.get(name), globalSubrIndex, localSubrIndex);
+            type2 = new Type2CharString(this, type2seq, getDefaultWidthX(sid), getNominalWidthX(sid));
+            charStringCache.put(name, type2);
+        }
+        return type2;
     }
 
     /**
+     * Returns the defaultWidthX for the given SID
+     *
+     * @param sid SID
+     * @return defaultWidthX
+     */
+    protected int getDefaultWidthX(int sid)
+    {
+        Number num = (Number)getProperty("defaultWidthX");
+        if (num == null)
+        {
+            return 1000;
+        }
+        return num.intValue();
+    }
+
+    /**
+     * Returns the nominalWidthX for the given SID
+     *
+     * @param sid SID
+     * @return defaultWidthX
+     */
+    protected int getNominalWidthX(int sid)
+    {
+        Number num = (Number)getProperty("nominalWidthX");
+        if (num == null)
+        {
+            return 0;
+        }
+        return num.intValue();
+    }
+
+    /**
      * {@inheritDoc}
      */
     public String toString()
@@ -414,7 +431,6 @@
 
     /**
      * This class is used for the font mapping.
-     * 
      */
     public class Mapping
     {
@@ -424,30 +440,17 @@
         private byte[] mappedBytes;
 
         /**
-         * Converts the mapping into a Type1-sequence.
-         * 
-         * @return the Type1-sequence
+         * Returns the Type 1 CharString for the character.
+         *
+         * @return the Type 1 CharString
          * @throws IOException if an error occurs during reading
          */
-        public List<Object> toType1Sequence() throws IOException
+        public Type1CharString getType1CharString() throws IOException
         {
-            CharStringConverter converter = createConverter();
-            return converter.convert(toType2Sequence());
+            return CFFFont.this.getType1CharString(mappedName, mappedSID);
         }
 
         /**
-         * Converts the mapping into a Type2-sequence.
-         * 
-         * @return the Type2-sequence
-         * @throws IOException if an error occurs during reading
-         */
-        public List<Object> toType2Sequence() throws IOException
-        {
-            Type2CharStringParser parser = new Type2CharStringParser();
-            return parser.parse(getBytes(), getGlobalSubrIndex(), getLocalSubrIndex());
-        }
-
-        /**
          * Gets the value for the code.
          * 
          * @return the code
Index: fontbox/src/main/java/org/apache/fontbox/cff/CFFFontROS.java
===================================================================
--- fontbox/src/main/java/org/apache/fontbox/cff/CFFFontROS.java	(revision 1555455)
+++ fontbox/src/main/java/org/apache/fontbox/cff/CFFFontROS.java	(working copy)
@@ -22,7 +22,14 @@
 import java.util.List;
 import java.util.Map;
 
-public class CFFFontROS extends CFFFont {
+/**
+ * This class represents a CID-Keyed CFF/Type2 Font.
+ *
+ * @author Villu Ruusmann
+ * @author John Hewson
+ */
+public class CFFFontROS extends CFFFont
+{
 	private String registry;
 	private String ordering;
 	private int supplement;
@@ -41,7 +48,7 @@
 
 	/**
 	 * Sets the registry value.
-	 * 
+	 *
 	 * @param registry the registry to set
 	 */
 	public void setRegistry(String registry) {
@@ -50,7 +57,7 @@
 
 	/**
 	 * Returns the ordering value.
-	 * 
+	 *
 	 * @return the ordering
 	 */
 	public String getOrdering() {
@@ -59,7 +66,7 @@
 
 	/**
 	 * Sets the ordering value.
-	 * 
+	 *
 	 * @param ordering the ordering to set
 	 */
 	public void setOrdering(String ordering) {
@@ -68,7 +75,7 @@
 
 	/**
 	 * Returns the supplement value.
-	 * 
+	 *
 	 * @return the supplement
 	 */
 	public int getSupplement() {
@@ -77,7 +84,7 @@
 
 	/**
 	 * Sets the supplement value.
-	 * 
+	 *
 	 * @param supplement the supplement to set
 	 */
 	public void setSupplement(int supplement) {
@@ -86,7 +93,7 @@
 
 	/**
 	 * Returns the font dictionaries.
-	 * 
+	 *
 	 * @return the fontDict
 	 */
 	public List<Map<String, Object>> getFontDict() {
@@ -95,7 +102,7 @@
 
 	/**
 	 * Sets the font dictionaries.
-	 * 
+	 *
 	 * @param fontDict the fontDict to set
 	 */
 	public void setFontDict(List<Map<String, Object>> fontDict) {
@@ -104,7 +111,7 @@
 
 	/**
 	 * Returns the private dictionary.
-	 * 
+	 *
 	 * @return the privDict
 	 */
 	public List<Map<String, Object>> getPrivDict() {
@@ -113,7 +120,7 @@
 
 	/**
 	 * Sets the private dictionary.
-	 * 
+	 *
 	 * @param privDict the privDict to set
 	 */
 	public void setPrivDict(List<Map<String, Object>> privDict) {
@@ -122,7 +129,7 @@
 
 	/**
 	 * Returns the fdSelect value.
-	 * 
+	 *
 	 * @return the fdSelect
 	 */
 	public CIDKeyedFDSelect getFdSelect() {
@@ -131,7 +138,7 @@
 
 	/**
 	 * Sets the fdSelect value.
-	 * 
+	 *
 	 * @param fdSelect the fdSelect to set
 	 */
 	public void setFdSelect(CIDKeyedFDSelect fdSelect) {
@@ -140,50 +147,74 @@
 
 	/**
 	 * Returns the Width value of the given Glyph identifier
-	 * 
-	 * @param CID
-	 * @return -1 if the SID is missing from the Font.
+	 *
+	 * @param cid CID
+	 * @return -1 if the CID is missing from the Font.
 	 * @throws IOException
 	 */
-	public int getWidth(int CID) throws IOException {
-		// ---- search the right FDArray index in the FDSelect according to the Character identifier
-		// 		this index will be used to access the private dictionary which contains useful values 
-		//		to compute width.
-		int fdArrayIndex = this.fdSelect.getFd(CID);
-		if (fdArrayIndex == -1 && CID == 0 ) { // --- notdef char
-			return super.getWidth(CID);
-		} else if (fdArrayIndex == -1) {
-			return 1000;
-		}
-		
-		Map<String, Object> fontDict = this.fontDictionaries.get(fdArrayIndex);
-		Map<String, Object> privDict = this.privateDictionaries.get(fdArrayIndex);
+  public int getWidth(int cid) throws IOException
+  {
+      // search the right FDArray index in the FDSelect according to the Character identifier
+      // this index will be used to access the private dictionary which contains useful values
+      // to compute width.
+      int fdArrayIndex = this.fdSelect.getFd(cid);
+      if (fdArrayIndex == -1 && cid == 0 ) // notdef char
+      {
+        return super.getWidth(cid);
+      }
+      else if (fdArrayIndex == -1)
+      {
+        return 1000;
+      }
+      Map<String, Object> fontDict = this.fontDictionaries.get(fdArrayIndex);
+      Map<String, Object> privDict = this.privateDictionaries.get(fdArrayIndex);
 
-		int nominalWidth = privDict.containsKey("nominalWidthX") ? ((Number)privDict.get("nominalWidthX")).intValue() : 0;
-		int defaultWidth = privDict.containsKey("defaultWidthX") ? ((Number)privDict.get("defaultWidthX")).intValue() : 1000 ;
+      for (Mapping m : getMappings())
+      {
+          if (m.getSID() == cid)
+          {
+              Type1CharString charstring = m.getType1CharString();
+              return charstring.getWidth();
+          }
+      }
 
-		for (Mapping m : getMappings() ){
-			if (m.getSID() == CID) {
+      // CID not found, return the notdef width
+      int nominalWidth = getNominalWidthX(cid);
+      int defaultWidth = getDefaultWidthX(cid);
+      return getNotDefWidth(defaultWidth, nominalWidth);
+  }
 
-				CharStringRenderer csr = null;
-				Number charStringType = (Number)getProperty("CharstringType");
-				if ( charStringType.intValue() == 2 ) {
-					List<Object> lSeq = m.toType2Sequence();
-					csr = new CharStringRenderer(false);
-					csr.render(lSeq);
-				} else {
-					List<Object> lSeq = m.toType1Sequence();
-					csr = new CharStringRenderer();
-					csr.render(lSeq);
-				}
+  /**
+   * Returns the defaultWidthX for the given CID
+   *
+   * @param cid CID
+   * @return defaultWidthX
+   */
+  protected int getDefaultWidthX(int cid)
+  {
+      int fdArrayIndex = this.fdSelect.getFd(cid);
+      if (fdArrayIndex == -1)
+      {
+          return 1000;
+      }
+      Map<String, Object> privDict = this.privateDictionaries.get(fdArrayIndex);
+      return privDict.containsKey("defaultWidthX") ? ((Number)privDict.get("defaultWidthX")).intValue() : 1000;
+  }
 
-				// ---- If the CharString has a Width nominalWidthX must be added, 
-				//	    otherwise it is the default width.
-				return csr.getWidth() != 0 ? csr.getWidth() + nominalWidth : defaultWidth;
-			}
-		}
-
-		// ---- CID Width not found, return the notdef width
-		return getNotDefWidth(defaultWidth, nominalWidth);
-	}
-}
+  /**
+   * Returns the nominalWidthX for the given CID
+   *
+   * @param cid CID
+   * @return defaultWidthX
+   */
+  protected int getNominalWidthX(int cid)
+  {
+      int fdArrayIndex = this.fdSelect.getFd(cid);
+      if (fdArrayIndex == -1)
+      {
+          return 0;
+      }
+      Map<String, Object> privDict = this.privateDictionaries.get(fdArrayIndex);
+      return privDict.containsKey("nominalWidthX") ? ((Number)privDict.get("nominalWidthX")).intValue() : 0;
+  }
+}
\ No newline at end of file
Index: fontbox/src/main/java/org/apache/fontbox/cff/CharStringHandler.java
===================================================================
--- fontbox/src/main/java/org/apache/fontbox/cff/CharStringHandler.java	(revision 1555455)
+++ fontbox/src/main/java/org/apache/fontbox/cff/CharStringHandler.java	(working copy)
@@ -21,24 +21,22 @@
 
 /**
  * A Handler for CharStringCommands.
- * 
+ *
  * @author Villu Ruusmann
  * @version $Revision$
  */
 public abstract class CharStringHandler
 {
-
     /**
      * Handler for a sequence of CharStringCommands.
-     * 
+     *
      * @param sequence of CharStringCommands
-     * 
+     *
      * @return may return a command sequence of a subroutine
      */
     @SuppressWarnings(value = { "unchecked" })
-    public List<Integer> handleSequence(List<Object> sequence)
+    public void handleSequence(List<Object> sequence)
     {
-        List<Integer> numbers = null;
         int offset = 0;
         int size = sequence.size();
         for (int i = 0; i < size; i++)
@@ -46,30 +44,18 @@
             Object object = sequence.get(i);
             if (object instanceof CharStringCommand)
             {
-                if (numbers == null)
-                    numbers = (List) sequence.subList(offset, i);
-                else 
-                    numbers.addAll((List) sequence.subList(offset, i));
-                List<Integer> stack = handleCommand(numbers, (CharStringCommand) object);
-                if (stack != null && !stack.isEmpty())
-                    numbers = stack;
-                else
-                    numbers = null;
+                List<Integer> numbers = (List) sequence.subList(offset, i);
+                handleCommand(numbers, (CharStringCommand) object);
                 offset = i + 1;
             }
         }
-        if (numbers != null && !numbers.isEmpty())
-            return numbers;
-        else
-            return null;
     }
+
     /**
      * Handler for CharStringCommands.
-     *  
+     *
      * @param numbers a list of numbers
      * @param command the CharStringCommand
-     * 
-     * @return may return a command sequence of a subroutine
      */
-    public abstract List<Integer> handleCommand(List<Integer> numbers, CharStringCommand command);
+    public abstract void handleCommand(List<Integer> numbers, CharStringCommand command);
 }
\ No newline at end of file
Index: fontbox/src/main/java/org/apache/fontbox/cff/Type1FontFormatter.java
===================================================================
--- fontbox/src/main/java/org/apache/fontbox/cff/Type1FontFormatter.java	(revision 1555455)
+++ fontbox/src/main/java/org/apache/fontbox/cff/Type1FontFormatter.java	(working copy)
@@ -174,7 +174,7 @@
 
         for (CFFFont.Mapping mapping : mappings)
         {
-            byte[] type1Bytes = formatter.format(mapping.toType1Sequence());
+            byte[] type1Bytes = formatter.format(mapping.getType1CharString().getType1Sequence());
 
             byte[] charstringBytes = Type1FontUtil.charstringEncrypt(
                     type1Bytes, 4);
Index: fontbox/src/main/java/org/apache/fontbox/encoding/Encoding.java
===================================================================
--- fontbox/src/main/java/org/apache/fontbox/encoding/Encoding.java	(revision 1555455)
+++ fontbox/src/main/java/org/apache/fontbox/encoding/Encoding.java	(working copy)
@@ -153,10 +153,8 @@
      * @param code The character code.
      *
      * @return The name of the character.
-     *
-     * @throws IOException If there is no name for the code.
      */
-    public String getName( int code ) throws IOException
+    public String getName( int code )
     {
         String name = codeToName.get( code );
         if( name == null )
Index: pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/CFFGlyph2D.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/CFFGlyph2D.java	(revision 1555455)
+++ pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/CFFGlyph2D.java	(working copy)
@@ -29,7 +29,6 @@
 import org.apache.commons.logging.LogFactory;
 import org.apache.fontbox.cff.CFFFont;
 import org.apache.fontbox.cff.CFFFontROS;
-import org.apache.fontbox.cff.CharStringRenderer;
 import org.apache.pdfbox.encoding.Encoding;
 
 /**
@@ -80,14 +79,13 @@
         		codeToName.put(key, encodingCodeToName.get(key));
         	}
         }
-        CharStringRenderer renderer = cffFont.createRenderer();
         int glyphId = 0;
         for (CFFFont.Mapping mapping : mappings)
         {
             GeneralPath glyph = null;
             try
             {
-                glyph = renderer.render(mapping.toType1Sequence());
+                glyph = mapping.getType1CharString().getPath();
             }
             catch (IOException exception)
             {
