pdfbox-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From le...@apache.org
Subject svn commit: r1559225 [1/2] - in /pdfbox/trunk: fontbox/src/main/java/org/apache/fontbox/cff/ fontbox/src/main/java/org/apache/fontbox/encoding/ fontbox/src/main/java/org/apache/fontbox/pfb/ fontbox/src/main/java/org/apache/fontbox/type1/ fontbox/src/te...
Date Fri, 17 Jan 2014 19:09:27 GMT
Author: lehmi
Date: Fri Jan 17 19:09:26 2014
New Revision: 1559225

URL: http://svn.apache.org/r1559225
Log:
PDFBOX-1844: added a type1 parser to fontbox, pdfbox doesn't use the AWT to render embedded type1 fonts as proposed by John Hewson

Added:
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/encoding/CustomEncoding.java   (with props)
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Token.java   (with props)
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1CharStringReader.java   (with props)
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java   (with props)
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Lexer.java   (with props)
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Mapping.java   (with props)
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Parser.java   (with props)
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/package.html   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/Type1Glyph2D.java   (with props)
Removed:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/CFFGlyph2D.java
Modified:
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFontROS.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringHandler.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/DataInput.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/encoding/Encoding.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/pfb/PfbParser.java
    pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cff/Type1CharStringTest.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/PageDrawer.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/Glyph2D.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/TTFGlyph2D.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java?rev=1559225&r1=1559224&r2=1559225&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java Fri Jan 17 19:09:26 2014
@@ -21,6 +21,8 @@ import java.util.*;
 
 import org.apache.fontbox.cff.charset.CFFCharset;
 import org.apache.fontbox.cff.encoding.CFFEncoding;
+import org.apache.fontbox.type1.Type1CharStringReader;
+import org.apache.fontbox.type1.Type1Mapping;
 
 /**
  * This class represents a CFF/Type2 Font.
@@ -28,7 +30,7 @@ import org.apache.fontbox.cff.encoding.C
  * @author Villu Ruusmann
  * @author John Hewson
  */
-public class CFFFont
+public class CFFFont implements Type1CharStringReader
 {
     private String fontname = null;
     private Map<String, Object> topDict = new LinkedHashMap<String, Object>();
@@ -130,11 +132,21 @@ public class CFFFont
     }
 
     /**
+     * Get the mappings for the font as Type1Mapping
+     *
+     * @return the Type1Mapping
+     */
+    public Collection<? extends Type1Mapping> getType1Mappings()
+    {
+        return getMappings();
+    }
+
+    /**
      * Get the mapping (code/SID/charname/bytes) for this font.
      * 
      * @return mappings for codes < 256 and for codes > = 256
      */
-    public Collection<Mapping> getMappings()
+    public Collection<CFFFont.Mapping> getMappings()
     {
         List<Mapping> mappings = new ArrayList<Mapping>();
         Set<String> mappedNames = new HashSet<String>();
@@ -151,11 +163,7 @@ public class CFFFont
             {
                 continue;
             }
-            Mapping mapping = new Mapping();
-            mapping.setCode(entry.getCode());
-            mapping.setSID(entry.getSID());
-            mapping.setName(charName);
-            mapping.setBytes(bytes);
+            Mapping mapping = createMapping(entry.getCode(), entry.getSID(), charName, bytes);
             mappings.add(mapping);
             mappedNames.add(charName);
         }
@@ -175,11 +183,7 @@ public class CFFFont
                 {
                     continue;
                 }
-                Mapping mapping = new Mapping();
-                mapping.setCode(supplement.getCode());
-                mapping.setSID(supplement.getGlyph());
-                mapping.setName(charName);
-                mapping.setBytes(bytes);
+                Mapping mapping = createMapping(supplement.getCode(), supplement.getGlyph(), charName, bytes);
                 mappings.add(mapping);
                 mappedNames.add(charName);
             }
@@ -198,20 +202,33 @@ public class CFFFont
             {
                 continue;
             }
-            Mapping mapping = new Mapping();
-            mapping.setCode(code++);
-            mapping.setSID(entry.getSID());
-            mapping.setName(name);
-            mapping.setBytes(bytes);
-
+            Mapping mapping = createMapping(code++, entry.getSID(), name, bytes);
             mappings.add(mapping);
-
             mappedNames.add(name);
         }
         return mappings;
     }
 
     /**
+     * Returns a new mapping. Overridden in subclasses.
+     *
+     * @param code chatacter code
+     * @param sid SID
+     * @param name glyph name
+     * @param bytes charstring bytes
+     * @return a new mapping object
+     */
+    protected Mapping createMapping(int code, int sid, String name, byte[] bytes)
+    {
+        Mapping mapping = new Mapping();
+        mapping.setCode(code);
+        mapping.setSID(sid);
+        mapping.setName(name);
+        mapping.setBytes(bytes);
+        return  mapping;
+    }
+
+    /**
      * Return the Width value of the given Glyph identifier.
      * 
      * @param sid SID
@@ -320,11 +337,7 @@ public class CFFFont
     }
 
     /**
-     * Returns the Type 1 CharString for the character with the given name.
-     *
-     * @return Type 1 CharString
-     * @throws IOException if something went wrong
-     *
+     * {@inheritDoc}
      */
     public Type1CharString getType1CharString(String name) throws IOException
     {
@@ -343,7 +356,7 @@ public class CFFFont
         {
             Type2CharStringParser parser = new Type2CharStringParser();
             List<Object> type2seq = parser.parse(charStringsDict.get(name), globalSubrIndex, localSubrIndex);
-            type2 = new Type2CharString(this, type2seq, getDefaultWidthX(sid), getNominalWidthX(sid));
+            type2 = new Type2CharString(this, fontname, name, type2seq, getDefaultWidthX(sid), getNominalWidthX(sid));
             charStringCache.put(name, type2);
         }
         return type2;
@@ -432,9 +445,9 @@ public class CFFFont
     }
 
     /**
-     * This class is used for the font mapping.
+     * {@inheritDoc}
      */
-    public class Mapping
+    public class Mapping implements Type1Mapping
     {
         private int mappedCode;
         private int mappedSID;
@@ -442,10 +455,7 @@ public class CFFFont
         private byte[] mappedBytes;
 
         /**
-         * Returns the Type 1 CharString for the character.
-         *
-         * @return the Type 1 CharString
-         * @throws IOException if an error occurs during reading
+         * {@inheritDoc}
          */
         public Type1CharString getType1CharString() throws IOException
         {
@@ -453,23 +463,21 @@ public class CFFFont
         }
 
         /**
-         * Gets the value for the code.
-         * 
-         * @return the code
+         * {@inheritDoc}
          */
         public int getCode()
         {
             return mappedCode;
         }
 
-        private void setCode(int code)
+        protected void setCode(int code)
         {
             mappedCode = code;
         }
 
         /**
          * Gets the value for the SID.
-         * 
+         *
          * @return the SID
          */
         public int getSID()
@@ -477,37 +485,33 @@ public class CFFFont
             return mappedSID;
         }
 
-        private void setSID(int sid)
+        protected void setSID(int sid)
         {
             this.mappedSID = sid;
         }
 
         /**
-         * Gets the value for the name.
-         * 
-         * @return the name
+         * {@inheritDoc}
          */
         public String getName()
         {
             return mappedName;
         }
 
-        private void setName(String name)
+        protected void setName(String name)
         {
             this.mappedName = name;
         }
 
         /**
-         * Gets the value for the bytes.
-         * 
-         * @return the bytes
+         * {@inheritDoc}
          */
         public byte[] getBytes()
         {
             return mappedBytes;
         }
 
