Author: lehmi
Date: Wed Dec 26 15:36:45 2012
New Revision: 1425954

URL: http://svn.apache.org/viewvc?rev=1425954&view=rev
Log:
PDFBOX-1473: fixed the handling of "callsubr" and "callgsubr" commands based on 
a proposal by Juraj Lonc

Modified:
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java
    
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringConverter.java
    
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java
    
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java
    
pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cff/Type1CharStringTest.java
    
pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/util/Type1Parser.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=1425954&r1=1425953&r2=1425954&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 Wed 
Dec 26 15:36:45 2012
@@ -248,12 +248,12 @@ public class CFFFont
                byte[] glyphDesc = this.getCharStringsDict().get(".notdef");
                if (((Number)getProperty("CharstringType")).intValue() == 2 ) {
                        Type2CharStringParser parser = new 
Type2CharStringParser();
-                       List<Object> lSeq = parser.parse(glyphDesc);
+                       List<Object> lSeq = parser.parse(glyphDesc, 
getGlobalSubrIndex(), getLocalSubrIndex());
                        csr = new CharStringRenderer(false);
                        csr.render(lSeq);
                } else {
                        Type1CharStringParser parser = new 
Type1CharStringParser();
-                       List<Object> lSeq = parser.parse(glyphDesc);
+                       List<Object> lSeq = parser.parse(glyphDesc, 
getLocalSubrIndex());
                        csr = new CharStringRenderer();
                        csr.render(lSeq);
                }
@@ -313,8 +313,7 @@ public class CFFFont
        {
                Number defaultWidthX = (Number) getProperty("defaultWidthX");
                Number nominalWidthX = (Number) getProperty("nominalWidthX");
-               return new CharStringConverter(defaultWidthX.intValue(), 
nominalWidthX
-                               .intValue(), getGlobalSubrIndex(), 
getLocalSubrIndex());
+               return new CharStringConverter(defaultWidthX.intValue(), 
nominalWidthX.intValue());
        }
 
        /**
@@ -400,7 +399,7 @@ public class CFFFont
                public List<Object> toType2Sequence() throws IOException
                {
                        Type2CharStringParser parser = new 
Type2CharStringParser();
-                       return parser.parse(getBytes());
+                       return parser.parse(getBytes(), getGlobalSubrIndex(), 
getLocalSubrIndex());
                }
 
                /**

Modified: 
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringConverter.java
URL: 
http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringConverter.java?rev=1425954&r1=1425953&r2=1425954&view=diff
==============================================================================
--- 
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringConverter.java
 (original)
+++ 
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringConverter.java
 Wed Dec 26 15:36:45 2012
@@ -16,7 +16,6 @@
  */
 package org.apache.fontbox.cff;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -35,24 +34,34 @@ public class CharStringConverter extends
     private int nominalWidthX = 0;
     private List<Object> sequence = null;
     private int pathCount = 0;
