You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ja...@apache.org on 2014/08/30 04:27:00 UTC

svn commit: r1621411 [2/7] - in /pdfbox/trunk: ./ examples/src/main/java/org/apache/pdfbox/examples/pdmodel/ fontbox/src/main/java/org/apache/fontbox/afm/ fontbox/src/main/java/org/apache/fontbox/cff/ fontbox/src/main/java/org/apache/fontbox/cff/charse...

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java Sat Aug 30 02:26:57 2014
@@ -34,21 +34,24 @@ public class Type2CharString extends Typ
     private int defWidthX = 0;
     private int nominalWidthX = 0;
     private int pathCount = 0;
-    private List<Object> type2sequence;
+    private final List<Object> type2sequence;
+    private final int gid;
 
     /**
      * Constructor.
-     * @param reader Parent CFF font
+     * @param font Parent CFF font
      * @param fontName font name
-     * @param glyphName glyph name
+     * @param glyphName glyph name (or CID as hex string)
+     * @param gid GID
      * @param sequence Type 2 char string sequence
      * @param defaultWidthX default width
      * @param nomWidthX nominal width
      */
-    public Type2CharString(Type1CharStringReader reader, String fontName, String glyphName, List<Object> sequence,
+    public Type2CharString(Type1CharStringReader font, String fontName, String glyphName, int gid, List<Object> sequence,
                            int defaultWidthX, int nomWidthX)
     {
-        super(reader, fontName, glyphName);
+        super(font, fontName, glyphName);
+        this.gid = gid;
         type2sequence = sequence;
         defWidthX = defaultWidthX;
         nominalWidthX = nomWidthX;
@@ -56,8 +59,15 @@ public class Type2CharString extends Typ
     }
 
     /**
-     * Returns the advance width of the glyph.
-     * @return the width
+     * Return the GID (glyph id) of this charstring.
+     */
+    public int getGID()
+    {
+        return gid;
+    }
+
+    /**
+     * Returns the advance width of this glyph.
      */
     public int getWidth()
     {
@@ -73,8 +83,7 @@ public class Type2CharString extends Typ
     }
 
     /**
-     * Returns the Type 2 char string sequence.
-     * @return the Type 2 sequence
+     * Returns the Type 2 charstring sequence.
      */
     public List<Object> getType2Sequence()
     {
@@ -138,7 +147,7 @@ public class Type2CharString extends Typ
         }
         else if ("endchar".equals(name))
         {
-            numbers = clearStack(numbers, numbers.size() == 5);
+            numbers = clearStack(numbers, numbers.size() == 5 || numbers.size() == 1);
             closePath();
             if (numbers.size() == 4)
             {

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java Sat Aug 30 02:26:57 2014
@@ -32,7 +32,7 @@ public class Type2CharStringParser
     private final String fontName, glyphName;
 
     /**
-     * Constructs a new Type1CharStringParser object.
+     * Constructs a new Type1CharStringParser object for a Type 1-equivalent font.
      *
      * @param fontName font name
      * @param glyphName glyph name
@@ -44,6 +44,18 @@ public class Type2CharStringParser
     }
 
     /**
+     * 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("%04x", cid); // for debugging only
+    }
+
+    /**
      * The given byte array will be parsed and converted to a Type2 sequence.
      * @param bytes the given mapping as byte array
      * @param globalSubrIndex index containing all global subroutines

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java Sat Aug 30 02:26:57 2014
@@ -17,15 +17,12 @@
 package org.apache.fontbox.cmap;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.Iterator;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 
 /**
  * This class represents a CMap file.
@@ -34,9 +31,6 @@ import org.apache.commons.logging.LogFac
  */
 public class CMap
 {
- 
-    private static final Log LOG = LogFactory.getLog(CMap.class);
-    
     private int wmode = 0;
     private String cmapName = null;
     private String cmapVersion = null;
@@ -45,44 +39,25 @@ public class CMap
     private String registry = null;
     private String ordering = null;
     private int supplement = 0;
-    
-    private List<CodespaceRange> codeSpaceRanges = new ArrayList<CodespaceRange>();
-    private Map<Integer,String> singleByteMappings = new HashMap<Integer,String>();
-    private Map<Integer,String> doubleByteMappings = new HashMap<Integer,String>();
-
-    private final Map<Integer,String> cid2charMappings = new HashMap<Integer,String>();
-    private final Map<String,Integer> char2CIDMappings = new HashMap<String,Integer>();
-    private final List<CIDRange> cidRanges = new LinkedList<CIDRange>();
+
+    // code lengths
+    private final List<CodespaceRange> codespaceRanges = new ArrayList<CodespaceRange>();
+
+    // Unicode mappings
+    private final Map<Integer,String> charToUnicode = new HashMap<Integer,String>();
+
+    // CID mappings
+    private final Map<Integer,Integer> codeToCid = new HashMap<Integer,Integer>();
+    private final List<CIDRange> codeToCidRanges = new LinkedList<CIDRange>();
 
     private static final String SPACE = " ";
     private int spaceMapping = -1;
-    
+
     /**
      * Creates a new instance of CMap.
      */
-    public CMap()
-    {
-        //default constructor
-    }
-    
-    /**
-     * This will tell if this cmap has any one byte mappings.
-     * 
-     * @return true If there are any one byte mappings, false otherwise.
-     */
-    public boolean hasOneByteMappings()
+    CMap()
     {
-        return singleByteMappings.size() > 0;
-    }
-    
-    /**
-     * This will tell if this cmap has any two byte mappings.
-     * 
-     * @return true If there are any two byte mappings, false otherwise.
-     */
-    public boolean hasTwoByteMappings()
-    {
-        return doubleByteMappings.size() > 0;
     }
 
     /**
@@ -92,104 +67,143 @@ public class CMap
      */
     public boolean hasCIDMappings()
     {
-        return !char2CIDMappings.isEmpty() || !cidRanges.isEmpty();
+        return !codeToCid.isEmpty() || !codeToCidRanges.isEmpty();
     }
 
     /**
-     * This will perform a lookup into the map.
+     * This will tell if this cmap has any Unicode mappings.
      *
-     * @param code The code used to lookup.
-     * @param offset The offset into the byte array.
-     * @param length The length of the data we are getting.
-     *
-     * @return The string that matches the lookup.
+     * @return true If there are any Unicode mappings, false otherwise.
      */
-    public String lookup( byte[] code, int offset, int length )
+    public boolean hasUnicodeMappings()
     {
-        return lookup(getCodeFromArray(code, offset, length), length);
+        return !charToUnicode.isEmpty();
     }
 
     /**
-     * This will perform a lookup into the map.
-     *
-     * @param code The code used to lookup.
-     * @param length The length of the data we are getting.
+     * Returns the sequence of Unicode characters for the given character code.
      *
-     * @return The string that matches the lookup.
+     * @param code character code
+     * @return Unicode characters (may be more than one, e.g "fi" ligature)
      */
-    public String lookup( int code, int length )
+    public String toUnicode(int code)
     {
-        String result = null;
-        if( length == 1 )
-        {
-            result = singleByteMappings.get( code );
-        }
-        else if( length == 2 )
-        {
-            result = doubleByteMappings.get( code );
-        }
-        return result;
+        return charToUnicode.get(code);
     }
-    
+
     /**
-     * This will perform a lookup into the CID map.
+     * Reads a character code from a string in the content stream.
+     * <p>>See "CMap Mapping" and "Handling Undefined Characters" in PDF32000 for more details.
      *
-     * @param cid The CID used to lookup.
-     *
-     * @return The string that matches the lookup.
+     * @param in string stream
+     * @return character code
+     * @throws IOException if there was an error reading the stream or CMap
      */
-    public String lookupCID(int cid) 
+    public int readCode(InputStream in) throws IOException
     {
-        if (cid2charMappings.containsKey(cid)) 
-        {
-            return cid2charMappings.get(cid);
-        } 
-        else 
+        // save the position in the string
+        in.mark(4);
+
+        // mapping algorithm
+        List<Byte> bytes = new ArrayList<Byte>(4);
+        for (int i = 0; i < 4; i++)
         {
-            for (CIDRange range : cidRanges) 
+            bytes.add((byte)in.read());
+            for (CodespaceRange range : codespaceRanges)
             {
-                int ch = range.unmap(cid);
-                if (ch != -1) 
+                if (range.isFullMatch(bytes))
                 {
-                    return Character.toString((char) ch);
+                    return toInt(bytes);
                 }
             }
-            return null;
         }
+
+        // reset to the original position in the string
+        in.reset();
+
+        // modified mapping algorithm
+        bytes = new ArrayList<Byte>(4);
+        for (int i = 0; i < 4; i++)
+        {
+            bytes.add((byte)in.read());
+            CodespaceRange match = null;
+            CodespaceRange shortest = null;
+            for (CodespaceRange range : codespaceRanges)
+            {
+                if (range.isPartialMatch(bytes.get(i), i));
+                {
+                    if (match == null)
+                    {
+                        match = range;
+                    }
+                    else if (range.getStart().length < match.getStart().length)
+                    {
+                        // for multiple matches, choose the codespace with the shortest codes
+                        match = range;
+                    }
+                }
+
+                // find shortest range
+                if (shortest == null || range.getStart().length < shortest.getStart().length)
+                {
+                    shortest = range;
+                }
+            }
+
+            // if there are no matches, the range with the shortest codes is chosen
+            if (match == null)
+            {
+                match = shortest;
+            }
+
+            // we're done when we have enough bytes for the matched range
+            if (match.getStart().length == bytes.size())
+            {
+                return toInt(bytes);
+            }
+        }
+
+        throw new IOException("CMap is invalid");
     }
 
     /**
-     * This will perform a lookup into the CID map.
-     *
-     * @param code The code used to lookup.
-     * @param offset the offset into the array.
-     * @param length the length of the subarray.
+     * Returns an int given a List<Byte>
+     */
+    private int toInt(List<Byte> data)
+    {
+        int code = 0;
+        for (byte b : data)
+        {
+            code <<= 8;
+            code |= (b + 256) % 256;
+        }
+        return code;
+    }
+
+    /**
+     * Returns the CID for the given character code.
      *
-     * @return The CID that matches the lookup.
+     * @param code character code
+     * @return CID
      */
-    public int lookupCID(byte[] code, int offset, int length) 
+    public int toCID(int code)
     {
-        if (isInCodeSpaceRanges(code,offset,length)) 
+        if (codeToCid.containsKey(code))
         {
-            int codeAsInt = getCodeFromArray(code, offset, length);
-            if (char2CIDMappings.containsKey(codeAsInt)) 
-            {
-                return char2CIDMappings.get(codeAsInt);
-            } 
-            else 
+            return codeToCid.get(code);
+        }
+        else
+        {
+            for (CIDRange range : codeToCidRanges)
             {
-                for (CIDRange range : cidRanges) 
+                int ch = range.map((char)code);
+                if (ch != -1)
                 {
-                    int ch = range.map((char)codeAsInt);
-                    if (ch != -1) 
-                    {
-                        return ch;
-                    }
+                    return ch;
                 }
-                return -1;
             }
+            return 0;
         }
-        return -1;
     }
     
     /**
@@ -211,49 +225,32 @@ public class CMap
     }
 
     /**
-     * This will add a mapping.
-     *
-     * @param src The src to the mapping.
-     * @param dest The dest to the mapping.
+     * This will add a character code to Unicode character sequence mapping.
      *
-     * @throws IOException if the src is invalid.
+     * @param codes The character codes to map from.
+     * @param unicode The Unicode characters to map to.
      */
-    public void addMapping( byte[] src, String dest ) throws IOException
+    void addCharMapping(byte[] codes, String unicode)
     {
-        
-        int srcLength = src.length;
-        int intSrc = getCodeFromArray(src, 0, srcLength);
-        if ( SPACE.equals(dest) )
-        {
-            spaceMapping = intSrc;
-        }
-        if( srcLength == 1 )
-        {
-            singleByteMappings.put( intSrc, dest );
-        }
-        else if( srcLength == 2 )
-        {
-            doubleByteMappings.put( intSrc, dest );
-        }
-        else
+        int code = getCodeFromArray(codes, 0, codes.length);
+        charToUnicode.put(code, unicode);
+
+        // fixme: ugly little hack
+        if (SPACE.equals(unicode))
         {
-            // Just log the invalid entry instead of throwing an exception
-            LOG.error("Mapping code should be 1 or two bytes and not " + src.length);
+            spaceMapping = code;
         }
     }
 
     /**
      * This will add a CID mapping.
      *
-     * @param src The CID to the mapping.
-     * @param dest The dest to the mapping.
-     *
-     * @throws IOException if the src is invalid.
+     * @param code character code
+     * @param cid CID
      */
-    public void addCIDMapping( int src, String dest ) throws IOException
+    void addCIDMapping(int code, int cid)
     {
-        cid2charMappings.put( src, dest );
-        char2CIDMappings.put( dest, src );
+        codeToCid.put(cid, code);
     }
 
     /**
@@ -264,9 +261,9 @@ public class CMap
      * @param cid the cid to be started with.
      *
      */
-    public void addCIDRange(char from, char to, int cid) 
+    void addCIDRange(char from, char to, int cid)
     {
-        cidRanges.add(0, new CIDRange(from, to, cid));
+        codeToCidRanges.add(0, new CIDRange(from, to, cid));
     }
 
     /**
@@ -274,19 +271,9 @@ public class CMap
      *
      * @param range A single codespace range.
      */
-    public void addCodespaceRange( CodespaceRange range )
+    void addCodespaceRange( CodespaceRange range )
     {
-        codeSpaceRanges.add( range );
-    }
-
-    /**
-     * Getter for property codeSpaceRanges.
-     *
-     * @return Value of property codeSpaceRanges.
-     */
-    public List<CodespaceRange> getCodeSpaceRanges()
-    {
-        return codeSpaceRanges;
+        codespaceRanges.add(range);
     }
     
     /**
@@ -295,46 +282,12 @@ public class CMap
      * 
      * @param cmap The cmap to load mappings from.
      */
-    public void useCmap( CMap cmap )
-    {
-        this.codeSpaceRanges.addAll( cmap.codeSpaceRanges );
-        this.singleByteMappings.putAll( cmap.singleByteMappings );
-        this.doubleByteMappings.putAll( cmap.doubleByteMappings );
-    }
-
-    /**
-     *  Check whether the given byte array is in codespace ranges or not.
-     *  
-     *  @param code The byte array to look for in the codespace range.
-     *  
-     *  @return true if the given byte array is in the codespace range.
-     */
-    public boolean isInCodeSpaceRanges( byte[] code )
+    void useCmap( CMap cmap )
     {
-        return isInCodeSpaceRanges(code, 0, code.length);
-    }
- 
-    /**
-     *  Check whether the given byte array is in codespace ranges or not.
-     *  
-     *  @param code The byte array to look for in the codespace range.
-     *  @param offset The starting offset within the byte array.
-     *  @param length The length of the part of the array.
-     *  
-     *  @return true if the given byte array is in the codespace range.
-     */
-    public boolean isInCodeSpaceRanges( byte[] code, int offset, int length )
-    {
-        Iterator<CodespaceRange> it = codeSpaceRanges.iterator();
-        while ( it.hasNext() ) 
-        {
-            CodespaceRange range = it.next();
-            if ( range != null && range.isInRange(code, offset, length) )
-            {
-                return true;
-            }
-        }
-        return false;
+        this.codespaceRanges.addAll(cmap.codespaceRanges);
+        this.charToUnicode.putAll(cmap.charToUnicode);
+        this.codeToCid.putAll(cmap.codeToCid);
+        this.codeToCidRanges.addAll(cmap.codeToCidRanges);
     }
     
     /**
@@ -488,4 +441,10 @@ public class CMap
     {
         return spaceMapping;
     }
-}
\ No newline at end of file
+
+    @Override
+    public String toString()
+    {
+        return cmapName;
+    }
+}

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java Sat Aug 30 02:26:57 2014
@@ -22,7 +22,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.PushbackInputStream;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -30,35 +29,12 @@ import java.util.Map;
 import org.apache.fontbox.util.ResourceLoader;
 
 /**
- * This will parse a CMap stream.
+ * Parses a CMap stream.
  *
- * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * 
+ * @author Ben Litchfield
  */
 public class CMapParser
 {
-    private static final String BEGIN_CODESPACE_RANGE = "begincodespacerange";
-    private static final String BEGIN_BASE_FONT_CHAR = "beginbfchar";
-    private static final String BEGIN_BASE_FONT_RANGE = "beginbfrange";
-    private static final String BEGIN_CID_CHAR = "begincidchar";
-    private static final String BEGIN_CID_RANGE = "begincidrange";
-    private static final String USECMAP = "usecmap";
-
-    private static final String END_CODESPACE_RANGE = "endcodespacerange";
-    private static final String END_BASE_FONT_CHAR = "endbfchar";
-    private static final String END_BASE_FONT_RANGE = "endbfrange";
-    private static final String END_CID_CHAR = "endcidchar";
-    private static final String END_CID_RANGE = "endcidrange";
-    private static final String END_CMAP = "endcmap";
-
-    private static final String WMODE = "WMode";
-    private static final String CMAP_NAME = "CMapName";
-    private static final String CMAP_VERSION = "CMapVersion";
-    private static final String CMAP_TYPE = "CMapType";
-    private static final String REGISTRY = "Registry";
-    private static final String ORDERING = "Ordering";
-    private static final String SUPPLEMENT = "Supplement";
-
     private static final String MARK_END_OF_DICTIONARY = ">>";
     private static final String MARK_END_OF_ARRAY = "]";
 
@@ -121,7 +97,7 @@ public class CMapParser
             if (token instanceof Operator)
             {
                 Operator op = (Operator) token;
-                if (op.op.equals(USECMAP))
+                if (op.op.equals("usecmap"))
                 {
                     LiteralName useCmapName = (LiteralName) previousToken;
                     InputStream useStream = ResourceLoader.loadResource(resourceRoot + useCmapName.name);
@@ -132,12 +108,12 @@ public class CMapParser
                     CMap useCMap = parse(resourceRoot, useStream);
                     result.useCmap(useCMap);
                 }
-                else if (op.op.equals(END_CMAP))
+                else if (op.op.equals("endcmap"))
                 {
                     // end of CMap reached, stop reading as there isn't any interesting info anymore
                     break;
                 }
-                else if (op.op.equals(BEGIN_CODESPACE_RANGE))
+                else if (op.op.equals("begincodespacerange"))
                 {
                     Number cosCount = (Number) previousToken;
                     for (int j = 0; j < cosCount.intValue(); j++)
@@ -145,7 +121,7 @@ public class CMapParser
                         Object nextToken = parseNextToken(cmapStream);
                         if (nextToken instanceof Operator)
                         {
-                            if (!((Operator) nextToken).op.equals(END_CODESPACE_RANGE))
+                            if (!((Operator) nextToken).op.equals("endcodespacerange"))
                             {
                                 throw new IOException("Error : ~codespacerange contains an unexpected operator : "
                                         + ((Operator) nextToken).op);
@@ -160,7 +136,7 @@ public class CMapParser
                         result.addCodespaceRange(range);
                     }
                 }
-                else if (op.op.equals(BEGIN_BASE_FONT_CHAR))
+                else if (op.op.equals("beginbfchar"))
                 {
                     Number cosCount = (Number) previousToken;
                     for (int j = 0; j < cosCount.intValue(); j++)
@@ -168,7 +144,7 @@ public class CMapParser
                         Object nextToken = parseNextToken(cmapStream);
                         if (nextToken instanceof Operator)
                         {
-                            if (!((Operator) nextToken).op.equals(END_BASE_FONT_CHAR))
+                            if (!((Operator) nextToken).op.equals("endbfchar"))
                             {
                                 throw new IOException("Error : ~bfchar contains an unexpected operator : "
                                         + ((Operator) nextToken).op);
@@ -181,11 +157,11 @@ public class CMapParser
                         {
                             byte[] bytes = (byte[]) nextToken;
                             String value = createStringFromBytes(bytes);
-                            result.addMapping(inputCode, value);
+                            result.addCharMapping(inputCode, value);
                         }
                         else if (nextToken instanceof LiteralName)
                         {
-                            result.addMapping(inputCode, ((LiteralName) nextToken).name);
+                            result.addCharMapping(inputCode, ((LiteralName) nextToken).name);
                         }
                         else
                         {
@@ -194,7 +170,7 @@ public class CMapParser
                         }
                     }
                 }
-                else if (op.op.equals(BEGIN_BASE_FONT_RANGE))
+                else if (op.op.equals("beginbfrange"))
                 {
                     Number cosCount = (Number) previousToken;
 
@@ -203,7 +179,7 @@ public class CMapParser
                         Object nextToken = parseNextToken(cmapStream);
                         if (nextToken instanceof Operator)
                         {
-                            if (!((Operator) nextToken).op.equals(END_BASE_FONT_RANGE))
+                            if (!((Operator) nextToken).op.equals("endbfrange"))
                             {
                                 throw new IOException("Error : ~bfrange contains an unexpected operator : "
                                         + ((Operator) nextToken).op);
@@ -226,10 +202,10 @@ public class CMapParser
                         }
                         boolean done = false;
                         // don't add 1:1 mappings to reduce the memory footprint
-                        if (Arrays.equals(startCode, tokenBytes))
+                        /*if (Arrays.equals(startCode, tokenBytes))
                         {
                             done = true;
-                        }
+                        }*/
                         String value = null;
 
                         int arrayIndex = 0;
@@ -240,7 +216,7 @@ public class CMapParser
                                 done = true;
                             }
                             value = createStringFromBytes(tokenBytes);
-                            result.addMapping(startCode, value);
+                            result.addCharMapping(startCode, value);
                             increment(startCode);
 
                             if (array == null)
@@ -258,7 +234,7 @@ public class CMapParser
                         }
                     }
                 }
-                else if (op.op.equals(BEGIN_CID_CHAR))
+                else if (op.op.equals("begincidchar"))
                 {
                     Number cosCount = (Number) previousToken;
                     for (int j = 0; j < cosCount.intValue(); j++)
@@ -266,7 +242,7 @@ public class CMapParser
                         Object nextToken = parseNextToken(cmapStream);
                         if (nextToken instanceof Operator)
                         {
-                            if (!((Operator) nextToken).op.equals(END_CID_CHAR))
+                            if (!((Operator) nextToken).op.equals("endcidchar"))
                             {
                                 throw new IOException("Error : ~cidchar contains an unexpected operator : "
                                         + ((Operator) nextToken).op);
@@ -275,11 +251,11 @@ public class CMapParser
                         }
                         byte[] inputCode = (byte[]) nextToken;
                         int mappedCode = (Integer) parseNextToken(cmapStream);
-                        String mappedStr = createStringFromBytes(inputCode);
-                        result.addCIDMapping(mappedCode, mappedStr);
+                        int mappedCID = createIntFromBytes(inputCode);
+                        result.addCIDMapping(mappedCode, mappedCID);
                     }
                 }
-                else if (op.op.equals(BEGIN_CID_RANGE))
+                else if (op.op.equals("begincidrange"))
                 {
                     int numberOfLines = (Integer) previousToken;
                     for (int n = 0; n < numberOfLines; n++)
@@ -287,7 +263,7 @@ public class CMapParser
                         Object nextToken = parseNextToken(cmapStream);
                         if (nextToken instanceof Operator)
                         {
-                            if (!((Operator) nextToken).op.equals(END_CID_RANGE))
+                            if (!((Operator) nextToken).op.equals("endcidrange"))
                             {
                                 throw new IOException("Error : ~cidrange contains an unexpected operator : "
                                         + ((Operator) nextToken).op);
@@ -309,8 +285,8 @@ public class CMapParser
                             int endOfMappings = mappedCode + end - start;
                             while (mappedCode <= endOfMappings)
                             {
-                                String mappedStr = createStringFromBytes(startCode);
-                                result.addCIDMapping(mappedCode++, mappedStr);
+                                int mappedCID = createIntFromBytes(startCode);
+                                result.addCIDMapping(mappedCode++, mappedCID);
                                 increment(startCode);
                             }
                         }
@@ -320,7 +296,7 @@ public class CMapParser
             else if (token instanceof LiteralName)
             {
                 LiteralName literal = (LiteralName) token;
-                if (WMODE.equals(literal.name))
+                if ("WMode".equals(literal.name))
                 {
                     Object next = parseNextToken(cmapStream);
                     if (next instanceof Integer)
@@ -328,7 +304,7 @@ public class CMapParser
                         result.setWMode((Integer) next);
                     }
                 }
-                else if (CMAP_NAME.equals(literal.name))
+                else if ("CMapName".equals(literal.name))
                 {
                     Object next = parseNextToken(cmapStream);
                     if (next instanceof LiteralName)
@@ -336,7 +312,7 @@ public class CMapParser
                         result.setName(((LiteralName) next).name);
                     }
                 }
-                else if (CMAP_VERSION.equals(literal.name))
+                else if ("CMapVersion".equals(literal.name))
                 {
                     Object next = parseNextToken(cmapStream);
                     if (next instanceof Number)
@@ -348,7 +324,7 @@ public class CMapParser
                         result.setVersion((String) next);
                     }
                 }
-                else if (CMAP_TYPE.equals(literal.name))
+                else if ("CMapType".equals(literal.name))
                 {
                     Object next = parseNextToken(cmapStream);
                     if (next instanceof Integer)
@@ -356,7 +332,7 @@ public class CMapParser
                         result.setType((Integer) next);
                     }
                 }
-                else if (REGISTRY.equals(literal.name))
+                else if ("Registry".equals(literal.name))
                 {
                     Object next = parseNextToken(cmapStream);
                     if (next instanceof String)
@@ -364,7 +340,7 @@ public class CMapParser
                         result.setRegistry((String) next);
                     }
                 }
-                else if (ORDERING.equals(literal.name))
+                else if ("Ordering".equals(literal.name))
                 {
                     Object next = parseNextToken(cmapStream);
                     if (next instanceof String)
@@ -372,7 +348,7 @@ public class CMapParser
                         result.setOrdering((String) next);
                     }
                 }
-                else if (SUPPLEMENT.equals(literal.name))
+                else if ("Supplement".equals(literal.name))
                 {
                     Object next = parseNextToken(cmapStream);
                     if (next instanceof Integer)
@@ -703,24 +679,4 @@ public class CMapParser
             op = theOp;
         }
     }
-
-    /**
-     * A simple class to test parsing of cmap files.
-     * 
-     * @param args Some command line arguments.
-     * 
-     * @throws Exception If there is an error parsing the file.
-     */
-    public static void main(String[] args) throws Exception
-    {
-        if (args.length != 1)
-        {
-            System.err.println("usage: java org.apache.fontbox.cmap.CMapParser <CMAP File>");
-            System.exit(-1);
-        }
-        CMapParser parser = new CMapParser();
-        File cmapFile = new File(args[0]);
-        CMap result = parser.parse(cmapFile);
-        System.out.println("Result:" + result);
-    }
 }

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CodespaceRange.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CodespaceRange.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CodespaceRange.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cmap/CodespaceRange.java Sat Aug 30 02:26:57 2014
@@ -16,15 +16,15 @@
  */
 package org.apache.fontbox.cmap;
 
+import java.util.List;
+
 /**
  * This represents a single entry in the codespace range.
  *
- * @author Ben Litchfield (ben@benlitchfield.com)
- * @version $Revision: 1.1 $
+ * @author Ben Litchfield
  */
 public class CodespaceRange
 {
-
     private byte[] start;
     private byte[] end;
 
@@ -48,7 +48,7 @@ public class CodespaceRange
      * @param endBytes New value of property end.
      *
      */
-    public void setEnd(byte[] endBytes)
+    void setEnd(byte[] endBytes)
     {
         end = endBytes;
     }
@@ -66,50 +66,69 @@ public class CodespaceRange
      * @param startBytes New value of property start.
      *
      */
-    public void setStart(byte[] startBytes)
+    void setStart(byte[] startBytes)
     {
         start = startBytes;
     }
 
     /**
-     *  Check whether the given byte array is in this codespace range or ot.
-     *  @param code The byte array to look for in the codespace range.
-     *  @param offset The starting offset within the byte array.
-     *  @param length The length of the part of the array.
-     *  
-     *  @return true if the given byte array is in the codespace range.
+     * Returns true if the given code bytes match this codespace range.
      */
-    public boolean isInRange(byte[] code, int offset, int length)
+    public boolean matches(byte[] code)
     {
-        if ( length < start.length || length > end.length ) 
-        {
-            return false;
-        }
-
-        if ( end.length == length ) 
+        // code must be the same length as the bounding codes
+        if (code.length >= start.length && code.length <= end.length)
         {
-            for ( int i = 0; i < end.length; i++ ) 
+            // each of it bytes must lie between the corresponding bytes of the upper & lower bounds
+            for (int i = 0; i < code.length; i++)
             {
-                int endInt = ((int)end[i]) & 0xFF;
-                int codeInt = ((int)code[offset + i]) & 0xFF;
-                if ( endInt < codeInt )
+                int startNum = start[i] & 0xff;
+                int endNum = end[i] & 0xff;
+                int codeNum = code[i] & 0xff;
+
+                if (codeNum > endNum || codeNum < startNum)
                 {
                     return false;
                 }
             }
+            return true;
         }
-        if ( start.length == length ) 
+        return false;
+    }
+
+    /**
+     * Returns true if the given code bytes match this codespace range.
+     */
+    public boolean isFullMatch(List<Byte> code)
+    {
+        // code must be the same length as the bounding codes
+        if (code.size() >= start.length && code.size() <= end.length)
         {
-            for ( int i = 0; i < end.length; i++ ) 
+            // each of it bytes must lie between the corresponding bytes of the upper & lower bounds
+            for (int i = 0; i < code.size(); i++)
             {
-                int startInt = ((int)start[i]) & 0xFF;
-                int codeInt = ((int)code[offset + i]) & 0xFF;
-                if ( startInt > codeInt )
+                int startNum = start[i] & 0xff;
+                int endNum = end[i] & 0xff;
+                int codeNum = code.get(i) & 0xff;
+
+                if (codeNum > endNum || codeNum < startNum)
                 {
                     return false;
                 }
             }
+            return true;
         }
-        return true;
+        return false;
+    }
+
+    /**
+     * Returns true if the given byte matches the byte at the given index of this codespace range.
+     */
+    public boolean isPartialMatch(byte b, int index)
+    {
+        int startNum = start[index] & 0xff;
+        int endNum = end[index] & 0xff;
+        int codeNum = b & 0xff;
+        return !(codeNum > endNum || codeNum < startNum);
     }
-}
\ No newline at end of file
+}

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/encoding/Encoding.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/encoding/Encoding.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/encoding/Encoding.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/encoding/Encoding.java Sat Aug 30 02:26:57 2014
@@ -22,98 +22,26 @@ import java.util.HashMap;
 import java.util.Map;
 
 /**
- * This is an interface to a text encoder.
+ * A PostScript Encoding vector.
  *
  * @author Ben Litchfield
- * 
  */
 public abstract class Encoding
 {
-    /**
-     * The number of standard mac glyph names.
-     */
-    public static final int NUMBER_OF_MAC_GLYPHS = 258;
-    
-    /**
-     * The 258 standard mac glyph names a used in 'post' format 1 and 2.
-     */
-    public static final String[] MAC_GLYPH_NAMES = new String[] 
-    { 
-        ".notdef",".null", "nonmarkingreturn", "space", "exclam", "quotedbl",
-            "numbersign", "dollar", "percent", "ampersand", "quotesingle",
-            "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen",
-            "period", "slash", "zero", "one", "two", "three", "four", "five",
-            "six", "seven", "eight", "nine", "colon", "semicolon", "less",
-            "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F",
-            "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S",
-            "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash",
-            "bracketright", "asciicircum", "underscore", "grave", "a", "b",
-            "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
-            "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft",
-            "bar", "braceright", "asciitilde", "Adieresis", "Aring",
-            "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", "aacute",
-            "agrave", "acircumflex", "adieresis", "atilde", "aring",
-            "ccedilla", "eacute", "egrave", "ecircumflex", "edieresis",
-            "iacute", "igrave", "icircumflex", "idieresis", "ntilde", "oacute",
-            "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave",
-            "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling",
-            "section", "bullet", "paragraph", "germandbls", "registered",
-            "copyright", "trademark", "acute", "dieresis", "notequal", "AE",
-            "Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
-            "yen", "mu", "partialdiff", "summation", "product", "pi",
-            "integral", "ordfeminine", "ordmasculine", "Omega", "ae", "oslash",
-            "questiondown", "exclamdown", "logicalnot", "radical", "florin",
-            "approxequal", "Delta", "guillemotleft", "guillemotright",
-            "ellipsis", "nonbreakingspace", "Agrave", "Atilde", "Otilde", "OE",
-            "oe", "endash", "emdash", "quotedblleft", "quotedblright",
-            "quoteleft", "quoteright", "divide", "lozenge", "ydieresis",
-            "Ydieresis", "fraction", "currency", "guilsinglleft",
-            "guilsinglright", "fi", "fl", "daggerdbl", "periodcentered",
-            "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
-            "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
-            "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
-            "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi",
-            "circumflex", "tilde", "macron", "breve", "dotaccent", "ring",
-            "cedilla", "hungarumlaut", "ogonek", "caron", "Lslash", "lslash",
-            "Scaron", "scaron", "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
-            "Yacute", "yacute", "Thorn", "thorn", "minus", "multiply",
-            "onesuperior", "twosuperior", "threesuperior", "onehalf",
-            "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
-            "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute", "Ccaron",
-            "ccaron", "dcroat" 
-    };
-
-    /**
-     * The indices of the standard mac glyph names.
-     */
-    public static Map<String,Integer> MAC_GLYPH_NAMES_INDICES;
-    
-    static 
-    {
-        MAC_GLYPH_NAMES_INDICES = new HashMap<String,Integer>();
-        for (int i=0;i<Encoding.NUMBER_OF_MAC_GLYPHS;++i) 
-        {
-            MAC_GLYPH_NAMES_INDICES.put(Encoding.MAC_GLYPH_NAMES[i],i);
-        }
-    }
-
-    /**
-     * Identifies a non-mapped character. 
-     */
     private static final String NOTDEF = ".notdef";
+    private static final Map<String,String> NAME_TO_CHARACTER = new HashMap<String,String>();
+    private static final Map<String,String> CHARACTER_TO_NAME = new HashMap<String,String>();
 
     /**
      * This is a mapping from a character code to a character name.
      */
     protected Map<Integer,String> codeToName = new HashMap<Integer,String>();
+
     /**
      * This is a mapping from a character name to a character code.
      */
     protected Map<String,Integer> nameToCode = new HashMap<String,Integer>();
 
-    private static final Map<String,String> NAME_TO_CHARACTER = new HashMap<String,String>();
-    private static final Map<String,String> CHARACTER_TO_NAME = new HashMap<String,String>();
-
     /**
      * This will add a character encoding.
      *
@@ -130,7 +58,6 @@ public abstract class Encoding
      * This will get the character code for the name.
      *
      * @param name The name of the character.
-     *
      * @return The code for the character or null if it is not in the encoding.
      */
     public Integer getCode( String name )
@@ -142,7 +69,6 @@ public abstract class Encoding
      * This will take a character code and get the name from the code.
      *
      * @param code The character code.
-     *
      * @return The name of the character.
      */
     public String getName( int code )
@@ -159,9 +85,7 @@ public abstract class Encoding
      * This will take a character code and get the name from the code.
      *
      * @param c The character.
-     *
      * @return The name of the character.
-     *
      * @throws IOException If there is no name for the character.
      */
     public String getNameFromCharacter( char c ) throws IOException
@@ -178,9 +102,7 @@ public abstract class Encoding
      * This will get the character from the code.
      *
      * @param code The character code.
-     *
      * @return The printable character for the code.
-     *
      * @throws IOException If there is not name for the character.
      */
     public String getCharacter( int code ) throws IOException
@@ -192,7 +114,6 @@ public abstract class Encoding
      * This will get the character from the name.
      *
      * @param name The name of the character.
-     *
      * @return The printable character for the code.
      */
     public static String getCharacter( String name )
@@ -206,7 +127,7 @@ public abstract class Encoding
     }
     
     /**
-     * Returns an unmodifiable view of the Code2Name mapping.
+     * Returns an unmodifiable view of the code to name mapping.
      * 
      * @return the Code2Name map
      */