-        private void setBytes(byte[] bytes)
+        protected void setBytes(byte[] bytes)
         {
             this.mappedBytes = bytes;
         }

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFontROS.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFontROS.java?rev=1559225&r1=1559224&r2=1559225&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFontROS.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFontROS.java Fri Jan 17 19:09:26 2014
@@ -158,6 +158,19 @@ public class CFFFontROS extends CFFFont
     }
 
     /**
+     * {@inheritDoc}
+     */
+    protected Mapping createMapping(int code, int sid, String name, byte[] bytes)
+    {
+        Mapping mapping = new Mapping();
+        mapping.setCode(sid); // code = sid
+        mapping.setSID(sid);
+        mapping.setName(name);
+        mapping.setBytes(bytes);
+        return  mapping;
+    }
+
+    /**
      * Returns the Width value of the given Glyph identifier
      *
      * @param cid CID

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringHandler.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringHandler.java?rev=1559225&r1=1559224&r2=1559225&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringHandler.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringHandler.java Fri Jan 17 19:09:26 2014
@@ -18,11 +18,13 @@ package org.apache.fontbox.cff;
 
 
 import java.util.List;
+import java.util.Stack;
 
 /**
  * A Handler for CharStringCommands.
  *
  * @author Villu Ruusmann
+ * @author John Hewson
  * 
  */
 public abstract class CharStringHandler
@@ -33,21 +35,26 @@ public abstract class CharStringHandler
      * @param sequence of CharStringCommands
      *
      */
-    @SuppressWarnings(value = { "unchecked" })
-    public void handleSequence(List<Object> sequence)
+    public List<Integer> handleSequence(List<Object> sequence)
     {
-        int offset = 0;
-        int size = sequence.size();
-        for (int i = 0; i < size; i++)
+        Stack<Integer> stack = new Stack<Integer>();
+        for (Object obj : sequence)
         {
-            Object object = sequence.get(i);
-            if (object instanceof CharStringCommand)
+            if (obj instanceof CharStringCommand)
             {
-                List<Integer> numbers = (List) sequence.subList(offset, i);
-                handleCommand(numbers, (CharStringCommand) object);
-                offset = i + 1;
+                List<Integer> results = handleCommand(stack, (CharStringCommand)obj);
+                stack.clear();  // this is basically returning the new stack
+                if (results != null)
+                {
+                    stack.addAll(results);
+                }
+            }
+            else
+            {
+                stack.push((Integer)obj);
             }
         }
+        return stack;
     }
 
     /**
@@ -56,5 +63,5 @@ public abstract class CharStringHandler
      * @param numbers a list of numbers
      * @param command the CharStringCommand
      */
-    public abstract void handleCommand(List<Integer> numbers, CharStringCommand command);
+    public abstract List<Integer> handleCommand(List<Integer> numbers, CharStringCommand command);
 }
\ No newline at end of file

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/DataInput.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/DataInput.java?rev=1559225&r1=1559224&r2=1559225&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/DataInput.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/DataInput.java Fri Jan 17 19:09:26 2014
@@ -103,6 +103,21 @@ public class DataInput
     }
 
     /**
+     * Peeks one single unsigned byte from the buffer.
+     * @return the unsigned byte as int
+     * @throws IOException if an error occurs during reading
+     */
+    public int peekUnsignedByte(int offset) throws IOException
+    {
+        int b = peek(offset);
+        if (b < 0)
+        {
+            throw new EOFException();
+        }
+        return b;
+    }
+
+    /**
      * Read one single short value from the buffer.
      * @return the short value
      * @throws IOException if an error occurs during reading
@@ -175,4 +190,17 @@ public class DataInput
             return -1;
         }
     }
+
+    private int peek(int offset)
+    {
+        try
+        {
+            int value = inputBuffer[bufferPosition + offset] & 0xff;
+            return value;
+        }
+        catch (RuntimeException re)
+        {
+            return -1;
+        }
+    }
 }
\ No newline at end of file

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java?rev=1559225&r1=1559224&r2=1559225&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java Fri Jan 17 19:09:26 2014
@@ -19,12 +19,15 @@ package org.apache.fontbox.cff;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.fontbox.encoding.StandardEncoding;
+import org.apache.fontbox.type1.Type1CharStringReader;
 
+import java.awt.Point;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.GeneralPath;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -37,31 +40,37 @@ public class Type1CharString
 {
     private static final Log LOG = LogFactory.getLog(Type1CharString.class);
 
-    private CFFFont cffFont;
+    private Type1CharStringReader reader;
+    private String fontName, glyphName;
     private GeneralPath path = null;
     private int width = 0;
-    private Point2D leftSideBearing = null;
-    private Point2D referencePoint = null;
+    private Point2D.Float leftSideBearing = null;
+    private Point2D.Float current = null;
+    private boolean isFlex = false;
+    private List<Point.Float> flexPoints = new ArrayList<Point2D.Float>();
     protected List<Object> type1Sequence;
 
     /**
      * Constructs a new Type1CharString object.
-     * @param font Parent CFF font
+     * @param reader Parent Type 1 CharString reader
      * @param sequence Type 1 char string sequence
      */
-    public Type1CharString(CFFFont font, List<Object> sequence)
+    public Type1CharString(Type1CharStringReader reader, String fontName, String glyphName, List<Object> sequence)
     {
-        this(font);
+        this(reader, fontName, glyphName);
         type1Sequence = sequence;
     }
 
     /**
      * Constructor for use in subclasses.
-     * @param font Parent CFF font
+     * @param reader Parent Type 1 CharString reader
      */