-    private IndexData globalSubrIndex = null;
-    private IndexData localSubrIndex = null;
 
     /**
      * Constructor.
      * 
      * @param defaultWidth default width
      * @param nominalWidth nominal width
+     * 
+     * @deprecated Use {@link CharStringConverter#CharStringConverter(int, 
int)} instead
      */
     public CharStringConverter(int defaultWidth, int nominalWidth, IndexData 
fontGlobalSubrIndex, IndexData fontLocalSubrIndex)
     {
         defaultWidthX = defaultWidth;
         nominalWidthX = nominalWidth;
-        globalSubrIndex = fontGlobalSubrIndex;
-        localSubrIndex = fontLocalSubrIndex;
     }
 
     /**
+     * Constructor.
+     * 
+     * @param defaultWidth default width
+     * @param nominalWidth nominal width
+     * 
+     */
+    public CharStringConverter(int defaultWidth, int nominalWidth)
+    {
+        defaultWidthX = defaultWidth;
+        nominalWidthX = nominalWidth;
+    }
+    /**
      * Converts a sequence of Type1/Type2 commands into a sequence of 
CharStringCommands.
      * @param commandSequence the type1/type2 sequence
      * @return the CHarStringCommandSequence
@@ -145,44 +154,6 @@ public class CharStringConverter extends
         {
             drawAlternatingCurve(numbers, true);
         } 
-        else if ("callsubr".equals(name))
-        {
-            //get subrbias
-            int bias = 0;
-            int nSubrs = localSubrIndex.getCount();
-            
-            if (nSubrs < 1240)
-            {
-                bias = 107;
-            }
-            else if (nSubrs < 33900) 
-            {
-                bias = 1131;
-            }
-            else 
-            {
-                bias = 32768;
-            }
-           
-            List<Integer> result = null;
-            int subrNumber = bias+numbers.get(numbers.size()-1);
-            if (subrNumber < localSubrIndex.getCount())
-            {
-                Type2CharStringParser parser = new Type2CharStringParser();
-                byte[] bytes = localSubrIndex.getBytes(subrNumber);
-                List<Object> parsed = null;
-                try {
-                    parsed = parser.parse(bytes);
-                    parsed.addAll(0,numbers.subList(0, numbers.size()-1));
-                    result = handleSequence(parsed);
-                } 
-                catch (IOException e) 
-                {
-                    e.printStackTrace();
-                }
-            }
-            return result;
-        }
         else if ("return".equals(name))
         {
             return numbers;
@@ -276,42 +247,6 @@ public class CharStringConverter extends
         {
             drawCurve(numbers, true);
         } 
-        else if ("callgsubr".equals(name))
-        {
-            //get subrbias
-            int bias = 0;
-            int nSubrs = globalSubrIndex.getCount();
-            
-            if (nSubrs < 1240)
-            {
-                bias = 107;
-            }
-            else if (nSubrs < 33900)
-            {
-                bias = 1131;
-            }
-            else 
-            {
-                bias = 32768;
-            }
-            List<Integer> result = null;
-            int subrNumber = bias+numbers.get(numbers.size()-1);
-            if (subrNumber < nSubrs)
-            {
-                Type2CharStringParser parser = new Type2CharStringParser();
-                byte[] bytes = globalSubrIndex.getBytes(subrNumber);
-                List<Object> parsed = null;
-                try {
-                    parsed = parser.parse(bytes);
-                    parsed.addAll(0,numbers.subList(0, numbers.size()-1));
-                    result = handleSequence(parsed);
-                } catch (IOException e) 
-                {
-                    e.printStackTrace();
-                }
-            }
-            return result;
-        }
         else
         {
             addCommand(numbers, command);

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=1425954&r1=1425953&r2=1425954&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
 Wed Dec 26 15:36:45 2012
@@ -34,18 +34,61 @@ public class Type1CharStringParser
     /**
      * 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
+     * 
      * @return the Type1 sequence
      * @throws IOException if an error occurs during reading
      */