@@ -214,5 +135,4 @@ public abstract class Encoding
     {
         return Collections.unmodifiableMap(codeToName);
     }
-
-}
\ No newline at end of file
+}

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfSimpleDescript.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfSimpleDescript.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfSimpleDescript.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfSimpleDescript.java Sat Aug 30 02:26:57 2014
@@ -186,26 +186,18 @@ public class GlyfSimpleDescript extends 
      */
     private void readFlags(int flagCount, TTFDataStream bais) throws IOException
     {
-        try
+        for (int index = 0; index < flagCount; index++)
         {
-            for (int index = 0; index < flagCount; index++)
+            flags[index] = (byte) bais.readUnsignedByte();
+            if ((flags[index] & REPEAT) != 0)
             {
-                flags[index] = (byte) bais.readUnsignedByte();
-                if ((flags[index] & REPEAT) != 0)
+                int repeats = bais.readUnsignedByte();
+                for (int i = 1; i <= repeats; i++)
                 {
-                    int repeats = bais.readUnsignedByte();
-                    for (int i = 1; i <= repeats; i++)
-                    {
-                        flags[index + i] = flags[index];
-                    }
-                    index += repeats;
+                    flags[index + i] = flags[index];
                 }
+                index += repeats;
             }
         }
-        catch (ArrayIndexOutOfBoundsException e)
-        {
-            LOG.error("error: array index out of bounds", e);
-        }
     }