-    protected Type1CharString(CFFFont font)
+    protected Type1CharString(Type1CharStringReader reader, String fontName, String glyphName)
     {
-        cffFont = font;
+        this.reader = reader;
+        this.fontName = fontName;
+        this.glyphName = glyphName;
+        this.current = new Point2D.Float(0, 0);
     }
 
     /**
@@ -96,7 +105,6 @@ public class Type1CharString
      */
     public GeneralPath getPath()
     {
-        //TODO does not need to be lazy anymore?
         if (path == null)
         {
           render();
@@ -120,24 +128,54 @@ public class Type1CharString
     {
         path = new GeneralPath();
         leftSideBearing = new Point2D.Float(0, 0);
-        referencePoint = null;
         width = 0;
         CharStringHandler handler = new CharStringHandler() {
-            public void handleCommand(List<Integer> numbers, CharStringCommand command)
+            public List<Integer> handleCommand(List<Integer> numbers, CharStringCommand command)
             {
-                Type1CharString.this.handleCommand(numbers, command);
+                return Type1CharString.this.handleCommand(numbers, command);
             }
         };
         handler.handleSequence(type1Sequence);
     }
 
-    private void handleCommand(List<Integer> numbers, CharStringCommand command)
+    private List<Integer> handleCommand(List<Integer> numbers, CharStringCommand command)
     {
         String name = CharStringCommand.TYPE1_VOCABULARY.get(command.getKey());
 
-        if ("vmoveto".equals(name))
+        if ("rmoveto".equals(name))
         {
-            rmoveTo(0, numbers.get(0));
+            if (isFlex)
+            {
+                flexPoints.add(new Point2D.Float(numbers.get(0), numbers.get(1)));
+            }
+            else
+            {
+                rmoveTo(numbers.get(0), numbers.get(1));
+            }
+        }
+        else if ("vmoveto".equals(name))
+        {
+            if (isFlex)
+            {
+                // not in the Type 1 spec, but exists in some fonts
+                flexPoints.add(new Point2D.Float(0, numbers.get(0)));
+            }
+            else
+            {
+                rmoveTo(0, numbers.get(0));
+            }
+        }
+        else if ("hmoveto".equals(name))
+        {
+            if (isFlex)
+            {
+                // not in the Type 1 spec, but exists in some fonts
+                flexPoints.add(new Point2D.Float(numbers.get(0), 0));
+            }
+            else
+            {
+                rmoveTo(numbers.get(0), 0);
+            }
         }
         else if ("rlineto".equals(name))
         {
@@ -153,8 +191,8 @@ public class Type1CharString
         }
         else if ("rrcurveto".equals(name))
         {
-            rrcurveTo(numbers.get(0), numbers.get(1), numbers.get(2), numbers
-                .get(3), numbers.get(4), numbers.get(5));
+            rrcurveTo(numbers.get(0), numbers.get(1), numbers.get(2),
+                    numbers.get(3), numbers.get(4), numbers.get(5));
         }
         else if ("closepath".equals(name))
         {
@@ -164,19 +202,13 @@ public class Type1CharString
         {
             leftSideBearing = new Point2D.Float(numbers.get(0), numbers.get(1));
             width = numbers.get(2);
+            current.setLocation(leftSideBearing);
         }
         else if ("hsbw".equals(name))
         {
             leftSideBearing = new Point2D.Float(numbers.get(0), 0);
             width = numbers.get(1);
-        }
-        else if ("rmoveto".equals(name))
-        {
-            rmoveTo(numbers.get(0), numbers.get(1));
-        }
-        else if ("hmoveto".equals(name))
-        {
-            rmoveTo(numbers.get(0), 0);
+            current.setLocation(leftSideBearing);
         }
         else if ("vhcurveto".equals(name))
         {
@@ -186,31 +218,112 @@ public class Type1CharString
         else if ("hvcurveto".equals(name))
         {
             rrcurveTo(numbers.get(0), 0, numbers.get(1),
-                numbers.get(2), 0, numbers.get(3));
+                    numbers.get(2), 0, numbers.get(3));
         }
         else if ("seac".equals(name))
         {
             seac(numbers.get(0), numbers.get(1), numbers.get(2), numbers.get(3), numbers.get(4));
         }
+        else if ("setcurrentpoint".equals(name))
+        {
+            setcurrentpoint(numbers.get(0), numbers.get(1));
+        }
+        else if ("callothersubr".equals(name))
+        {
+            callothersubr(numbers.get(0));
+        }
+        else if ("div".equals(name))
+        {
+            int b = numbers.get(numbers.size() -1);
+            int a = numbers.get(numbers.size() -2);
+
+            int result = a / b; // TODO loss of precision, should be float
+
+            List<Integer> list = new ArrayList<Integer>(numbers);
+            numbers.remove(numbers.size() - 1);
+            numbers.remove(numbers.size() - 1);
+            list.add(result);
+            return list;
+        }
+        else if ("hstem".equals(name) || "vstem".equals(name) ||
+                 "hstem3".equals(name) || "vstem3".equals(name) || "dotsection".equals(name))
+        {
+            // ignore hints
+        }
+        else if ("endchar".equals(name))
+        {
+            // end
+        }
+        else
+        {
+            // indicates a PDFBox bug
+            throw new IllegalArgumentException("Unknown command: " + name);
+        }
+        return null;
     }
 
     /**
-     * Relative moveto.
+     * Sets the current absolute point without performing a moveto.
+     * Used only with results from callothersubr
      */
-    private void rmoveTo(Number dx, Number dy)
+    private void setcurrentpoint(int x, int y)
+    {
+        current.setLocation(x, y);
+    }
+
+    /**
+     * Flex (via OtherSubrs)
+     * @param num OtherSubrs entry number
+     */
+    private void callothersubr(int num)
     {
-        Point2D point = referencePoint;
-        if (point == null)
+        if (num == 0)
         {
-            point = path.getCurrentPoint();
-            if (point == null)
-            {
-                point = leftSideBearing;
-            }
+            // end flex
+            isFlex = false;
+
+            // reference point is relative to start point
+            Point.Float reference = flexPoints.get(0);
+            reference.setLocation(current.getX() + reference.getX(), current.getY() + reference.getY());
+
+            // first point is relative to reference point
+            Point.Float first = flexPoints.get(1);
+            first.setLocation(reference.getX() + first.getX(), reference.getY() + first.getY());
+
+            // make the first point relative to the start point
+            first.setLocation(first.getX() - current.getX(), first.getY() - current.getY());
+
+            rrcurveTo(flexPoints.get(1).getX(), flexPoints.get(1).getY(),
+                    flexPoints.get(2).getX(), flexPoints.get(2).getY(),
+                    flexPoints.get(3).getX(), flexPoints.get(3).getY());
+
+            rrcurveTo(flexPoints.get(4).getX(), flexPoints.get(4).getY(),
+                    flexPoints.get(5).getX(), flexPoints.get(5).getY(),
+                    flexPoints.get(6).getX(), flexPoints.get(6).getY());
+
+            flexPoints.clear();
+        }
+        else if (num == 1)
+        {
+            // begin flex
+            isFlex = true;
+        }
+        else
+        {
+            // indicates a PDFBox bug
+            throw new IllegalArgumentException("Unexpected other subroutine: " + num);
         }
-        referencePoint = null;
-        path.moveTo((float)(point.getX() + dx.doubleValue()),
-                    (float)(point.getY() + dy.doubleValue()));
+    }
+
+    /**
+     * Relative moveto.
+     */
+    private void rmoveTo(Number dx, Number dy)
+    {
+        float x = (float)current.getX() + dx.floatValue();
+        float y = (float)current.getY() + dy.floatValue();
+        path.moveTo(x, y);
+        current.setLocation(x, y);
     }
 
     /**
@@ -218,9 +331,10 @@ public class Type1CharString
      */
     private void rlineTo(Number dx, Number dy)
     {
-        Point2D point = path.getCurrentPoint();
-        path.lineTo((float)(point.getX() + dx.doubleValue()),
-                    (float)(point.getY() + dy.doubleValue()));
+        float x = (float)current.getX() + dx.floatValue();
+        float y = (float)current.getY() + dy.floatValue();
+        path.lineTo(x, y);
+        current.setLocation(x, y);
     }
 
     /**
@@ -229,14 +343,14 @@ public class Type1CharString
     private void rrcurveTo(Number dx1, Number dy1, Number dx2, Number dy2,
             Number dx3, Number dy3)
     {
-        Point2D point = path.getCurrentPoint();
-        float x1 = (float) point.getX() + dx1.floatValue();
-        float y1 = (float) point.getY() + dy1.floatValue();
+        float x1 = (float) current.getX() + dx1.floatValue();
+        float y1 = (float) current.getY() + dy1.floatValue();
         float x2 = x1 + dx2.floatValue();
         float y2 = y1 + dy2.floatValue();
         float x3 = x2 + dx3.floatValue();
         float y3 = y2 + dy3.floatValue();
         path.curveTo(x1, y1, x2, y2, x3, y3);
+        current.setLocation(x3, y3);
     }
 
     /**
@@ -244,8 +358,8 @@ public class Type1CharString
      */
     private void closepath()
     {
-        referencePoint = path.getCurrentPoint();
         path.closePath();
+        path.moveTo(current.getX(), current.getY());
     }
 
     /**
@@ -261,12 +375,12 @@ public class Type1CharString
         {
             try
             {
-                Type1CharString base = cffFont.getType1CharString(baseName);
+                Type1CharString base = reader.getType1CharString(baseName);
                 path.append(base.getPath().getPathIterator(null), false);
             }
             catch (IOException e)
             {
-                LOG.warn("invalid character in seac command");
+                LOG.warn("invalid seac character in glyph " + glyphName + " of font " + fontName);
             }
         }
         // accent character
@@ -275,7 +389,7 @@ public class Type1CharString
         {
             try
             {
-                Type1CharString accent = cffFont.getType1CharString(accentName);
+                Type1CharString accent = reader.getType1CharString(accentName);
                 AffineTransform at = AffineTransform.getTranslateInstance(
                     leftSideBearing.getX() + adx.floatValue(),
                     leftSideBearing.getY() + ady.floatValue());
@@ -283,7 +397,7 @@ public class Type1CharString
             }
             catch (IOException e)
             {
-                LOG.warn("invalid character in seac command");
+                LOG.warn("invalid seac character in glyph " + glyphName + " of font " + fontName);
             }
         }
     }

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java?rev=1559225&r1=1559224&r2=1559225&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java Fri Jan 17 19:09:26 2014
@@ -16,85 +16,144 @@
  */
 package org.apache.fontbox.cff;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Stack;
 
 /**
- * This class represents a converter for a mapping into a Type1-sequence.
+ * This class represents a converter for a mapping into a Type 1 sequence.
+ *
+ * @see "Adobe Type 1 Font Format, Adobe Systems (1999)"
+ *
  * @author Villu Ruusmann
- * @version $Revision: 1.0 $
+ * @author John Hewson
  */
 public class Type1CharStringParser
 {
+    private static final Log LOG = LogFactory.getLog(Type1CharStringParser.class);
+
+    // 1-byte commands
+    final static int RETURN = 11;
+    final static int CALLSUBR = 10;
+
+    // 2-byte commands
+    final static int TWO_BYTE = 12;
+    final static int CALLOTHERSUBR = 16;
+    final static int POP = 17;
 
-    private DataInput input = null;
-    private List<Object> sequence = null;
+    private String fontName, glyphName;
+
+    /**
+     * Constructs a new Type1CharStringParser object.
+     *
+     * @param fontName font name
+     * @param glyphName glyph name
+     */
+    public Type1CharStringParser(String fontName, String glyphName)
+    {
+        this.fontName = fontName;
+        this.glyphName = glyphName;
+    }
 
     /**
      * The given byte array will be parsed and converted to a Type1 sequence.
+     *
      * @param bytes the given mapping as byte array
-     * @param localSubrIndex index containing all local subroutines
-     * 
+     * @param subrs list of local subroutines
      * @return the Type1 sequence
      * @throws IOException if an error occurs during reading
      */
-    public List<Object> parse(byte[] bytes, IndexData localSubrIndex) throws IOException
+    public List<Object> parse(byte[] bytes, List<byte[]> subrs) throws IOException
     {
-        return parse(bytes, localSubrIndex, true);
+        return parse(bytes, subrs, new ArrayList<Object>());
     }
-    
-    private List<Object> parse(byte[] bytes, IndexData localSubrIndex, boolean init) throws IOException
+
+    private List<Object> parse(byte[] bytes, List<byte[]> subrs, List<Object> sequence) throws IOException
     {
-        if (init) 
-        {
-            sequence = new ArrayList<Object>();
-        }
-        input = new DataInput(bytes);
-        boolean localSubroutineIndexProvided = localSubrIndex != null && localSubrIndex.getCount() > 0;
+        DataInput input = new DataInput(bytes);
         while (input.hasRemaining())
         {
             int b0 = input.readUnsignedByte();
-
-            if (b0 == 10 && localSubroutineIndexProvided) 
-            { // process subr command
+            if (b0 == CALLSUBR)
+            {
+                // callsubr command
                 Integer operand=(Integer)sequence.remove(sequence.size()-1);
-                //get subrbias
-                int bias = 0;
-                int nSubrs = localSubrIndex.getCount();
-                
-                if (nSubrs < 1240)
+
+                if (operand < subrs.size())
                 {
-                    bias = 107;
+                    byte[] subrBytes = subrs.get(operand);
+                    parse(subrBytes, subrs, sequence);
+                    Object lastItem = sequence.get(sequence.size()-1);
+                    if (lastItem instanceof CharStringCommand &&
+                          ((CharStringCommand)lastItem).getKey().getValue()[0] == RETURN)
+                    {
+                        sequence.remove(sequence.size()-1); // remove "return" command
+                    }
                 }
-                else if (nSubrs < 33900) 
+            }
+            else if (b0 == TWO_BYTE && input.peekUnsignedByte(0) == CALLOTHERSUBR)
+            {
+                // callothersubr command (needed in order to expand Subrs)
+                input.readByte();
+
+                Integer othersubrNum = (Integer)sequence.remove(sequence.size()-1);
+                Integer numArgs = (Integer)sequence.remove(sequence.size()-1);
+
+                // othersubrs 0-3 have their own semantics
+                Stack<Integer> results = new Stack<Integer>();
+                if (othersubrNum == 0) {
+                    results.push((Integer)sequence.remove(sequence.size()-1));
+                    results.push((Integer)sequence.remove(sequence.size()-1));
+                    sequence.remove(sequence.size()-1);
+                    // end flex
+                    sequence.add(0);
+                    sequence.add(new CharStringCommand(TWO_BYTE, CALLOTHERSUBR));
+                }
+                else if (othersubrNum == 1)
                 {
-                    bias = 1131;
+                    // begin flex
+                    sequence.add(1);
+                    sequence.add(new CharStringCommand(TWO_BYTE, CALLOTHERSUBR));
                 }
-                else 
+                else if (othersubrNum == 3)
                 {
-                    bias = 32768;
+                    // allows hint replacement
+                    results.push((Integer)sequence.remove(sequence.size()-1));
                 }
-                int subrNumber = bias+operand;
-                if (subrNumber < localSubrIndex.getCount())
+                else
                 {
-                    byte[] subrBytes = localSubrIndex.getBytes(subrNumber);
-                    parse(subrBytes, localSubrIndex, false);
-                    Object lastItem = sequence.get(sequence.size()-1);
-                    if (lastItem instanceof CharStringCommand && ((CharStringCommand)lastItem).getKey().getValue()[0] == 11)
-                    {
-                        sequence.remove(sequence.size()-1); // remove "return" command
+                    // all remaining othersubrs use this fallback mechanism
+                    for (int i = 0; i < numArgs; i++) {
+                        Integer arg = (Integer)sequence.remove(sequence.size()-1);
+                        results.push(arg);
                     }
                 }
-                
-            } 
+
+                // pop must follow immediately
+                while (input.peekUnsignedByte(0) == TWO_BYTE && input.peekUnsignedByte(1) == POP)
+                {
+                    input.readByte(); // B0_POP
+                    input.readByte(); // B1_POP
+                    Integer val = results.pop();
+                    sequence.add(val);
+                }
+
+                if (results.size() > 0)
+                {
+                    LOG.warn("Value left on the PostScript stack in glyph " + glyphName + " of font " + fontName);
+                }
+            }
             else if (b0 >= 0 && b0 <= 31)
             {
-                sequence.add(readCommand(b0));
+                sequence.add(readCommand(input, b0));
             } 
             else if (b0 >= 32 && b0 <= 255)
             {
-                sequence.add(readNumber(b0));
+                sequence.add(readNumber(input, b0));
             } 
             else
             {
@@ -104,7 +163,7 @@ public class Type1CharStringParser
         return sequence;
     }
 
-    private CharStringCommand readCommand(int b0) throws IOException
+    private CharStringCommand readCommand(DataInput input, int b0) throws IOException
     {
         if (b0 == 12)
         {
@@ -114,21 +173,21 @@ public class Type1CharStringParser
         return new CharStringCommand(b0);
     }
 
-    private Integer readNumber(int b0) throws IOException
+    private Integer readNumber(DataInput input, int b0) throws IOException
     {
         if (b0 >= 32 && b0 <= 246)
         {
-            return Integer.valueOf(b0 - 139);
+            return b0 - 139;
         } 
         else if (b0 >= 247 && b0 <= 250)
         {
             int b1 = input.readUnsignedByte();
-            return Integer.valueOf((b0 - 247) * 256 + b1 + 108);
+            return (b0 - 247) * 256 + b1 + 108;
         } 
         else if (b0 >= 251 && b0 <= 254)
         {
             int b1 = input.readUnsignedByte();
-            return Integer.valueOf(-(b0 - 251) * 256 - b1 - 108);
+            return -(b0 - 251) * 256 - b1 - 108;
         } 
         else if (b0 == 255)
         {
@@ -137,7 +196,7 @@ public class Type1CharStringParser
             int b3 = input.readUnsignedByte();
             int b4 = input.readUnsignedByte();
 
-            return Integer.valueOf(b1 << 24 | b2 << 16 | b3 << 8 | b4);
+            return b1 << 24 | b2 << 16 | b3 << 8 | b4;
         } 
         else
         {

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=1559225&r1=1559224&r2=1559225&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 Fri Jan 17 19:09:26 2014
@@ -16,6 +16,8 @@
  */
 package org.apache.fontbox.cff;
 
+import org.apache.fontbox.type1.Type1CharStringReader;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -36,14 +38,17 @@ public class Type2CharString extends Typ
 
     /**
      * Constructor.
-     * @param font Parent CFF font
+     * @param reader Parent CFF font
+     * @param fontName font name
+     * @param glyphName glyph name
      * @param sequence Type 2 char string sequence
      * @param defaultWidthX default width
-     * @param nomWidthX nominal width width
+     * @param nomWidthX nominal width
      */
-    public Type2CharString(CFFFont font, List<Object> sequence, int defaultWidthX, int nomWidthX)
+    public Type2CharString(Type1CharStringReader reader, String fontName, String glyphName, List<Object> sequence,
+                           int defaultWidthX, int nomWidthX)
     {
-        super(font);
+        super(reader, fontName, glyphName);
         type2sequence = sequence;
         defWidthX = defaultWidthX;
         nominalWidthX = nomWidthX;
@@ -63,7 +68,7 @@ public class Type2CharString extends Typ
         }
         else
         {
-            return nominalWidthX + width;
+            return width;
         }
     }
 
@@ -85,16 +90,16 @@ public class Type2CharString extends Typ
         type1Sequence = new ArrayList<Object>();
         pathCount = 0;
         CharStringHandler handler = new CharStringHandler() {
-            public void handleCommand(List<Integer> numbers, CharStringCommand command)
+            public List<Integer> handleCommand(List<Integer> numbers, CharStringCommand command)
             {
-                Type2CharString.this.handleCommand(numbers, command);
+                return Type2CharString.this.handleCommand(numbers, command);
             }
         };
         handler.handleSequence(sequence);
     }
 
     @SuppressWarnings(value = { "unchecked" })
-    private void handleCommand(List<Integer> numbers, CharStringCommand command)
+    private List<Integer> handleCommand(List<Integer> numbers, CharStringCommand command)
     {
         String name = CharStringCommand.TYPE2_VOCABULARY.get(command.getKey());
 
@@ -247,6 +252,7 @@ public class Type2CharString extends Typ
         {
             addCommand(numbers, command);
         }
+        return null;
     }
 
     private List<Integer> clearStack(List<Integer> numbers, boolean flag)

Added: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/encoding/CustomEncoding.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/encoding/CustomEncoding.java?rev=1559225&view=auto
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/encoding/CustomEncoding.java (added)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/encoding/CustomEncoding.java Fri Jan 17 19:09:26 2014
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.fontbox.encoding;
+
+import java.util.Map;
+
+/**
+ * A font-specific encoding.
+ *
+ * @author John Hewson
+ */
+public class CustomEncoding extends Encoding
+{
+    /**
+     * Constructor.
+     * 
+     * @param codeToName the given code to name mapping
+     */
+    public CustomEncoding(Map<Integer, String> codeToName)
+    {
+        for (Map.Entry<Integer, String> entry : codeToName.entrySet())
+        {
+            addCharacterEncoding(entry.getKey(), entry.getValue());
+        }
+    }
+}
\ No newline at end of file

Propchange: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/encoding/CustomEncoding.java
------------------------------------------------------------------------------
    svn:eol-style = native

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=1559225&r1=1559224&r2=1559225&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 Fri Jan 17 19:09:26 2014
@@ -131,18 +131,11 @@ public abstract class Encoding
      *
      * @param name The name of the character.
      *
-     * @return The code for the character.
-     *
-     * @throws IOException If there is no character code for the name.
+     * @return The code for the character or null if it is not in the encoding.
      */
-    public int getCode( String name ) throws IOException
+    public Integer getCode( String name )
     {
-        Integer code = nameToCode.get( name );
-        if( code == null )
-        {
-            throw new IOException( "No character code for character name '" + name + "'" );
-        }
-        return code.intValue();
+        return nameToCode.get( name );
     }
 
     /**

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/pfb/PfbParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/pfb/PfbParser.java?rev=1559225&r1=1559224&r2=1559225&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/pfb/PfbParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/pfb/PfbParser.java Fri Jan 17 19:09:26 2014
@@ -23,6 +23,7 @@ import java.io.EOFException;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Arrays;
 
 /**
  * Parser for a pfb-file.
@@ -194,4 +195,22 @@ public class PfbParser 
     {
         return pfbdata.length;
     }
+
+    /**
+     * Returns the first segment
+     * @return first segment bytes
+     */
+    public byte[] getSegment1()
+    {
+        return Arrays.copyOfRange(pfbdata, 0, lengths[0]);
+    }
+
+    /**
+     * Returns the second segment
+     * @return second segment bytes
+     */
+    public byte[] getSegment2()
+    {
+        return Arrays.copyOfRange(pfbdata, lengths[0], lengths[0] + lengths[1]);
+    }
 }

Added: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Token.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Token.java?rev=1559225&view=auto
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Token.java (added)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Token.java Fri Jan 17 19:09:26 2014
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.fontbox.type1;
+
+/**
+ * A lexical token in an Adobe Type 1 font.
+ *
+ * @see Type1Lexer
+ *
+ * @author John Hewson
+ */
+class Token
+{
+    /**
+     * All different types of tokens.  
+     *
+     */
+    static enum Kind
+    {
+        NONE, STRING, NAME, LITERAL, REAL, INTEGER,
+        START_ARRAY,  END_ARRAY, START_PROC,
+        END_PROC, CHARSTRING
+    }
+
+    // exposed statically for convenience
+    static final Kind STRING = Kind.STRING;
+    static final Kind NAME = Kind.NAME;
+    static final Kind LITERAL = Kind.LITERAL;
+    static final Kind REAL = Kind.REAL;
+    static final Kind INTEGER = Kind.INTEGER;
+    static final Kind START_ARRAY = Kind.START_ARRAY;
+    static final Kind END_ARRAY = Kind.END_ARRAY;
+    static final Kind START_PROC = Kind.START_PROC;
+    static final Kind END_PROC = Kind.END_PROC;
+    static final Kind CHARSTRING = Kind.CHARSTRING;
+
+    private String text;
+    private byte[] data;
+    private Kind kind;
+
+    /**
+     * Constructs a new Token object given its text and kind.
+     * @param text
+     * @param type
+     */
+    public Token(String text, Kind type)
+    {
+        this.text = text;
+        this.kind = type;
+    }
+
+    /**
+     * Constructs a new Token object given its single-character text and kind.
+     * @param character
+     * @param type
+     */
+    public Token(char character, Kind type)
+    {
+        this.text = Character.toString(character);
+        this.kind = type;
+    }
+
+    /**
+     * Constructs a new Token object given its raw data and kind.
+     * This is for CHARSTRING tokens only.
+     * @param data
+     * @param type
+     */
+    public Token(byte[] data, Kind type)
+    {
+        this.data = data;
+        this.kind = type;
+    }
+
+    public String getText()
+    {
+        return text;
+    }
+
+    public Kind getKind()
+    {
+        return kind;
+    }
+
+    public int intValue()
+    {
+        return Integer.parseInt(text);
+    }
+
+    public float floatValue()
+    {
+        return Float.parseFloat(text);
+    }
+
+    public boolean booleanValue()
+    {
+        return text.equals("true");
+    }
+
+    public byte[] getData()
+    {
+        return data;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        if (kind == CHARSTRING)
+        {
+            return "Token[kind=CHARSTRING, data=" + data.length + " bytes]";
+        }
+        else
+        {
+            return "Token[kind=" + kind + ", text=" + text + "]";
+        }
+    }
+}
\ No newline at end of file

Propchange: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Token.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1CharStringReader.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1CharStringReader.java?rev=1559225&view=auto
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1CharStringReader.java (added)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1CharStringReader.java Fri Jan 17 19:09:26 2014
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.fontbox.type1;
+
+import org.apache.fontbox.cff.Type1CharString;
+import java.io.IOException;
+
+/**
+ * Something which can read Type 1 CharStrings, namely Type 1 and CFF fonts.
+ *
+ * @author John Hewson
+ */
+public interface Type1CharStringReader
+{
+    /**
+     * Returns the Type 1 CharString for the character with the given name.
+     *
+     * @return Type 1 CharString
+     * @throws IOException if something went wrong
+     */
+    public Type1CharString getType1CharString(String name) throws IOException;
+}

Propchange: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1CharStringReader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 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=1559225&view=auto
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java (added)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java Fri Jan 17 19:09:26 2014
@@ -0,0 +1,577 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.fontbox.type1;
+
+import org.apache.fontbox.cff.Type1CharString;
+import org.apache.fontbox.cff.Type1CharStringParser;
+import org.apache.fontbox.encoding.Encoding;
+import org.apache.fontbox.pfb.PfbParser;
+
+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;
+
+/**
+ * Represents an Adobe Type 1 (.pfb) font.
+ *
+ * @author John Hewson
+ */
+public final class Type1Font implements Type1CharStringReader
+{
+    /**
+     * Constructs a new Type1Font object from a .pfb stream.
+     *
+     * @param pfbStream .pfb input stream, including headers
+     * @return a type1 font
+     * 
+     * @throws IOException if something went wrong
+     */
+    public static Type1Font createWithPFB(InputStream pfbStream) throws IOException
+    {
+        PfbParser pfb = new PfbParser(pfbStream);
+        Type1Parser parser = new Type1Parser();
+        return parser.parse(pfb.getSegment1(), pfb.getSegment2());
+    }
+
+    /**
+     * Constructs a new Type1Font object from two header-less .pfb segments.
+     *
+     * @param segment1 The first segment, without header
+     * @param segment2 The second segment, without header
+     * @return A new Type1Font instance
+     * @throws IOException if something went wrong
+     */
+    public static Type1Font createWithSegments(byte[] segment1, byte[] segment2) throws IOException
+    {
+        Type1Parser parser = new Type1Parser();
+        return parser.parse(segment1, segment2);
+    }
+
+    // font dictionary
+    String fontName = "";
+    Encoding encoding = null;
+    int paintType;
+    int fontType;
+    List<Number> fontMatrix = new ArrayList<Number>();
+    List<Number> fontBBox = new ArrayList<Number>();
+    int uniqueID;
+    float strokeWidth;
+    String fontID = "";
+
+    // FontInfo dictionary
+    String version = "";
+    String notice = "";
+    String fullName = "";
+    String familyName = "";
+    String weight = "";
+    float italicAngle;
+    boolean isFixedPitch;
+    float underlinePosition;
+    float underlineThickness;
+
+    // Private dictionary
+    List<Number> blueValues = new ArrayList<Number>();
+    List<Number> otherBlues = new ArrayList<Number>();
+    List<Number> familyBlues = new ArrayList<Number>();
+    List<Number> familyOtherBlues = new ArrayList<Number>();
+    float blueScale;
+    int blueShift, blueFuzz;
+    List<Number> stdHW = new ArrayList<Number>();
+    List<Number> stdVW = new ArrayList<Number>();
+    List<Number> stemSnapH = new ArrayList<Number>();
+    List<Number> stemSnapV = new ArrayList<Number>();
+    boolean forceBold;
+    int languageGroup;
+
+    // Subrs array, and CharStrings dictionary
+    final List<byte[]> subrs = new ArrayList<byte[]>();
+    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;
+
+    /**
+     * Constructs a new Type1Font, called by Type1Parser.
+     */
+    Type1Font()
+    {
+    }
+
+    /**
+     * Returns the /Subrs array as raw bytes.
+     *
+     * @return Type 1 char string bytes
+     */
+    public List<byte[]> getSubrsArray()
+    {
+        return Collections.unmodifiableList(subrs);
+    }
+
+    /**
+     * Returns the /CharStrings dictionary as raw bytes.
+     *
+     * @return Type 1 char string bytes
+     */
+    public Map<String, byte[]> getCharStringsDict()
+    {
+        return Collections.unmodifiableMap(charstrings);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Type1CharString getType1CharString(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;
+    }
+
+    /**
+     * Get the mappings for the font as Type1Mapping.
+     *
+     * @return the Type1Mapping
+     */
+    public Collection<? extends Type1Mapping> getType1Mappings()
+    {
+        return getMappings();
+    }
+
+    /**
+     * Get the mapping (code/charname/bytes) for this font.
+     *
+     * @return mappings for character codes
+     */
+    public Collection<Type1Font.Mapping> getMappings()
+    {
+        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;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public class Mapping implements Type1Mapping
+    {
+        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)
+        {
+            this.mappedBytes = bytes;
+        }
+    }
+
+    // font dictionary
+
+    /**
+     * Returns the font name.
+     * 
+     * @return the font name
+     */
+    public String getFontName()
+    {
+        return fontName;
+    }
+
+    /**
+     * Returns the Encoding, if present.
+     * @return the encoding or null
+     */
+    public Encoding getEncoding()
+    {
+        return encoding;
+    }
+
+    /**
+     * Returns the paint type.
+     * 
+     * @return the paint type
+     */
+    public int getPaintType()
+    {
+        return paintType;
+    }
+
+    /**
+     * Returns the font type.
+     * 
+     * @return the font type
+     */
+    public int getFontType()
+    {
+        return fontType;
+    }
+
+    /**
+     * Returns the font matrix.
+     * 
+     * @return the font matrix
+     */
+    public List<Number> getFontMatrix()
+    {
+        return Collections.unmodifiableList(fontMatrix);
+    }
+
+    /**
+     * Returns the font bounding box.
+     * 
+     * @return the font bounding box
+     */
+    public List<Number> getFontBBox()
+    {
+        return Collections.unmodifiableList(fontBBox);
+    }
+
+    /**
+     * Returns unique ID.
+     * 
+     * @return the unique ID
+     */
+    public int getUniqueID()
+    {
+        return uniqueID;
+    }
+
+    /**
+     * Returns the stroke width.
+     * 
+     * @return the stroke width
+     */
+    public float getStrokeWidth()
+    {
+        return strokeWidth;
+    }
+
+    /**
+     * Returns the font ID.
+     * 
+     * @return the font ID
+     */
+    public String getFontID()
+    {
+        return fontID;
+    }
+
+    // FontInfo dictionary
+
+    /**
+     * Returns the version.
+     * 
+     * @return the version
+     */
+    public String getVersion()
+    {
+        return version;
+    }
+
+    /**
+     * Returns the notice.
+     * 
+     * @return the notice
+     */
+    public String getNotice()
+    {
+        return notice;
+    }
+
+    /**
+     * Returns the full name.
+     * 
+     * @return the full name
+     */
+    public String getFullName()
+    {
+        return fullName;
+    }
+
+    /**
+     * Returns the family name.
+     * 
+     * @return the family name
+     */
+    public String getFamilyName()
+    {
+        return familyName;
+    }
+
+    /**
+     * Returns the weight.
+     * 
+     * @return the weight
+     */
+    public String getWeight()
+    {
+        return weight;
+    }
+
+    /**
+     * Returns the italic angle.
+     * 
+     * @return the italic angle
+     */
+    public float getItalicAngle()
+    {
+        return italicAngle;
+    }
+
+    /**
+     * Determines if the font has a fixed pitch.
+     * 
+     * @return true if the font has a fixed pitch
+     */
+    public boolean isFixedPitch()
+    {
+        return isFixedPitch;
+    }
+
+    /**
+     * Returns the underline position
+     * 
+     * @return the underline position
+     */
+    public float getUnderlinePosition()
+    {
+        return underlinePosition;
+    }
+
+    /**
+     * Returns the underline thickness.
+     * 
+     * @return the underline thickness
+     */
+    public float getUnderlineThickness()
+    {
+        return underlineThickness;
+    }
+
+    // Private dictionary
+
+    /**
+     * Returns the blues values.
+     * 
+     * @return the blues values
+     */
+    public List<Number> getBlueValues()
+    {
+        return Collections.unmodifiableList(blueValues);
+    }
+
+    /**
+     * Returns the other blues values.
+     * 
+     * @return the other blues values
+     */
+    public List<Number> getOtherBlues()
+    {
+        return Collections.unmodifiableList(otherBlues);
+    }
+
+    /**
+     * Returns the family blues values.
+     * 
+     * @return the family blues values
+     */
+    public List<Number> getFamilyBlues()
+    {
+        return Collections.unmodifiableList(familyBlues);
+    }
+
+    /**
+     * Returns the other family blues values.
+     * 
+     * @return the other family blues values
+     */
+    public List<Number> getFamilyOtherBlues()
+    {
+        return Collections.unmodifiableList(familyOtherBlues);
+    }
+
+    /**
+     * Returns the blue scale.
+     * 
+     * @return the blue scale
+     */
+    public float getBlueScale()
+    {
+        return blueScale;
+    }
+
+    /**
+     * Returns the blue shift.
+     * 
+     * @return the blue shift
+     */
+    public int getBlueShift()
+    {
+        return blueShift;
+    }
+
+    /**
+     * Returns the blue fuzz.
+     * 
+     * @return the blue fuzz
+     */
+    public int getBlueFuzz()
+    {
+        return blueFuzz;
+    }
+
+    /**
+     * Returns the StdHW value.
+     * 
+     * @return the StdHW value
+     */
+    public List<Number> getStdHW()
+    {
+        return Collections.unmodifiableList(stdHW);
+    }
+
+    /**
+     * Returns the StdVW value.
+     * 
+     * @return the StdVW value
+     */
+    public List<Number> getStdVW()
+    {
+        return Collections.unmodifiableList(stdVW);
+    }
+
+    /**
+     * Returns the StemSnapH value.
+     * 
+     * @return the StemSnapH value
+     */
+    public List<Number> getStemSnapH()
+    {
+        return Collections.unmodifiableList(stemSnapH);
+    }
+
+    /**
+     * Returns the StemSnapV value.
+     * 
+     * @return the StemSnapV value
+     */
+    public List<Number> getStemSnapV()
+    {
+        return Collections.unmodifiableList(stemSnapV);
+    }
+
+    /**
+     * Determines if the font is bold.
+     * 
+     * @return true if the font is bold
+     */
+    public boolean isForceBold()
+    {
+        return forceBold;
+    }
+
+    /**
+     * Returns the language group.
+     * 
+     * @return the language group
+     */
+    public int getLanguageGroup()
+    {
+        return languageGroup;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return getClass().getName() + "[fontName=" + fontName + ", fullName=" + fullName
+                + ", encoding=" + encoding + ", charStringsDict=" + charstrings
+                + "]";
+    }
+}

Propchange: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Lexer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Lexer.java?rev=1559225&view=auto
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Lexer.java (added)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Lexer.java Fri Jan 17 19:09:26 2014
@@ -0,0 +1,403 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.fontbox.type1;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+
+/**
+ * Lexer for the ASCII portions of an Adobe Type 1 font.
+ *
+ * @see Type1Parser
+ *
+ * The PostScript language, of which Type 1 fonts are a subset, has a
+ * somewhat awkward lexical structure. It is neither regular nor
+ * context-free, and the execution of the program can modify the
+ * the behaviour of the lexer/parser.
+ *
+ * Nevertheless, this class represents an attempt to artificially seperate
+ * the PostScript parsing process into separate lexing and parsing phases
+ * in order to reduce the complexity of the parsing phase.
+ *
+ * @see "PostScript Language Reference 3rd ed, Adobe Systems (1999)"
+ *
+ * @author John Hewson
+ */
+class Type1Lexer
+{
+    private ByteBuffer buffer;
+    private Token aheadToken;
+    private int openParens = 0;
+
+    /**
+     * Constructs a new Type1Lexer given a header-less .pfb segment.
+     * @param bytes Header-less .pfb segment
+     * @throws IOException
+     */
+    public Type1Lexer(byte[] bytes) throws IOException
+    {
+        this.buffer = ByteBuffer.wrap(bytes);
+        aheadToken = readToken(null);
+    }
+
+    /**
+     * Returns the next token and consumes it.
+     * @return The next token.
+     */
+    public Token nextToken() throws IOException
+    {
+        Token curToken = aheadToken;
+        //System.out.println(curToken); // for debugging
+        aheadToken = readToken(curToken);
+        return curToken;
+    }
+
+    /**
+     * Returns the next token without consuming it.
+     * @return The next token
+     */
+    public Token peekToken()
+    {
+        return aheadToken;
+    }
+
+    /**
+     * Reads an ASCII char from the buffer.
+     */
+    private char getChar()
+    {
+        return (char) buffer.get();
+    }
+
+    /**
+     * Reads a single token.
+     * @param prevToken the previous token
+     */
+    private Token readToken(Token prevToken) throws IOException
+    {
+        boolean skip;
+        do
+        {
+            skip = false;
+            while (buffer.hasRemaining())
+            {
+                char c = getChar();
+
+                // delimiters
+                if (c == '%')
+                {
+                    // comment
+                    readComment();
+                }
+                else if (c == '(')
+                {
+                    return readString();
+                }
+                else if (c == ')')
+                {
+                    // not allowed outside a string context
+                    throw new IOException("unexpected closing parenthesis");
+                }
+                else if (c == '[')
+                {
+                    return new Token(c, Token.START_ARRAY);
+                }
+                else if (c == '{')
+                {
+                    return new Token(c, Token.START_PROC);
+                }
+                else if (c == ']')
+                {
+                    return new Token(c, Token.END_ARRAY);
+                }
+                else if (c == '}')
+                {
+                    return new Token(c, Token.END_PROC);
+                }
+                else if (c == '/')
+                {
+                    return new Token(readRegular(), Token.LITERAL);
+                }
+                else if (Character.isWhitespace(c))
+                {
+                    skip = true;
+                }
+                else
+                {
+                    buffer.position(buffer.position() -1);
+
+                    // regular character: try parse as number
+                    Token number = tryReadNumber();
+                    if (number != null)
+                    {
+                        return number;
+                    }
+                    else
+                    {
+                        // otherwise this must be a name
+                        String name = readRegular();
+
+                        if (name.equals("RD") || name.equals("-|"))
+                        {
+                            // return the next CharString instead
+                            if (prevToken.getKind() == Token.INTEGER)
+                            {
+                                return readCharString(prevToken.intValue());
+                            }
+                            else
+                            {
+                                throw new IOException("expected INTEGER before -| or RD");
+                            }
+                        }
+                        else
+                        {
+                            return new Token(name, Token.NAME);
+                        }
+                    }
+                }
+            }
+        } while (skip);
+        return null;
+    }
+
+    /**
+     * Reads a number or returns null.
+     */
+    private Token tryReadNumber()
+    {
+        buffer.mark();
+
+        StringBuilder sb = new StringBuilder();
+        char c = getChar();
+        boolean hasDigit = false;
+
+        // optional + or -
+        if (c == '+' || c == '-')
+        {
+            sb.append(c);
+            c = getChar();
+        }
+
+        // optional digits
+        while (Character.isDigit(c))
+        {
+            sb.append(c);
+            c = getChar();
+            hasDigit = true;
+        }
+
+        // optional .
+        if (c == '.')
+        {
+            sb.append(c);
+            c = getChar();
+        }
+        else if (sb.length() == 0 || !hasDigit)
+        {
+            // failure
+            buffer.reset();
+            return null;
+        }
+        else
+        {
+            // integer
+            buffer.position(buffer.position() -1);
+            return new Token(sb.toString(), Token.INTEGER);
+        }
+
+        // required digit
+        if (Character.isDigit(c))
+        {
+            sb.append(c);
+            c = getChar();
+        }
+        else
+        {
+            // failure
+            buffer.reset();
+            return null;
+        }
+
+        // optional digits
+        while (Character.isDigit(c))
+        {
+            sb.append(c);
+            c = getChar();
+        }
+
+        // optional E
+        if (c == 'E')
+        {
+            sb.append(c);
+            c = getChar();
+
+            // required digit
+            if (Character.isDigit(c))
+            {
+                sb.append(c);
+                c = getChar();
+            }
+            else
+            {
+                // failure
+                buffer.reset();
+                return null;
+            }
+
+            // optional digits
+            while (Character.isDigit(c))
+            {
+                sb.append(c);
+                c = getChar();
+            }
+        }
+
+        // real
+        buffer.position(buffer.position() -1);
+        return new Token(sb.toString(), Token.REAL);
+    }
+
+    /**
+     * Reads a sequence of regular characters, i.e. not delimiters
+     * or whitespace
+     */
+    private String readRegular()
+    {
+        StringBuilder sb = new StringBuilder();
+        while (buffer.hasRemaining())
+        {
+            buffer.mark();
+            char c = getChar();
+            if (Character.isWhitespace(c) ||
+                c == '(' || c == ')' ||
+                c == '<' || c == '>' ||
+                c == '[' || c == ']' ||
+                c == '{' || c == '}' ||
+                c == '/' || c == '%' )
+            {
+                buffer.reset();
+                break;
+            }
+            else
+            {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Reads a line comment.
+     */
+    private String readComment()
+    {
+        StringBuilder sb = new StringBuilder();
+        while (buffer.hasRemaining())
+        {
+            char c = getChar();
+            if (c == '\r' || c == '\n')
+            {
+                break;
+            }
+            else
+            {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Reads a (string).
+     */
+    private Token readString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        while (buffer.hasRemaining())
+        {
+            char c = getChar();
+
+            // string context
+            if (c == '(')
+            {
+                openParens++;
+                sb.append('(');
+            }
+            else if (c == ')')
+            {
+                if (openParens == 0)
+                {
+                    // end of string
+                    return new Token(sb.toString(), Token.STRING);
+                }
+                else
+                {
+                    sb.append(')');
+                    openParens--;
+                }
+            }
+            else if (c == '\\')
+            {
+                // escapes: \n \r \t \b \f \\ \( \)
+                char c1 = getChar();
+                switch (c1)
+                {
+                    case 'n':
+                    case 'r': sb.append("\n"); break;
+                    case 't': sb.append('\t'); break;
+                    case 'b': sb.append('\b'); break;
+                    case 'f': sb.append('\f'); break;
+                    case '\\': sb.append('\\'); break;
+                    case '(': sb.append('('); break;
+                    case ')': sb.append(')'); break;
+                }
+                // octal \ddd
+                if (Character.isDigit(c1))
+                {
+                    String num = String.valueOf(new char[] { c1, getChar(), getChar() });
+                    Integer code = Integer.parseInt(num, 8);
+                    sb.append((char)(int)code);
+                }
+            }
+            else if (c == '\r' || c == '\n')
+            {
+                sb.append("\n");
+            }
+            else
+            {
+                sb.append(c);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Reads a binary CharString.
+     */
+    private Token readCharString(int length)
+    {
+        buffer.get(); // space
+        byte[] data = new byte[length];
+        buffer.get(data);
+        return new Token(data, Token.CHARSTRING);
+    }
+}
\ No newline at end of file

Propchange: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Lexer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Mapping.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Mapping.java?rev=1559225&view=auto
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Mapping.java (added)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Mapping.java Fri Jan 17 19:09:26 2014
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.fontbox.type1;
+
+import org.apache.fontbox.cff.Type1CharString;
+
+import java.io.IOException;
+
+/**
+ * A high-level mapping from character codes to glyphs.
+ *
+ * @author John Hewson
+ */
+public interface Type1Mapping
+{
+    /**
+     * Returns the Type 1 CharString for the character.
+     *
+     * @return the Type 1 CharString
+     * @throws java.io.IOException if an error occurs during reading
+     */
+    public Type1CharString getType1CharString() throws IOException;
+
+    /**
+     * Gets the value for the code.
+     *
+     * @return the code
+     */
+    public int getCode();
+
+    /**
+     * Gets the value for the name.
+     *
+     * @return the name
+     */
+    public String getName();
+
+    /**
+     * Gets the value for the bytes.
+     *
+     * @return the bytes
+     */
+    public byte[] getBytes();
+}

Propchange: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Mapping.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message