-    public List<Object> parse(byte[] bytes) throws IOException
+    public List<Object> parse(byte[] bytes, IndexData localSubrIndex) throws 
IOException
     {
+        return parse(bytes, localSubrIndex, true);
+    }
+    
+    private List<Object> parse(byte[] bytes, IndexData localSubrIndex, boolean 
init) throws IOException
+    {
+        if (init) 
+        {
+            sequence = new ArrayList<Object>();
+        }
         input = new DataInput(bytes);
-        sequence = new ArrayList<Object>();
+        boolean localSubroutineIndexProvided = localSubrIndex != null && 
localSubrIndex.getCount() > 0;
         while (input.hasRemaining())
         {
             int b0 = input.readUnsignedByte();
 
-            if (b0 >= 0 && b0 <= 31)
+            if (b0 == 10 && localSubroutineIndexProvided) 
+            { // process subr command
+                Integer operand=(Integer)sequence.remove(sequence.size()-1);
+                //get subrbias
+                int bias = 0;
+                int nSubrs = localSubrIndex.getCount();
+                
+                if (nSubrs < 1240)
+                {
+                    bias = 107;
+                }
+                else if (nSubrs < 33900) 
+                {
+                    bias = 1131;
+                }
+                else 
+                {
+                    bias = 32768;
+                }
+                int subrNumber = bias+operand;
+                if (subrNumber < localSubrIndex.getCount())
+                {
+                    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
+                    }
+                }
+                
+            } 
+            else if (b0 >= 0 && b0 <= 31)
             {
                 sequence.add(readCommand(b0));
             } 

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=1425954&r1=1425953&r2=1425954&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
 Wed Dec 26 15:36:45 2012
@@ -28,7 +28,6 @@ import java.util.List;
 public class Type2CharStringParser
 {
 
-    private DataInput input = null;
     private int hstemCount = 0;
     private int vstemCount = 0;
     private List<Object> sequence = null;
@@ -36,48 +35,122 @@ public class Type2CharStringParser
     /**
      * 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
+     * @param localSubrIndex index containing all local subroutines
+     * 
      * @return the Type2 sequence
      * @throws IOException if an error occurs during reading
      */
-    public List<Object> parse(byte[] bytes) throws IOException
+    public List<Object> parse(byte[] bytes, IndexData globalSubrIndex, 
IndexData localSubrIndex) throws IOException
     {
-        input = new DataInput(bytes);
-
-        hstemCount = 0;
-        vstemCount = 0;
-
-        sequence = new ArrayList<Object>();
+       return parse(bytes, globalSubrIndex, localSubrIndex, true);
+    }
+    
+    private List<Object> parse(byte[] bytes, IndexData globalSubrIndex, 
IndexData localSubrIndex, boolean init) throws IOException
+    {
+        if (init) 
+        {
+               hstemCount = 0;
+               vstemCount = 0;
+               sequence = new ArrayList<Object>();
+        }
+        DataInput input = new DataInput(bytes);
+        boolean localSubroutineIndexProvided = localSubrIndex != null && 
localSubrIndex.getCount() > 0;
+        boolean globalSubroutineIndexProvided = globalSubrIndex != null && 
globalSubrIndex.getCount() > 0;
 
         while (input.hasRemaining())
         {
             int b0 = input.readUnsignedByte();
-
-            if (b0 >= 0 && b0 <= 27)
+            if (b0 == 10 && localSubroutineIndexProvided) 
+            { // process subr command
+               Integer operand=(Integer)sequence.remove(sequence.size()-1);
+               //get subrbias
+                int bias = 0;
+                int nSubrs = localSubrIndex.getCount();
+                
+                if (nSubrs < 1240)
+                {
+                    bias = 107;
+                }
+                else if (nSubrs < 33900) 
+                {
+                    bias = 1131;
+                }
+                else 
+                {
+                    bias = 32768;
+                }
+                int subrNumber = bias+operand;
+                if (subrNumber < localSubrIndex.getCount())
+                {
+                    byte[] subrBytes = localSubrIndex.getBytes(subrNumber);
+                    parse(subrBytes, globalSubrIndex, 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
+                    }
+                }
+               
+            } 
+            else if (b0 == 29 && globalSubroutineIndexProvided) 
+            { // process globalsubr command
+                Integer operand=(Integer)sequence.remove(sequence.size()-1);
+                //get subrbias
+                int bias = 0;
+                int nSubrs = globalSubrIndex.getCount();
+                
+                if (nSubrs < 1240)
+                {
+                    bias = 107;
+                }
+                else if (nSubrs < 33900) 
+                {
+                    bias = 1131;
+                }
+                else 
+                {
+                    bias = 32768;
+                }
+                
+                int subrNumber = bias+operand;
+                if (subrNumber < globalSubrIndex.getCount())
+                {
+                    byte[] subrBytes = globalSubrIndex.getBytes(subrNumber);
+                    parse(subrBytes, globalSubrIndex, 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
+                    }
+                }
+                       
+            } 
+            else if (b0 >= 0 && b0 <= 27)
             {
-                sequence.add(readCommand(b0));
+                sequence.add(readCommand(b0, input));
             } 
             else if (b0 == 28)
             {
-                sequence.add(readNumber(b0));
+                sequence.add(readNumber(b0, input));
             } 
             else if (b0 >= 29 && b0 <= 31)
             {
-                sequence.add(readCommand(b0));
+                sequence.add(readCommand(b0, input));
             } 
             else if (b0 >= 32 && b0 <= 255)
             {
-                sequence.add(readNumber(b0));
+                sequence.add(readNumber(b0, input));
             }
             else
             {
                 throw new IllegalArgumentException();
             }
         }
-
         return sequence;
     }
 
-    private CharStringCommand readCommand(int b0) throws IOException
+    private CharStringCommand readCommand(int b0, DataInput input) throws 
IOException
     {
 
         if (b0 == 1 || b0 == 18)
@@ -111,7 +184,7 @@ public class Type2CharStringParser
         return new CharStringCommand(b0);
     }
 
-    private Integer readNumber(int b0) throws IOException
+    private Integer readNumber(int b0, DataInput input) throws IOException
     {
 
         if (b0 == 28)
@@ -141,11 +214,10 @@ public class Type2CharStringParser
         {
             int b1 = input.readUnsignedByte();
             int b2 = input.readUnsignedByte();
-            int b3 = input.readUnsignedByte();
-            int b4 = input.readUnsignedByte();
-
             // The lower bytes are representing the digits after 
             // the decimal point and aren't needed in this context
+            input.readUnsignedByte();
+            input.readUnsignedByte();
             return Integer.valueOf((short)(b1 << 8 | b2));
         } 
         else

Modified: 
pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cff/Type1CharStringTest.java
URL: 
http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cff/Type1CharStringTest.java?rev=1425954&r1=1425953&r2=1425954&view=diff
==============================================================================
--- 
pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cff/Type1CharStringTest.java
 (original)
+++ 
pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cff/Type1CharStringTest.java
 Wed Dec 26 15:36:45 2012
@@ -42,7 +42,8 @@ public class Type1CharStringTest
                 new int[] { 12, 0 }, new int[] { 31 });
 
         byte[] encodedCommands = new 
Type1CharStringFormatter().format(commands);
-        List<Object> decodedCommands = new 
Type1CharStringParser().parse(encodedCommands);
+        List<Object> decodedCommands = new Type1CharStringParser()
+                .parse(encodedCommands, new IndexData(0));
 
         assertEquals(1 + 2 + 1, encodedCommands.length);
 
@@ -61,7 +62,7 @@ public class Type1CharStringTest
 
         byte[] encodedNumbers = new Type1CharStringFormatter().format(numbers);
         List<Object> decodedNumbers = new Type1CharStringParser()
-                .parse(encodedNumbers);
+                .parse(encodedNumbers, new IndexData(0));
 
         assertEquals(5 + 2 * 2 + 3 * 1 + 2 * 2 + 5, encodedNumbers.length);
 

Modified: 
pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/util/Type1Parser.java
URL: 
http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/util/Type1Parser.java?rev=1425954&r1=1425953&r2=1425954&view=diff
==============================================================================
--- 
pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/util/Type1Parser.java
 (original)
+++ 
pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/util/Type1Parser.java
 Wed Dec 26 15:36:45 2012
@@ -34,6 +34,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.commons.io.IOUtils;
+import org.apache.fontbox.cff.IndexData;
 import org.apache.fontbox.cff.Type1CharStringParser;
 import org.apache.fontbox.cff.Type1FontUtil;
 import org.apache.pdfbox.encoding.Encoding;
@@ -281,7 +282,8 @@ public final class Type1Parser {
                stream.read(descBinary, 0, sizeOfCharString);
                byte[] description = 
Type1FontUtil.charstringDecrypt(descBinary, lenIV);
                Type1CharStringParser t1p = new Type1CharStringParser();
-               List<Object> operations = t1p.parse(description);
+               // TODO provide the local subroutine indexes
+               List<Object> operations = t1p.parse(description, new 
IndexData(0));
                type1Font.addGlyphDescription(label, new 
GlyphDescription(operations));
 
                readToken(stream); // skip "ND" or "|-" token


Reply via email to