-
 }

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphRenderer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphRenderer.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphRenderer.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphRenderer.java Sat Aug 30 02:26:57 2014
@@ -214,7 +214,7 @@ class GlyphRenderer
         path.closePath();
         if (LOG.isDebugEnabled())
         {
-            LOG.debug("closePath");
+            LOG.trace("closePath");
         }
     }
 
@@ -223,7 +223,7 @@ class GlyphRenderer
         path.moveTo(point.x, point.y);
         if (LOG.isDebugEnabled())
         {
-            LOG.debug("moveTo: " + String.format("%d,%d", point.x, point.y));
+            LOG.trace("moveTo: " + String.format("%d,%d", point.x, point.y));
         }
     }
 
@@ -232,7 +232,7 @@ class GlyphRenderer
         path.lineTo(point.x, point.y);
         if (LOG.isDebugEnabled())
         {
-            LOG.debug("lineTo: " + String.format("%d,%d", point.x, point.y));
+            LOG.trace("lineTo: " + String.format("%d,%d", point.x, point.y));
         }
     }
 
@@ -241,7 +241,7 @@ class GlyphRenderer
         path.quadTo(ctrlPoint.x, ctrlPoint.y, point.x, point.y);
         if (LOG.isDebugEnabled())
         {
-            LOG.debug("quadTo: " + String.format("%d,%d %d,%d", ctrlPoint.x, ctrlPoint.y,
+            LOG.trace("quadTo: " + String.format("%d,%d %d,%d", ctrlPoint.x, ctrlPoint.y,
                     point.x, point.y));
         }
     }

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/HorizontalMetricsTable.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/HorizontalMetricsTable.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/HorizontalMetricsTable.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/HorizontalMetricsTable.java Sat Aug 30 02:26:57 2014
@@ -46,21 +46,31 @@ public class HorizontalMetricsTable exte
         HorizontalHeaderTable hHeader = ttf.getHorizontalHeader();
         int numHMetrics = hHeader.getNumberOfHMetrics();
         int numGlyphs = ttf.getNumberOfGlyphs();
-        
+
+        int bytesRead = 0;
         advanceWidth = new int[ numHMetrics ];
         leftSideBearing = new short[ numHMetrics ];
         for( int i=0; i<numHMetrics; i++ )
         {
             advanceWidth[i] = data.readUnsignedShort();
             leftSideBearing[i] = data.readSignedShort();
+            bytesRead += 4;
         }
-        
-        int numberNonHorizontal = numGlyphs - numHMetrics;
-        nonHorizontalLeftSideBearing = new short[ numberNonHorizontal ];
-        for( int i=0; i<numberNonHorizontal; i++ )
+
+        if (bytesRead < getLength())
         {
-            nonHorizontalLeftSideBearing[i] = data.readSignedShort();
+            int numberNonHorizontal = numGlyphs - numHMetrics;
+            nonHorizontalLeftSideBearing = new short[ numberNonHorizontal ];
+            for( int i=0; i<numberNonHorizontal; i++ )
+            {
+                if (bytesRead < getLength())
+                {
+                    nonHorizontalLeftSideBearing[i] = data.readSignedShort();
+                    bytesRead += 2;
+                }
+            }
         }
+
         initialized = true;
     }
     /**

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/NameRecord.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/NameRecord.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/NameRecord.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/NameRecord.java Sat Aug 30 02:26:57 2014
@@ -21,72 +21,49 @@ import java.io.IOException;
 /**
  * A name record in the name table.
  * 
- * @author Ben Litchfield (ben@benlitchfield.com)
- * @version $Revision: 1.1 $
+ * @author Ben Litchfield
  */
 public class NameRecord
 {
-    /**
-     * A constant for the platform.
-     */
-    public static final int PLATFORM_APPLE_UNICODE = 0;
-    /**
-     * A constant for the platform.
-     */
+    // platform ids
+    public static final int PLATFORM_UNICODE = 0;
     public static final int PLATFORM_MACINTOSH = 1;
-    /**
-     * A constant for the platform.
-     */
     public static final int PLATFORM_ISO = 2;
-    /**
-     * A constant for the platform.
-     */
     public static final int PLATFORM_WINDOWS = 3;
-    
-    /**
-     * Platform specific encoding.
-     */
-    public static final int PLATFORM_ENCODING_WINDOWS_UNDEFINED = 0;
-    /**
-     * Platform specific encoding.
-     */
-    public static final int PLATFORM_ENCODING_WINDOWS_UNICODE = 1;
-    
-    /**
-     * A name id.
-     */
+
+    // Unicode encoding ids
+    public static final int ENCODING_UNICODE_1_0 = 0;
+    public static final int ENCODING_UNICODE_1_1 = 1;
+    public static final int ENCODING_UNICODE_2_0_BMP = 3;
+    public static final int ENCODING_UNICODE_2_0_FULL = 4;
+
+    // Unicode encoding ids
+    public static final int LANGUGAE_UNICODE = 0;
+
+    // Windows encoding ids
+    public static final int ENCODING_WINDOWS_SYMBOL = 0;
+    public static final int ENCODING_WINDOWS_UNICODE_BMP = 1;
+    public static final int ENCODING_WINDOWS_UNICODE_UCS4 = 10;
+
+    // Windows language ids
+    public static final int LANGUGAE_WINDOWS_EN_US = 0x0409;
+
+    // Macintosh encoding ids
+    public static final int ENCODING_MACINTOSH_ROMAN = 0;
+
+    // Macintosh language ids
+    public static final int LANGUGAE_MACINTOSH_ENGLISH = 0;
+
+    // name ids
     public static final int NAME_COPYRIGHT = 0;
-    /**
-     * A name id.
-     */
     public static final int NAME_FONT_FAMILY_NAME = 1;
-    /**
-     * A name id.
-     */
     public static final int NAME_FONT_SUB_FAMILY_NAME = 2;
-    /**
-     * A name id.
-     */
     public static final int NAME_UNIQUE_FONT_ID = 3;
-    /**
-     * A name id.
-     */
     public static final int NAME_FULL_FONT_NAME = 4;
-    /**
-     * A name id.
-     */
     public static final int NAME_VERSION = 5;
-    /**
-     * A name id.
-     */
     public static final int NAME_POSTSCRIPT_NAME = 6;
-    /**
-     * A name id.
-     */
     public static final int NAME_TRADEMARK = 7;
     
-    
-    
     private int platformId;
     private int platformEncodingId;
     private int languageId;

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/NamingTable.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/NamingTable.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/NamingTable.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/NamingTable.java Sat Aug 30 02:26:57 2014
@@ -19,13 +19,14 @@ package org.apache.fontbox.ttf;
 import java.io.IOException;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * A table in a true type font.
  * 
- * @author Ben Litchfield (ben@benlitchfield.com)
- * 
+ * @author Ben Litchfield
  */
 public class NamingTable extends TTFTable
 {
@@ -35,12 +36,14 @@ public class NamingTable extends TTFTabl
     public static final String TAG = "name";
     
     private List<NameRecord> nameRecords = new ArrayList<NameRecord>();
-    
+
+    private Map<Integer, Map<Integer, Map<Integer, Map<Integer, String>>>> lookupTable =
+            new HashMap<Integer, Map<Integer, Map<Integer, Map<Integer, String>>>>();
+
     private String fontFamily = null;
     private String fontSubFamily = null;
     private String psName = null;
-    
-    
+
     /**
      * This will read the required data from the stream.
      * 
@@ -53,80 +56,173 @@ public class NamingTable extends TTFTabl
         int formatSelector = data.readUnsignedShort();
         int numberOfNameRecords = data.readUnsignedShort();
         int offsetToStartOfStringStorage = data.readUnsignedShort();
-        for( int i=0; i< numberOfNameRecords; i++ )
+        for (int i=0; i< numberOfNameRecords; i++)
         {
             NameRecord nr = new NameRecord();
-            nr.initData( ttf, data );
-            nameRecords.add( nr );
+            nr.initData(ttf, data);
+            nameRecords.add(nr);
         }
-        for( int i=0; i<numberOfNameRecords; i++ )
+
+        for (int i=0; i<numberOfNameRecords; i++)
         {
-            NameRecord nr = nameRecords.get( i );
-            data.seek( getOffset() + (2*3)+numberOfNameRecords*2*6+nr.getStringOffset() );
+            NameRecord nr = nameRecords.get(i);
+            data.seek(getOffset() + (2*3)+numberOfNameRecords*2*6+nr.getStringOffset());
             int platform = nr.getPlatformId();
             int encoding = nr.getPlatformEncodingId();
             String charset = "ISO-8859-1";
-            boolean isPlatform310 = false;
-            boolean isPlatform10 = false;
-            if( platform == 3 && (encoding == 1 || encoding == 0) )
+            if (platform == 3 && (encoding == 1 || encoding == 0))
             {
                 charset = "UTF-16";
-                isPlatform310 = true;
             }
-            else if( platform == 2 )
+            else if (platform == 2)
             {
-                if( encoding == 0 )
+                if (encoding == 0)
                 {
                     charset = "US-ASCII";
                 }
-                else if( encoding == 1 )
+                else if (encoding == 1)
                 {
                     //not sure is this is correct??
                     charset = "ISO-10646-1";
                 }
-                else if( encoding == 2 )
+                else if (encoding == 2)
                 {
                     charset = "ISO-8859-1";
                 }
             }
-            else if ( platform == 1 && encoding == 0)
+            String string = data.readString(nr.getStringLength(), charset);
+            nr.setString(string);
+        }
+
+        // build multi-dimensional lookup table
+        for (NameRecord nr : nameRecords)
+        {
+            // name id
+            if (!lookupTable.containsKey(nr.getNameId()))
             {
-                isPlatform10 = true;
+                lookupTable.put(nr.getNameId(),
+                        new HashMap<Integer, Map<Integer, Map<Integer, String>>>());
             }
-            String string = data.readString( nr.getStringLength(), charset );
-            nr.setString( string );
-            int nameID = nr.getNameId();
-            if (nameID == NameRecord.NAME_FONT_FAMILY_NAME)
-            {
-                // prefer 3,1 or 3,0 platform/encoding use 1,0 as fallback
-                if (isPlatform310 || (isPlatform10 && fontFamily == null))
-                {
-                    fontFamily = string;
-                }
-            }            
-            else if (nameID == NameRecord.NAME_FONT_SUB_FAMILY_NAME)
+            Map<Integer, Map<Integer, Map<Integer, String>>> platformLookup =
+                    lookupTable.get(nr.getNameId());
+
+            // platform id
+            if (!platformLookup.containsKey(nr.getPlatformId()))
             {
-                // prefer 3,1 or 3,0 platform/encoding use 1,0 as fallback
-                if (isPlatform310 || (isPlatform10 && fontSubFamily == null))
-                {
-                    fontSubFamily = string;
-                }
-            }            
-            else if (nameID == NameRecord.NAME_POSTSCRIPT_NAME)
+                platformLookup.put(nr.getPlatformId(),
+                                   new HashMap<Integer, Map<Integer, String>>());
+            }
+            Map<Integer, Map<Integer, String>> encodingLookup =
+                    platformLookup.get(nr.getPlatformId());
+
+            // encoding id
+            if (!encodingLookup.containsKey(nr.getPlatformEncodingId()))
             {
-                // prefer 3,1 or 3,0 platform/encoding use 1,0 as fallback
-                if (isPlatform310 || (isPlatform10 && psName == null))
-                {
-                    psName = string;
-                }
-            }            
+               encodingLookup.put(nr.getPlatformEncodingId(),
+                                  new HashMap<Integer, String>());
+            }
+            Map<Integer, String> languageLookup = encodingLookup.get(nr.getPlatformEncodingId());
+
+            // language id / string
+            languageLookup.put(nr.getLanguageId(), nr.getString());
         }
+
+        // extract strings of interest
+        fontFamily = getEnglishName(NameRecord.NAME_FONT_FAMILY_NAME);
+        fontSubFamily = getEnglishName(NameRecord.NAME_FONT_SUB_FAMILY_NAME);
+
+        // extract PostScript name, only these two formats are valid
+        psName = getName(NameRecord.NAME_POSTSCRIPT_NAME,
+                         NameRecord.PLATFORM_MACINTOSH,
+                         NameRecord.ENCODING_MACINTOSH_ROMAN,
+                         NameRecord.LANGUGAE_MACINTOSH_ENGLISH);
+        if (psName == null)
+        {
+            psName = getName(NameRecord.NAME_POSTSCRIPT_NAME,
+                             NameRecord.PLATFORM_WINDOWS,
+                             NameRecord.ENCODING_WINDOWS_UNICODE_BMP,
+                             NameRecord.LANGUGAE_WINDOWS_EN_US);
+        }
+
         initialized = true;
     }
-    
+
+    /**
+     * Helper to get English names by best effort.
+     */
+    private String getEnglishName(int nameId)
+    {
+        // Unicode, Full, BMP, 1.1, 1.0
+        for (int i = 4; i <= 0; i--)
+        {
+            String nameUni =
+                    getName(nameId,
+                            NameRecord.PLATFORM_UNICODE,
+                            i,
+                            NameRecord.LANGUGAE_UNICODE);
+            if (nameUni != null)
+            {
+                return nameUni;
+            }
+        }
+
+        // Windows, Unicode BMP, EN-US
+        String nameWin =
+                getName(nameId,
+                        NameRecord.PLATFORM_WINDOWS,
+                        NameRecord.ENCODING_WINDOWS_UNICODE_BMP,
+                        NameRecord.LANGUGAE_WINDOWS_EN_US);
+        if (nameWin != null)
+        {
+            return nameWin;
+        }
+
+        // Macintosh, Roman, English
+        String nameMac =
+                getName(nameId,
+                        NameRecord.PLATFORM_MACINTOSH,
+                        NameRecord.ENCODING_MACINTOSH_ROMAN,
+                        NameRecord.LANGUGAE_MACINTOSH_ENGLISH);
+        if (nameMac != null)
+        {
+            return nameMac;
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns a name from the table, or null it it does not exist.
+     *
+     * @param nameId Name ID from NameRecord constants.
+     * @param platformId Platform ID from NameRecord constants.
+     * @param encodingId Platform Encoding ID from NameRecord constants.
+     * @param languageId Language ID from NameRecord constants.
+     * @return name, or null
+     */
+    public String getName(int nameId, int platformId, int encodingId, int languageId)
+    {
+        Map<Integer, Map<Integer, Map<Integer, String>>> platforms = lookupTable.get(nameId);
+        if (platforms == null)
+        {
+            return null;
+        }
+        Map<Integer, Map<Integer, String>> encodings = platforms.get(platformId);
+        if (encodings == null)
+        {
+            return null;
+        }
+        Map<Integer, String> languages = encodings.get(encodingId);
+        if (languages == null)
+        {
+            return null;
+        }
+        return languages.get(languageId);
+    }
+
     /**
      * This will get the name records for this naming table.
-     * 
+     *
      * @return A list of NameRecord objects.
      */
     public List<NameRecord> getNameRecords()
@@ -135,9 +231,9 @@ public class NamingTable extends TTFTabl
     }
     
     /**
-     * Returns the font family name.
-     * 
-     * @return the font family name
+     * Returns the font family name, in English.
+     *
+     * @return the font family name, in English
      */
     public String getFontFamily()
     {
@@ -145,9 +241,9 @@ public class NamingTable extends TTFTabl
     }
 
     /**
-     * Returns the font sub family name.
-     * 
-     * @return the font sub family name
+     * Returns the font sub family name, in English.
+     *
+     * @return the font sub family name, in English
      */
     public String getFontSubFamily()
     {
@@ -155,13 +251,12 @@ public class NamingTable extends TTFTabl
     }
 
     /**
-     * Returns the postscript name.
-     * 
-     * @return the postscript name
+     * Returns the PostScript name.
+     *
+     * @return the PostScript name
      */
-    public String getPSName()
+    public String getPostScriptName()
     {
         return psName;
     }
-
 }

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/PostScriptTable.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/PostScriptTable.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/PostScriptTable.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/PostScriptTable.java Sat Aug 30 02:26:57 2014
@@ -24,7 +24,6 @@ import org.apache.fontbox.encoding.Encod
  * A table in a true type font.
  * 
  * @author Ben Litchfield (ben@benlitchfield.com)
- * 
  */
 public class PostScriptTable extends TTFTable
 {
@@ -68,8 +67,8 @@ public class PostScriptTable extends TTF
             /*
              * This TrueType font file contains exactly the 258 glyphs in the standard Macintosh TrueType.
              */
-            glyphNames = new String[Encoding.NUMBER_OF_MAC_GLYPHS];
-            System.arraycopy(Encoding.MAC_GLYPH_NAMES, 0, glyphNames, 0, Encoding.NUMBER_OF_MAC_GLYPHS);
+            glyphNames = new String[WGL4Names.NUMBER_OF_MAC_GLYPHS];
+            System.arraycopy(WGL4Names.MAC_GLYPH_NAMES, 0, glyphNames, 0, WGL4Names.NUMBER_OF_MAC_GLYPHS);
         }
         else if (formatType == 2.0f)
         {
@@ -89,10 +88,10 @@ public class PostScriptTable extends TTF
                 }
             }
             String[] nameArray = null;
-            if (maxIndex >= Encoding.NUMBER_OF_MAC_GLYPHS)
+            if (maxIndex >= WGL4Names.NUMBER_OF_MAC_GLYPHS)
             {
-                nameArray = new String[maxIndex - Encoding.NUMBER_OF_MAC_GLYPHS + 1];
-                for (int i = 0; i < maxIndex - Encoding.NUMBER_OF_MAC_GLYPHS + 1; i++)
+                nameArray = new String[maxIndex - WGL4Names.NUMBER_OF_MAC_GLYPHS + 1];
+                for (int i = 0; i < maxIndex - WGL4Names.NUMBER_OF_MAC_GLYPHS + 1; i++)
                 {
                     int numberOfChars = data.readUnsignedByte();
                     nameArray[i] = data.readString(numberOfChars);
@@ -101,13 +100,13 @@ public class PostScriptTable extends TTF
             for (int i = 0; i < numGlyphs; i++)
             {
                 int index = glyphNameIndex[i];
-                if (index < Encoding.NUMBER_OF_MAC_GLYPHS)
+                if (index < WGL4Names.NUMBER_OF_MAC_GLYPHS)
                 {
-                    glyphNames[i] = Encoding.MAC_GLYPH_NAMES[index];
+                    glyphNames[i] = WGL4Names.MAC_GLYPH_NAMES[index];
                 }
-                else if (index >= Encoding.NUMBER_OF_MAC_GLYPHS && index <= 32767)
+                else if (index >= WGL4Names.NUMBER_OF_MAC_GLYPHS && index <= 32767)
                 {
-                    glyphNames[i] = nameArray[index - Encoding.NUMBER_OF_MAC_GLYPHS];
+                    glyphNames[i] = nameArray[index - WGL4Names.NUMBER_OF_MAC_GLYPHS];
                 }
                 else
                 {
@@ -128,7 +127,7 @@ public class PostScriptTable extends TTF
             glyphNames = new String[glyphNameIndex.length];
             for (int i = 0; i < glyphNames.length; i++)
             {
-                String name = Encoding.MAC_GLYPH_NAMES[glyphNameIndex[i]];
+                String name = WGL4Names.MAC_GLYPH_NAMES[glyphNameIndex[i]];
                 if (name != null)
                 {
                     glyphNames[i] = name;

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java Sat Aug 30 02:26:57 2014
@@ -69,8 +69,7 @@ public class TTFParser
      */
     public TrueTypeFont parseTTF(String ttfFile) throws IOException
     {
-        RAFDataStream raf = new RAFDataStream(ttfFile, "r");
-        return parseTTF(raf);
+        return parseTTF(new File(ttfFile));
     }
 
     /**
@@ -82,8 +81,7 @@ public class TTFParser
      */
     public TrueTypeFont parseTTF(File ttfFile) throws IOException
     {
-        RAFDataStream raf = new RAFDataStream(ttfFile, "r");
-        return parseTTF(raf);
+        return parseTTF(new RAFDataStream(ttfFile, "r"));
     }
 
     /**
@@ -189,7 +187,7 @@ public class TTFParser
         }
 
         // check others mandatory tables
-        if (!isEmbedded && font.getCMAP() == null)
+        if (!isEmbedded && font.getCmap() == null)
         {
             throw new IOException("cmap is mandatory");
         }
@@ -199,9 +197,9 @@ public class TTFParser
     {
         TTFTable retval = null;
         String tag = raf.readString(4);
-        if (tag.equals(CMAPTable.TAG))
+        if (tag.equals(CmapTable.TAG))
         {
-            retval = new CMAPTable();
+            retval = new CmapTable();
         }
         else if (tag.equals(GlyphTable.TAG))
         {

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java Sat Aug 30 02:26:57 2014
@@ -16,30 +16,31 @@
  */
 package org.apache.fontbox.ttf;
 
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 import java.io.IOException;
 import java.io.InputStream;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.apache.fontbox.encoding.Encoding;
+import org.apache.fontbox.util.BoundingBox;
 
 /**
  * A TrueType font file.
  * 
  * @author Ben Litchfield
  */
-public class TrueTypeFont 
+public class TrueTypeFont implements Type1Equivalent
 {
-    private final Log log = LogFactory.getLog(TrueTypeFont.class);
-
     private float version;
     private int numberOfGlyphs = -1;
     private int unitsPerEm = -1;
     private int[] advanceWidths = null;
     private Map<String,TTFTable> tables = new HashMap<String,TTFTable>();
     private TTFDataStream data;
+    private Map<String, Integer> postScriptNames;
     
     /**
      * Constructor.  Clients should use the TTFParser to create a new TrueTypeFont object.
@@ -97,13 +98,23 @@ public class TrueTypeFont 
     {
         return tables.values();
     }
+
+    /**
+     * Get all of the tables.
+     *
+     * @return All of the tables.
+     */
+    public Map<String, TTFTable> getTableMap()
+    {
+        return tables;
+    }
     
     /**
      * This will get the naming table for the true type font.
      * 
      * @return The naming table.
      */
-    public NamingTable getNaming()
+    public synchronized NamingTable getNaming() throws IOException
     {
         NamingTable naming = (NamingTable)tables.get( NamingTable.TAG );
         if (naming != null && !naming.getInitialized())
@@ -118,7 +129,7 @@ public class TrueTypeFont 
      * 
      * @return The postscript table.
      */
-    public PostScriptTable getPostScript()
+    public synchronized PostScriptTable getPostScript() throws IOException
     {
         PostScriptTable postscript = (PostScriptTable)tables.get( PostScriptTable.TAG );
         if (postscript != null && !postscript.getInitialized())
@@ -133,7 +144,7 @@ public class TrueTypeFont 
      * 
      * @return The OS/2 table.
      */
-    public OS2WindowsMetricsTable getOS2Windows()
+    public synchronized OS2WindowsMetricsTable getOS2Windows() throws IOException
     {
         OS2WindowsMetricsTable os2WindowsMetrics = (OS2WindowsMetricsTable)tables.get( OS2WindowsMetricsTable.TAG );
         if (os2WindowsMetrics != null && !os2WindowsMetrics.getInitialized())
@@ -148,7 +159,7 @@ public class TrueTypeFont 
      * 
      * @return The maxp table.
      */
-    public MaximumProfileTable getMaximumProfile()
+    public synchronized MaximumProfileTable getMaximumProfile() throws IOException
     {
         MaximumProfileTable maximumProfile = (MaximumProfileTable)tables.get( MaximumProfileTable.TAG );
         if (maximumProfile != null && !maximumProfile.getInitialized())
@@ -163,7 +174,7 @@ public class TrueTypeFont 
      * 
      * @return The head table.
      */
-    public HeaderTable getHeader()
+    public synchronized HeaderTable getHeader() throws IOException
     {
         HeaderTable header = (HeaderTable)tables.get( HeaderTable.TAG );
         if (header != null && !header.getInitialized())
@@ -178,7 +189,7 @@ public class TrueTypeFont 
      * 
      * @return The hhea table.
      */
-    public HorizontalHeaderTable getHorizontalHeader()
+    public synchronized HorizontalHeaderTable getHorizontalHeader() throws IOException
     {
         HorizontalHeaderTable horizontalHeader = (HorizontalHeaderTable)tables.get( HorizontalHeaderTable.TAG );
         if (horizontalHeader != null && !horizontalHeader.getInitialized())
@@ -193,7 +204,7 @@ public class TrueTypeFont 
      * 
      * @return The hmtx table.
      */
-    public HorizontalMetricsTable getHorizontalMetrics()
+    public synchronized HorizontalMetricsTable getHorizontalMetrics() throws IOException
     {
         HorizontalMetricsTable horizontalMetrics = (HorizontalMetricsTable)tables.get( HorizontalMetricsTable.TAG );
         if (horizontalMetrics != null && !horizontalMetrics.getInitialized())
@@ -208,7 +219,7 @@ public class TrueTypeFont 
      * 
      * @return The loca table.
      */
-    public IndexToLocationTable getIndexToLocation()
+    public synchronized IndexToLocationTable getIndexToLocation() throws IOException
     {
         IndexToLocationTable indexToLocation = (IndexToLocationTable)tables.get( IndexToLocationTable.TAG );
         if (indexToLocation != null && !indexToLocation.getInitialized())
@@ -223,7 +234,7 @@ public class TrueTypeFont 
      * 
      * @return The glyf table.
      */
-    public GlyphTable getGlyph()
+    public synchronized GlyphTable getGlyph() throws IOException
     {
         GlyphTable glyph = (GlyphTable)tables.get( GlyphTable.TAG );
         if (glyph != null && !glyph.getInitialized())
@@ -234,13 +245,13 @@ public class TrueTypeFont 
     }
     
     /**
-     * Get the cmap table for this TTF.
+     * Get the "cmap" table for this TTF.
      * 
-     * @return The cmap table.
+     * @return The "cmap" table.
      */
-    public CMAPTable getCMAP()
+    public synchronized CmapTable getCmap() throws IOException
     {
-        CMAPTable cmap = (CMAPTable)tables.get( CMAPTable.TAG );
+        CmapTable cmap = (CmapTable)tables.get( CmapTable.TAG );
         if (cmap != null && !cmap.getInitialized())
         {
             readTable(cmap);
@@ -267,21 +278,14 @@ public class TrueTypeFont 
      * 
      * @param table the table to be initialized
      */
-    void readTable(TTFTable table)
+    void readTable(TTFTable table) throws IOException
     {
-        try
-        {
-            // save current position
-            long currentPosition = data.getCurrentPosition();
-            data.seek(table.getOffset());
-            table.read(this, data);
-            // restore current position
-            data.seek(currentPosition);
-        }
-        catch (IOException exception)
-        {
-            log.error("An error occured when reading table " + table.getTag(), exception);
-        }
+        // save current position
+        long currentPosition = data.getCurrentPosition();
+        data.seek(table.getOffset());
+        table.read(this, data);
+        // restore current position
+        data.seek(currentPosition);
     }
 
     /**
@@ -289,7 +293,7 @@ public class TrueTypeFont 
      * 
      * @return the number of glyphs
      */
-    public int getNumberOfGlyphs()
+    public int getNumberOfGlyphs() throws IOException
     {
         if (numberOfGlyphs == -1)
         {
@@ -312,7 +316,7 @@ public class TrueTypeFont 
      * 
      * @return units per EM
      */
-    public int getUnitsPerEm()
+    public int getUnitsPerEm() throws IOException
     {
         if (unitsPerEm == -1)
         {
@@ -331,12 +335,12 @@ public class TrueTypeFont 
     }
 
     /**
-     * Returns the width for the given glyph code.
+     * Returns the width for the given GID.
      * 
-     * @param code the glyph code
+     * @param gid the GID
      * @return the width
      */
-    public int getAdvanceWidth(int code)
+    public int getAdvanceWidth(int gid) throws IOException
     {
         if (advanceWidths == null)
         {
@@ -351,9 +355,9 @@ public class TrueTypeFont 
                 advanceWidths = new int[]{250};
             }
         }
-        if (advanceWidths.length > code)
+        if (advanceWidths.length > gid)
         {
-            return advanceWidths[code];
+            return advanceWidths[gid];
         }
         else
         {
@@ -362,4 +366,144 @@ public class TrueTypeFont 
             return advanceWidths[advanceWidths.length-1];
         }
     }
+
+    @Override
+    public String getFullName() throws IOException
+    {
+        if (getNaming() != null)
+        {
+            return getNaming().getPostScriptName();
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    private synchronized void readPostScriptNames() throws IOException
+    {
+        if (postScriptNames == null)
+        {
+            postScriptNames = new HashMap<String, Integer>();
+            if (getPostScript() != null)
+            {
+                String[] names = getPostScript().getGlyphNames();
+                if (names != null)
+                {
+                    for (int i = 0; i < names.length; i++)
+                    {
+                        postScriptNames.put(names[i], i);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the GID for the given PostScript name, if the "post" table is present.
+     */
+    public int nameToGID(String name) throws IOException
+    {
+        readPostScriptNames();
+
+        GlyphData[] glyphs = getGlyph().getGlyphs();
+        Integer gid = postScriptNames.get(name);
+        if (gid == null || gid < 0 || gid >= glyphs.length)
+        {
+            return 0;
+        }
+        return gid;
+    }
+
+    @Override
+    public GeneralPath getPath(String name) throws IOException
+    {
+        readPostScriptNames();
+
+        GlyphData[] glyphs = getGlyph().getGlyphs();
+        Integer gid = postScriptNames.get(name);
+        if (gid == null || gid < 0 || gid >= glyphs.length)
+        {
+            gid = 0;
+        }
+
+        // some glyphs have no outlines (e.g. space, table, newline)
+        if (glyphs[gid] == null)
+        {
+            return new GeneralPath();
+        }
+        else
+        {
+            GeneralPath path = glyphs[gid].getPath();
+
+            // scale to 1000upem, per PostScript convention
+            float scale = 1000f / getUnitsPerEm();
+            AffineTransform atScale = AffineTransform.getScaleInstance(scale, scale);
+            path.transform(atScale);
+
+            return path;
+        }
+    }
+
+    @Override
+    public float getWidth(String name) throws IOException
+    {
+        readPostScriptNames();
+
+        Integer gid = postScriptNames.get(name);
+        int width = getAdvanceWidth(gid);
+        int unitsPerEM = getUnitsPerEm();
+        if (unitsPerEM != 1000)
+        {
+            width *= 1000f / unitsPerEM;
+        }
+        return width;
+    }
+
+    @Override
+    public boolean hasGlyph(String name) throws IOException
+    {
+        readPostScriptNames();
+
+        Integer gid = postScriptNames.get(name);
+        GlyphData[] glyphs = getGlyph().getGlyphs();
+        return !(gid == null || gid < 0 || gid >= glyphs.length);
+    }
+
+    @Override
+    public Encoding getEncoding()
+    {
+        return null;
+    }
+
+    @Override
+    public BoundingBox getFontBBox() throws IOException
+    {
+        short xMin = getHeader().getXMin();
+        short xMax = getHeader().getXMax();
+        short yMin = getHeader().getYMin();
+        short yMax = getHeader().getYMax();
+        float scale = 1000f / getUnitsPerEm();
+        return new BoundingBox(xMin * scale, yMin * scale, xMax * scale, yMax * scale);
+    }
+
+    @Override
+    public String toString()
+    {
+        try
+        {
+            if (getNaming() != null)
+            {
+                return getNaming().getPostScriptName();
+            }
+            else
+            {
+                return "(null)";
+            }
+        }
+        catch (IOException e)
+        {
+            return "(null - " + e.getMessage() + ")";
+        }
+    }
 }

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java Sat Aug 30 02:26:57 2014
@@ -21,23 +21,25 @@ import org.apache.fontbox.cff.Type1CharS
 import org.apache.fontbox.cff.Type1CharStringParser;
 import org.apache.fontbox.encoding.Encoding;
 import org.apache.fontbox.pfb.PfbParser;
+import org.apache.fontbox.ttf.Type1Equivalent;
+import org.apache.fontbox.util.BoundingBox;
 
+import java.awt.geom.GeneralPath;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
- * Represents an Adobe Type 1 (.pfb) font.
+ * Represents an Adobe Type 1 (.pfb) font. Thread safe.
  *
  * @author John Hewson
  */
-public final class Type1Font implements Type1CharStringReader
+public final class Type1Font implements Type1CharStringReader, Type1Equivalent
 {
     /**
      * Constructs a new Type1Font object from a .pfb stream.
@@ -109,8 +111,8 @@ public final class Type1Font implements 
     final Map<String, byte[]> charstrings = new LinkedHashMap<String, byte[]>();
 
     // private caches
-    private final Map<String, Type1CharString> charStringCache = new HashMap<String, Type1CharString>();
-    private Collection<Mapping> mappings;
+    private final Map<String, Type1CharString> charStringCache =
+            new ConcurrentHashMap<String, Type1CharString>();
 
     /**
      * Constructs a new Type1Font, called by Type1Parser.
@@ -139,112 +141,41 @@ public final class Type1Font implements 
         return Collections.unmodifiableMap(charstrings);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public Type1CharString getType1CharString(String name) throws IOException
+    @Override
+    public GeneralPath getPath(String name) throws IOException
     {
-        Type1CharString type1 = charStringCache.get(name);
-        if (type1 == null)
-        {
-            Type1CharStringParser parser = new Type1CharStringParser(fontName, name);
-            List<Object> sequence = parser.parse(charstrings.get(name), subrs);
-            type1 = new Type1CharString(this, fontName, name, sequence);
-            charStringCache.put(name, type1);
-        }
-        return type1;
+        return getType1CharString(name).getPath();
     }
 
-    /**
-     * Get the mappings for the font as Type1Mapping.
-     *
-     * @return the Type1Mapping
-     */
-    public Collection<? extends Type1Mapping> getType1Mappings()
+    @Override
+    public float getWidth(String name) throws IOException
     {
-        return getMappings();
+        return getType1CharString(name).getWidth();
     }
 
-    /**
-     * Get the mapping (code/charname/bytes) for this font.
-     *
-     * @return mappings for character codes
-     */
-    public Collection<Type1Font.Mapping> getMappings()
+    @Override
+    public boolean hasGlyph(String name)
     {
-        if (mappings == null)
-        {
-            mappings = new ArrayList<Mapping>();
-            for (String name : getCharStringsDict().keySet())
-            {
-                Integer code = encoding.getCode(name);
-                if (code == null)
-                {
-                    code = 0; // .notdef
-                }
-                Mapping mapping = new Mapping();
-                mapping.setCode(code);
-                mapping.setName(name);
-                mapping.setBytes(getCharStringsDict().get(name));
-                mappings.add(mapping);
-            }
-            mappings = Collections.unmodifiableCollection(mappings);
-        }
-        return mappings;
+        return charstrings.get(name) != null;
     }
 
-    public class Mapping implements Type1Mapping
+    @Override
+    public Type1CharString getType1CharString(String name) throws IOException
     {
-        private int mappedCode;
-        private String mappedName;
-        private byte[] mappedBytes;
-
-        /**
-         * {@inheritDoc}
-         */
-        public Type1CharString getType1CharString() throws IOException
-        {
-            return Type1Font.this.getType1CharString(mappedName);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public int getCode()
-        {
-            return mappedCode;
-        }
-
-        private void setCode(int code)
-        {
-            mappedCode = code;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public String getName()
-        {
-            return mappedName;
-        }
-
-        private void setName(String name)
-        {
-            this.mappedName = name;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public byte[] getBytes()
-        {
-            return mappedBytes;
-        }
-
-        private void setBytes(byte[] bytes)
+        Type1CharString type1 = charStringCache.get(name);
+        if (type1 == null)
         {
-            this.mappedBytes = bytes;
+            byte[] bytes = charstrings.get(name);
+            if (bytes == null)
+            {
+                bytes = charstrings.get(".notdef");
+            }
+            Type1CharStringParser parser = new Type1CharStringParser(fontName, name);
+            List<Object> sequence = parser.parse(bytes, subrs);
+            type1 = new Type1CharString(this, fontName, name, sequence);
+            charStringCache.put(name, type1);
         }
+        return type1;
     }
 
     // font dictionary
@@ -303,9 +234,9 @@ public final class Type1Font implements 
      * 
      * @return the font bounding box
      */
-    public List<Number> getFontBBox()
+    public BoundingBox getFontBBox()
     {
-        return Collections.unmodifiableList(fontBBox);
+        return new BoundingBox(fontBBox);
     }
 
     /**
@@ -365,6 +296,7 @@ public final class Type1Font implements 
      * 
      * @return the full name
      */
+    @Override
     public String getFullName()
     {
         return fullName;

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/util/BoundingBox.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/util/BoundingBox.java?rev=1621411&r1=1621410&r2=1621411&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/util/BoundingBox.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/util/BoundingBox.java Sat Aug 30 02:26:57 2014
@@ -17,6 +17,8 @@
 package org.apache.fontbox.util;
 
 
+import java.util.List;
+
 /**
  * This is an implementation of a bounding box.  This was originally written for the
  * AMF parser.
@@ -52,6 +54,20 @@ public class BoundingBox
         upperRightX = maxX;
         upperRightY = maxY;
     }
+
+    /**
+     * Constructor.
+     *
+     * @param numbers list of four numbers
+     */
+    public BoundingBox(List<Number> numbers)
+    {
+        lowerLeftX = numbers.get(0).floatValue();
+        lowerLeftY = numbers.get(1).floatValue();
+        upperRightX = numbers.get(2).floatValue();
+        upperRightY = numbers.get(3).floatValue();
+    }
+
     /**
      * Getter for property lowerLeftX.
      *