You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ti...@apache.org on 2015/03/16 21:26:03 UTC
svn commit: r1667121 - in
/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff:
CharStringCommand.java Type1CharString.java Type1CharStringParser.java
Type2CharString.java Type2CharStringParser.java
Author: tilman
Date: Mon Mar 16 20:26:02 2015
New Revision: 1667121
URL: http://svn.apache.org/r1667121
Log:
PDFBOX-2576: misc code cleanup, as suggested by Martin Schröder:
- move code out of unneded else
- add @Override where needed
- document an unused parameter
- make methods static
Modified:
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringCommand.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/cff/Type2CharStringParser.java
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringCommand.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringCommand.java?rev=1667121&r1=1667120&r2=1667121&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringCommand.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringCommand.java Mon Mar 16 20:26:02 2015
@@ -1,320 +1,317 @@
-/*
- * 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.cff;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-/**
- * This class represents a CharStringCommand.
- *
- * @author Villu Ruusmann
- */
-public class CharStringCommand
-{
-
- private Key commandKey = null;
-
- /**
- * Constructor with one value.
- *
- * @param b0 value
- */
- public CharStringCommand(int b0)
- {
- setKey(new Key(b0));
- }
-
- /**
- * Constructor with two values.
- *
- * @param b0 value1
- * @param b1 value2
- */
- public CharStringCommand(int b0, int b1)
- {
- setKey(new Key(b0, b1));
- }
-
- /**
- * Constructor with an array as values.
- *
- * @param values array of values
- */
- public CharStringCommand(int[] values)
- {
- setKey(new Key(values));
- }
-
- /**
- * The key of the CharStringCommand.
- * @return the key
- */
- public Key getKey()
- {
- return commandKey;
- }
-
- private void setKey(Key key)
- {
- commandKey = key;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString()
- {
- String str = TYPE2_VOCABULARY.get(getKey());
- if (str == null)
- {
- str = TYPE1_VOCABULARY.get(getKey());
- }
- if (str == null)
- {
- return getKey().toString() + '|';
- }
- else
- {
- return str + '|';
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode()
- {
- return getKey().hashCode();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object object)
- {
- if (object instanceof CharStringCommand)
- {
- CharStringCommand that = (CharStringCommand) object;
- return getKey().equals(that.getKey());
- }
- return false;
- }
-
- /**
- * A static class to hold one or more int values as key.
- */
- public static class Key
- {
-
- private int[] keyValues = null;
-
- /**
- * Constructor with one value.
- *
- * @param b0 value
- */
- public Key(int b0)
- {
- setValue(new int[] { b0 });
- }
-
- /**
- * Constructor with two values.
- *
- * @param b0 value1
- * @param b1 value2
- */
- public Key(int b0, int b1)
- {
- setValue(new int[] { b0, b1 });
- }
-
- /**
- * Constructor with an array as values.
- *
- * @param values array of values
- */
- public Key(int[] values)
- {
- setValue(values);
- }
-
- /**
- * Array the with the values.
- *
- * @return array with the values
- */
- public int[] getValue()
- {
- return keyValues;
- }
-
- private void setValue(int[] value)
- {
- keyValues = value;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString()
- {
- return Arrays.toString(getValue());
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode()
- {
- if (keyValues[0] == 12 && keyValues.length > 1)
- {
- return keyValues[0] ^ keyValues[1];
- }
- return keyValues[0];
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object object)
- {
- if (object instanceof Key)
- {
- Key that = (Key) object;
- if (keyValues[0] == 12 && that.keyValues[0] == 12)
- {
- if (keyValues.length > 1 && that.keyValues.length > 1)
- {
- return keyValues[1] == that.keyValues[1];
- }
- return keyValues.length == that.keyValues.length;
- }
- return keyValues[0] == that.keyValues[0];
- }
- return false;
- }
- }
-
- /**
- * A map with the Type1 vocabulary.
- */
- public static final Map<Key, String> TYPE1_VOCABULARY;
-
- static
- {
- Map<Key, String> map = new LinkedHashMap<Key, String>();
- map.put(new Key(1), "hstem");
- map.put(new Key(3), "vstem");
- map.put(new Key(4), "vmoveto");
- map.put(new Key(5), "rlineto");
- map.put(new Key(6), "hlineto");
- map.put(new Key(7), "vlineto");
- map.put(new Key(8), "rrcurveto");
- map.put(new Key(9), "closepath");
- map.put(new Key(10), "callsubr");
- map.put(new Key(11), "return");
- map.put(new Key(12), "escape");
- map.put(new Key(12, 0), "dotsection");
- map.put(new Key(12, 1), "vstem3");
- map.put(new Key(12, 2), "hstem3");
- map.put(new Key(12, 6), "seac");
- map.put(new Key(12, 7), "sbw");
- map.put(new Key(12, 12), "div");
- map.put(new Key(12, 16), "callothersubr");
- map.put(new Key(12, 17), "pop");
- map.put(new Key(12, 33), "setcurrentpoint");
- map.put(new Key(13), "hsbw");
- map.put(new Key(14), "endchar");
- map.put(new Key(21), "rmoveto");
- map.put(new Key(22), "hmoveto");
- map.put(new Key(30), "vhcurveto");
- map.put(new Key(31), "hvcurveto");
-
- TYPE1_VOCABULARY = Collections.unmodifiableMap(map);
- }
-
- /**
- * A map with the Type2 vocabulary.
- */
- public static final Map<Key, String> TYPE2_VOCABULARY;
-
- static
- {
- Map<Key, String> map = new LinkedHashMap<Key, String>();
- map.put(new Key(1), "hstem");
- map.put(new Key(3), "vstem");
- map.put(new Key(4), "vmoveto");
- map.put(new Key(5), "rlineto");
- map.put(new Key(6), "hlineto");
- map.put(new Key(7), "vlineto");
- map.put(new Key(8), "rrcurveto");
- map.put(new Key(10), "callsubr");
- map.put(new Key(11), "return");
- map.put(new Key(12), "escape");
- map.put(new Key(12, 3), "and");
- map.put(new Key(12, 4), "or");
- map.put(new Key(12, 5), "not");
- map.put(new Key(12, 9), "abs");
- map.put(new Key(12, 10), "add");
- map.put(new Key(12, 11), "sub");
- map.put(new Key(12, 12), "div");
- map.put(new Key(12, 14), "neg");
- map.put(new Key(12, 15), "eq");
- map.put(new Key(12, 18), "drop");
- map.put(new Key(12, 20), "put");
- map.put(new Key(12, 21), "get");
- map.put(new Key(12, 22), "ifelse");
- map.put(new Key(12, 23), "random");
- map.put(new Key(12, 24), "mul");
- map.put(new Key(12, 26), "sqrt");
- map.put(new Key(12, 27), "dup");
- map.put(new Key(12, 28), "exch");
- map.put(new Key(12, 29), "index");
- map.put(new Key(12, 30), "roll");
- map.put(new Key(12, 34), "hflex");
- map.put(new Key(12, 35), "flex");
- map.put(new Key(12, 36), "hflex1");
- map.put(new Key(12, 37), "flex1");
- map.put(new Key(14), "endchar");
- map.put(new Key(18), "hstemhm");
- map.put(new Key(19), "hintmask");
- map.put(new Key(20), "cntrmask");
- map.put(new Key(21), "rmoveto");
- map.put(new Key(22), "hmoveto");
- map.put(new Key(23), "vstemhm");
- map.put(new Key(24), "rcurveline");
- map.put(new Key(25), "rlinecurve");
- map.put(new Key(26), "vvcurveto");
- map.put(new Key(27), "hhcurveto");
- map.put(new Key(28), "shortint");
- map.put(new Key(29), "callgsubr");
- map.put(new Key(30), "vhcurveto");
- map.put(new Key(31), "hvcurveto");
-
- TYPE2_VOCABULARY = Collections.unmodifiableMap(map);
- }
-}
+/*
+ * 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.cff;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * This class represents a CharStringCommand.
+ *
+ * @author Villu Ruusmann
+ */
+public class CharStringCommand
+{
+
+ private Key commandKey = null;
+
+ /**
+ * Constructor with one value.
+ *
+ * @param b0 value
+ */
+ public CharStringCommand(int b0)
+ {
+ setKey(new Key(b0));
+ }
+
+ /**
+ * Constructor with two values.
+ *
+ * @param b0 value1
+ * @param b1 value2
+ */
+ public CharStringCommand(int b0, int b1)
+ {
+ setKey(new Key(b0, b1));
+ }
+
+ /**
+ * Constructor with an array as values.
+ *
+ * @param values array of values
+ */
+ public CharStringCommand(int[] values)
+ {
+ setKey(new Key(values));
+ }
+
+ /**
+ * The key of the CharStringCommand.
+ * @return the key
+ */
+ public Key getKey()
+ {
+ return commandKey;
+ }
+
+ private void setKey(Key key)
+ {
+ commandKey = key;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString()
+ {
+ String str = TYPE2_VOCABULARY.get(getKey());
+ if (str == null)
+ {
+ str = TYPE1_VOCABULARY.get(getKey());
+ }
+ if (str == null)
+ {
+ return getKey().toString() + '|';
+ }
+ return str + '|';
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode()
+ {
+ return getKey().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object object)
+ {
+ if (object instanceof CharStringCommand)
+ {
+ CharStringCommand that = (CharStringCommand) object;
+ return getKey().equals(that.getKey());
+ }
+ return false;
+ }
+
+ /**
+ * A static class to hold one or more int values as key.
+ */
+ public static class Key
+ {
+
+ private int[] keyValues = null;
+
+ /**
+ * Constructor with one value.
+ *
+ * @param b0 value
+ */
+ public Key(int b0)
+ {
+ setValue(new int[] { b0 });
+ }
+
+ /**
+ * Constructor with two values.
+ *
+ * @param b0 value1
+ * @param b1 value2
+ */
+ public Key(int b0, int b1)
+ {
+ setValue(new int[] { b0, b1 });
+ }
+
+ /**
+ * Constructor with an array as values.
+ *
+ * @param values array of values
+ */
+ public Key(int[] values)
+ {
+ setValue(values);
+ }
+
+ /**
+ * Array the with the values.
+ *
+ * @return array with the values
+ */
+ public int[] getValue()
+ {
+ return keyValues;
+ }
+
+ private void setValue(int[] value)
+ {
+ keyValues = value;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString()
+ {
+ return Arrays.toString(getValue());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode()
+ {
+ if (keyValues[0] == 12 && keyValues.length > 1)
+ {
+ return keyValues[0] ^ keyValues[1];
+ }
+ return keyValues[0];
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object object)
+ {
+ if (object instanceof Key)
+ {
+ Key that = (Key) object;
+ if (keyValues[0] == 12 && that.keyValues[0] == 12)
+ {
+ if (keyValues.length > 1 && that.keyValues.length > 1)
+ {
+ return keyValues[1] == that.keyValues[1];
+ }
+ return keyValues.length == that.keyValues.length;
+ }
+ return keyValues[0] == that.keyValues[0];
+ }
+ return false;
+ }
+ }
+
+ /**
+ * A map with the Type1 vocabulary.
+ */
+ public static final Map<Key, String> TYPE1_VOCABULARY;
+
+ static
+ {
+ Map<Key, String> map = new LinkedHashMap<Key, String>();
+ map.put(new Key(1), "hstem");
+ map.put(new Key(3), "vstem");
+ map.put(new Key(4), "vmoveto");
+ map.put(new Key(5), "rlineto");
+ map.put(new Key(6), "hlineto");
+ map.put(new Key(7), "vlineto");
+ map.put(new Key(8), "rrcurveto");
+ map.put(new Key(9), "closepath");
+ map.put(new Key(10), "callsubr");
+ map.put(new Key(11), "return");
+ map.put(new Key(12), "escape");
+ map.put(new Key(12, 0), "dotsection");
+ map.put(new Key(12, 1), "vstem3");
+ map.put(new Key(12, 2), "hstem3");
+ map.put(new Key(12, 6), "seac");
+ map.put(new Key(12, 7), "sbw");
+ map.put(new Key(12, 12), "div");
+ map.put(new Key(12, 16), "callothersubr");
+ map.put(new Key(12, 17), "pop");
+ map.put(new Key(12, 33), "setcurrentpoint");
+ map.put(new Key(13), "hsbw");
+ map.put(new Key(14), "endchar");
+ map.put(new Key(21), "rmoveto");
+ map.put(new Key(22), "hmoveto");
+ map.put(new Key(30), "vhcurveto");
+ map.put(new Key(31), "hvcurveto");
+
+ TYPE1_VOCABULARY = Collections.unmodifiableMap(map);
+ }
+
+ /**
+ * A map with the Type2 vocabulary.
+ */
+ public static final Map<Key, String> TYPE2_VOCABULARY;
+
+ static
+ {
+ Map<Key, String> map = new LinkedHashMap<Key, String>();
+ map.put(new Key(1), "hstem");
+ map.put(new Key(3), "vstem");
+ map.put(new Key(4), "vmoveto");
+ map.put(new Key(5), "rlineto");
+ map.put(new Key(6), "hlineto");
+ map.put(new Key(7), "vlineto");
+ map.put(new Key(8), "rrcurveto");
+ map.put(new Key(10), "callsubr");
+ map.put(new Key(11), "return");
+ map.put(new Key(12), "escape");
+ map.put(new Key(12, 3), "and");
+ map.put(new Key(12, 4), "or");
+ map.put(new Key(12, 5), "not");
+ map.put(new Key(12, 9), "abs");
+ map.put(new Key(12, 10), "add");
+ map.put(new Key(12, 11), "sub");
+ map.put(new Key(12, 12), "div");
+ map.put(new Key(12, 14), "neg");
+ map.put(new Key(12, 15), "eq");
+ map.put(new Key(12, 18), "drop");
+ map.put(new Key(12, 20), "put");
+ map.put(new Key(12, 21), "get");
+ map.put(new Key(12, 22), "ifelse");
+ map.put(new Key(12, 23), "random");
+ map.put(new Key(12, 24), "mul");
+ map.put(new Key(12, 26), "sqrt");
+ map.put(new Key(12, 27), "dup");
+ map.put(new Key(12, 28), "exch");
+ map.put(new Key(12, 29), "index");
+ map.put(new Key(12, 30), "roll");
+ map.put(new Key(12, 34), "hflex");
+ map.put(new Key(12, 35), "flex");
+ map.put(new Key(12, 36), "hflex1");
+ map.put(new Key(12, 37), "flex1");
+ map.put(new Key(14), "endchar");
+ map.put(new Key(18), "hstemhm");
+ map.put(new Key(19), "hintmask");
+ map.put(new Key(20), "cntrmask");
+ map.put(new Key(21), "rmoveto");
+ map.put(new Key(22), "hmoveto");
+ map.put(new Key(23), "vstemhm");
+ map.put(new Key(24), "rcurveline");
+ map.put(new Key(25), "rlinecurve");
+ map.put(new Key(26), "vvcurveto");
+ map.put(new Key(27), "hhcurveto");
+ map.put(new Key(28), "shortint");
+ map.put(new Key(29), "callgsubr");
+ map.put(new Key(30), "vhcurveto");
+ map.put(new Key(31), "hvcurveto");
+
+ TYPE2_VOCABULARY = Collections.unmodifiableMap(map);
+ }
+}
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=1667121&r1=1667120&r2=1667121&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 Mon Mar 16 20:26:02 2015
@@ -16,11 +16,6 @@
*/
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;
@@ -30,6 +25,11 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fontbox.encoding.StandardEncoding;
+import org.apache.fontbox.type1.Type1CharStringReader;
+
/**
* This class represents and renders a Type 1 CharString.
*
@@ -138,6 +138,7 @@ public class Type1CharString
leftSideBearing = new Point2D.Float(0, 0);
width = 0;
CharStringHandler handler = new CharStringHandler() {
+ @Override
public List<Integer> handleCommand(List<Integer> numbers, CharStringCommand command)
{
return Type1CharString.this.handleCommand(numbers, command);
@@ -411,6 +412,7 @@ public class Type1CharString
* Standard Encoding Accented Character
*
* Makes an accented character from two other characters.
+ * @param asb
*/
private void seac(Number asb, Number adx, Number ady, Number bchar, Number achar)
{
@@ -452,4 +454,4 @@ public class Type1CharString
{
return type1Sequence.toString().replace("|","\n").replace(",", " ");
}
-}
\ No newline at end of file
+}
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=1667121&r1=1667120&r2=1667121&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 Mon Mar 16 20:26:02 2015
@@ -1,235 +1,229 @@
-/*
- * 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.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 Type 1 sequence.
- *
- * @see "Adobe Type 1 Font Format, Adobe Systems (1999)"
- *
- * @author Villu Ruusmann
- * @author John Hewson
- */
-public class Type1CharStringParser
-{
- private static final Log LOG = LogFactory.getLog(Type1CharStringParser.class);
-
- // 1-byte commands
- static final int RETURN = 11;
- static final int CALLSUBR = 10;
-
- // 2-byte commands
- static final int TWO_BYTE = 12;
- static final int CALLOTHERSUBR = 16;
- static final int POP = 17;
-
- private final 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 subrs list of local subroutines
- * @return the Type1 sequence
- * @throws IOException if an error occurs during reading
- */
- public List<Object> parse(byte[] bytes, List<byte[]> subrs) throws IOException
- {
- return parse(bytes, subrs, new ArrayList<Object>());
- }
-
- private List<Object> parse(byte[] bytes, List<byte[]> subrs, List<Object> sequence) throws IOException
- {
- DataInput input = new DataInput(bytes);
- while (input.hasRemaining())
- {
- int b0 = input.readUnsignedByte();
- if (b0 == CALLSUBR)
- {
- // callsubr command
- Integer operand=(Integer)sequence.remove(sequence.size()-1);
-
- if (operand < subrs.size())
- {
- 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 (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(removeInteger(sequence));
- results.push(removeInteger(sequence));
- sequence.remove(sequence.size() - 1);
- // end flex
- sequence.add(0);
- sequence.add(new CharStringCommand(TWO_BYTE, CALLOTHERSUBR));
- }
- else if (othersubrNum == 1)
- {
- // begin flex
- sequence.add(1);
- sequence.add(new CharStringCommand(TWO_BYTE, CALLOTHERSUBR));
- }
- else if (othersubrNum == 3)
- {
- // allows hint replacement
- results.push(removeInteger(sequence));
- }
- else
- {
- // all remaining othersubrs use this fallback mechanism
- for (int i = 0; i < numArgs; i++)
- {
- Integer arg = removeInteger(sequence);
- 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(input, b0));
- }
- else if (b0 >= 32 && b0 <= 255)
- {
- sequence.add(readNumber(input, b0));
- }
- else
- {
- throw new IllegalArgumentException();
- }
- }
- return sequence;
- }
-
- // this method is a workaround for the fact that Type1CharStringParser assumes that subrs and
- // othersubrs can be unrolled without executing the 'div' operator, which isn't true
- private Integer removeInteger(List<Object> sequence) throws IOException
- {
- Object item = sequence.remove(sequence.size() - 1);
- if (item instanceof Integer)
- {
- return (Integer)item;
- }
- else
- {
- CharStringCommand command = (CharStringCommand)item;
-
- // div
- if (command.getKey().getValue()[0] == 12 && command.getKey().getValue()[0] == 12)
- {
- int a = (Integer)sequence.remove(sequence.size() - 1);
- int b = (Integer)sequence.remove(sequence.size() - 1);
- return b / a;
- }
- else
- {
- throw new IOException("Unexpected char string command: " + command.getKey());
- }
- }
- }
-
- private CharStringCommand readCommand(DataInput input, int b0) throws IOException
- {
- if (b0 == 12)
- {
- int b1 = input.readUnsignedByte();
- return new CharStringCommand(b0, b1);
- }
- return new CharStringCommand(b0);
- }
-
- private Integer readNumber(DataInput input, int b0) throws IOException
- {
- if (b0 >= 32 && b0 <= 246)
- {
- return b0 - 139;
- }
- else if (b0 >= 247 && b0 <= 250)
- {
- int b1 = input.readUnsignedByte();
- return (b0 - 247) * 256 + b1 + 108;
- }
- else if (b0 >= 251 && b0 <= 254)
- {
- int b1 = input.readUnsignedByte();
- return -(b0 - 251) * 256 - b1 - 108;
- }
- else if (b0 == 255)
- {
- int b1 = input.readUnsignedByte();
- int b2 = input.readUnsignedByte();
- int b3 = input.readUnsignedByte();
- int b4 = input.readUnsignedByte();
-
- return b1 << 24 | b2 << 16 | b3 << 8 | b4;
- }
- else
- {
- throw new IllegalArgumentException();
- }
- }
-}
+/*
+ * 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.cff;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * 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
+ * @author John Hewson
+ */
+public class Type1CharStringParser
+{
+ private static final Log LOG = LogFactory.getLog(Type1CharStringParser.class);
+
+ // 1-byte commands
+ static final int RETURN = 11;
+ static final int CALLSUBR = 10;
+
+ // 2-byte commands
+ static final int TWO_BYTE = 12;
+ static final int CALLOTHERSUBR = 16;
+ static final int POP = 17;
+
+ private final 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 subrs list of local subroutines
+ * @return the Type1 sequence
+ * @throws IOException if an error occurs during reading
+ */
+ public List<Object> parse(byte[] bytes, List<byte[]> subrs) throws IOException
+ {
+ return parse(bytes, subrs, new ArrayList<Object>());
+ }
+
+ private List<Object> parse(byte[] bytes, List<byte[]> subrs, List<Object> sequence) throws IOException
+ {
+ DataInput input = new DataInput(bytes);
+ while (input.hasRemaining())
+ {
+ int b0 = input.readUnsignedByte();
+ if (b0 == CALLSUBR)
+ {
+ // callsubr command
+ Integer operand=(Integer)sequence.remove(sequence.size()-1);
+
+ if (operand < subrs.size())
+ {
+ 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 (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(removeInteger(sequence));
+ results.push(removeInteger(sequence));
+ sequence.remove(sequence.size() - 1);
+ // end flex
+ sequence.add(0);
+ sequence.add(new CharStringCommand(TWO_BYTE, CALLOTHERSUBR));
+ }
+ else if (othersubrNum == 1)
+ {
+ // begin flex
+ sequence.add(1);
+ sequence.add(new CharStringCommand(TWO_BYTE, CALLOTHERSUBR));
+ }
+ else if (othersubrNum == 3)
+ {
+ // allows hint replacement
+ results.push(removeInteger(sequence));
+ }
+ else
+ {
+ // all remaining othersubrs use this fallback mechanism
+ for (int i = 0; i < numArgs; i++)
+ {
+ Integer arg = removeInteger(sequence);
+ 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(input, b0));
+ }
+ else if (b0 >= 32 && b0 <= 255)
+ {
+ sequence.add(readNumber(input, b0));
+ }
+ else
+ {
+ throw new IllegalArgumentException();
+ }
+ }
+ return sequence;
+ }
+
+ // this method is a workaround for the fact that Type1CharStringParser assumes that subrs and
+ // othersubrs can be unrolled without executing the 'div' operator, which isn't true
+ private static Integer removeInteger(List<Object> sequence) throws IOException
+ {
+ Object item = sequence.remove(sequence.size() - 1);
+ if (item instanceof Integer)
+ {
+ return (Integer)item;
+ }
+ CharStringCommand command = (CharStringCommand) item;
+
+ // div
+ if (command.getKey().getValue()[0] == 12 && command.getKey().getValue()[0] == 12)
+ {
+ int a = (Integer) sequence.remove(sequence.size() - 1);
+ int b = (Integer) sequence.remove(sequence.size() - 1);
+ return b / a;
+ }
+ throw new IOException("Unexpected char string command: " + command.getKey());
+ }
+
+ private static CharStringCommand readCommand(DataInput input, int b0) throws IOException
+ {
+ if (b0 == 12)
+ {
+ int b1 = input.readUnsignedByte();
+ return new CharStringCommand(b0, b1);
+ }
+ return new CharStringCommand(b0);
+ }
+
+ private static Integer readNumber(DataInput input, int b0) throws IOException
+ {
+ if (b0 >= 32 && b0 <= 246)
+ {
+ return b0 - 139;
+ }
+ else if (b0 >= 247 && b0 <= 250)
+ {
+ int b1 = input.readUnsignedByte();
+ return (b0 - 247) * 256 + b1 + 108;
+ }
+ else if (b0 >= 251 && b0 <= 254)
+ {
+ int b1 = input.readUnsignedByte();
+ return -(b0 - 251) * 256 - b1 - 108;
+ }
+ else if (b0 == 255)
+ {
+ int b1 = input.readUnsignedByte();
+ int b2 = input.readUnsignedByte();
+ int b3 = input.readUnsignedByte();
+ int b4 = input.readUnsignedByte();
+
+ return b1 << 24 | b2 << 16 | b3 << 8 | b4;
+ }
+ else
+ {
+ throw new IllegalArgumentException();
+ }
+ }
+}
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=1667121&r1=1667120&r2=1667121&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 Mon Mar 16 20:26:02 2015
@@ -16,13 +16,13 @@
*/
package org.apache.fontbox.cff;
-import org.apache.fontbox.type1.Type1CharStringReader;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import org.apache.fontbox.type1.Type1CharStringReader;
+
/**
* Represents a Type 2 CharString by converting it into an equivalent Type 1 CharString.
*
@@ -83,6 +83,7 @@ public class Type2CharString extends Typ
type1Sequence = new ArrayList<Object>();
pathCount = 0;
CharStringHandler handler = new CharStringHandler() {
+ @Override
public List<Integer> handleCommand(List<Integer> numbers, CharStringCommand command)
{
return Type2CharString.this.handleCommand(numbers, command);
@@ -269,6 +270,10 @@ public class Type2CharString extends Typ
return numbers;
}
+ /**
+ * @param numbers
+ * @param horizontal
+ */
private void expandStemHints(List<Integer> numbers, boolean horizontal)
{
// TODO
@@ -379,4 +384,4 @@ public class Type2CharString extends Typ
}
return result;
}
-}
\ No newline at end of file
+}
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=1667121&r1=1667120&r2=1667121&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 Mon Mar 16 20:26:02 2015
@@ -1,287 +1,287 @@
-/*
- * 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.cff;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * This class represents a converter for a mapping into a Type2-sequence.
- * @author Villu Ruusmann
- */
-public class Type2CharStringParser
-{
- private int hstemCount = 0;
- private int vstemCount = 0;
- private List<Object> sequence = null;
- private final String fontName, glyphName;
-
- /**
- * Constructs a new Type1CharStringParser object for a Type 1-equivalent font.
- *
- * @param fontName font name
- * @param glyphName glyph name
- */
- public Type2CharStringParser(String fontName, String glyphName)
- {
- this.fontName = fontName;
- this.glyphName = glyphName;
- }
-
- /**
- * Constructs a new Type1CharStringParser object for a CID-Keyed font.
- *
- * @param fontName font name
- * @param cid CID
- */
- public Type2CharStringParser(String fontName, int cid)
- {
- this.fontName = fontName;
- this.glyphName = String.format("%04x", cid); // for debugging only
- }
-
- /**
- * The given byte array will be parsed and converted to a Type2 sequence.
- * @param bytes the given mapping as byte array
- * @param globalSubrIndex index containing all global subroutines
- * @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, IndexData globalSubrIndex, IndexData localSubrIndex) throws IOException
- {
- 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 == 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, input));
- }
- else if (b0 == 28)
- {
- sequence.add(readNumber(b0, input));
- }
- else if (b0 >= 29 && b0 <= 31)
- {
- sequence.add(readCommand(b0, input));
- }
- else if (b0 >= 32 && b0 <= 255)
- {
- sequence.add(readNumber(b0, input));
- }
- else
- {
- throw new IllegalArgumentException();
- }
- }
- return sequence;
- }
-
- private CharStringCommand readCommand(int b0, DataInput input) throws IOException
- {
-
- if (b0 == 1 || b0 == 18)
- {
- hstemCount += peekNumbers().size() / 2;
- }
- else if (b0 == 3 || b0 == 19 || b0 == 20 || b0 == 23)
- {
- vstemCount += peekNumbers().size() / 2;
- } // End if
-
- if (b0 == 12)
- {
- int b1 = input.readUnsignedByte();
-
- return new CharStringCommand(b0, b1);
- }
- else if (b0 == 19 || b0 == 20)
- {
- int[] value = new int[1 + getMaskLength()];
- value[0] = b0;
-
- for (int i = 1; i < value.length; i++)
- {
- value[i] = input.readUnsignedByte();
- }
-
- return new CharStringCommand(value);
- }
-
- return new CharStringCommand(b0);
- }
-
- private Integer readNumber(int b0, DataInput input) throws IOException
- {
-
- if (b0 == 28)
- {
- int b1 = input.readUnsignedByte();
- int b2 = input.readUnsignedByte();
-
- return (int) (short) (b1 << 8 | b2);
- }
- else if (b0 >= 32 && b0 <= 246)
- {
- return b0 - 139;
- }
- else if (b0 >= 247 && b0 <= 250)
- {
- int b1 = input.readUnsignedByte();
-
- return (b0 - 247) * 256 + b1 + 108;
- }
- else if (b0 >= 251 && b0 <= 254)
- {
- int b1 = input.readUnsignedByte();
-
- return -(b0 - 251) * 256 - b1 - 108;
- }
- else if (b0 == 255)
- {
- int b1 = input.readUnsignedByte();
- int b2 = 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 (int) (short)(b1 << 8 | b2);
- }
- else
- {
- throw new IllegalArgumentException();
- }
- }
-
- private int getMaskLength()
- {
- int length = 1;
-
- int hintCount = hstemCount + vstemCount;
- while ((hintCount -= 8) > 0)
- {
- length++;
- }
-
- return length;
- }
-
- private List<Number> peekNumbers()
- {
- List<Number> numbers = new ArrayList<Number>();
-
- for (int i = sequence.size() - 1; i > -1; i--)
- {
- Object object = sequence.get(i);
-
- if (object instanceof Number)
- {
- Number number = (Number) object;
-
- numbers.add(0, number);
-
- continue;
- }
-
- return numbers;
- }
-
- return numbers;
- }
-}
+/*
+ * 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.cff;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class represents a converter for a mapping into a Type2-sequence.
+ * @author Villu Ruusmann
+ */
+public class Type2CharStringParser
+{
+ private int hstemCount = 0;
+ private int vstemCount = 0;
+ private List<Object> sequence = null;
+ private final String fontName, glyphName;
+
+ /**
+ * Constructs a new Type1CharStringParser object for a Type 1-equivalent font.
+ *
+ * @param fontName font name
+ * @param glyphName glyph name
+ */
+ public Type2CharStringParser(String fontName, String glyphName)
+ {
+ this.fontName = fontName;
+ this.glyphName = glyphName;
+ }
+
+ /**
+ * Constructs a new Type1CharStringParser object for a CID-Keyed font.
+ *
+ * @param fontName font name
+ * @param cid CID
+ */
+ public Type2CharStringParser(String fontName, int cid)
+ {
+ this.fontName = fontName;
+ this.glyphName = String.format("%04x", cid); // for debugging only
+ }
+
+ /**
+ * The given byte array will be parsed and converted to a Type2 sequence.
+ * @param bytes the given mapping as byte array
+ * @param globalSubrIndex index containing all global subroutines
+ * @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, IndexData globalSubrIndex, IndexData localSubrIndex) throws IOException
+ {
+ 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 == 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, input));
+ }
+ else if (b0 == 28)
+ {
+ sequence.add(readNumber(b0, input));
+ }
+ else if (b0 >= 29 && b0 <= 31)
+ {
+ sequence.add(readCommand(b0, input));
+ }
+ else if (b0 >= 32 && b0 <= 255)
+ {
+ sequence.add(readNumber(b0, input));
+ }
+ else
+ {
+ throw new IllegalArgumentException();
+ }
+ }
+ return sequence;
+ }
+
+ private CharStringCommand readCommand(int b0, DataInput input) throws IOException
+ {
+
+ if (b0 == 1 || b0 == 18)
+ {
+ hstemCount += peekNumbers().size() / 2;
+ }
+ else if (b0 == 3 || b0 == 19 || b0 == 20 || b0 == 23)
+ {
+ vstemCount += peekNumbers().size() / 2;
+ } // End if
+
+ if (b0 == 12)
+ {
+ int b1 = input.readUnsignedByte();
+
+ return new CharStringCommand(b0, b1);
+ }
+ else if (b0 == 19 || b0 == 20)
+ {
+ int[] value = new int[1 + getMaskLength()];
+ value[0] = b0;
+
+ for (int i = 1; i < value.length; i++)
+ {
+ value[i] = input.readUnsignedByte();
+ }
+
+ return new CharStringCommand(value);
+ }
+
+ return new CharStringCommand(b0);
+ }
+
+ private static Integer readNumber(int b0, DataInput input) throws IOException
+ {
+
+ if (b0 == 28)
+ {
+ int b1 = input.readUnsignedByte();
+ int b2 = input.readUnsignedByte();
+
+ return (int) (short) (b1 << 8 | b2);
+ }
+ else if (b0 >= 32 && b0 <= 246)
+ {
+ return b0 - 139;
+ }
+ else if (b0 >= 247 && b0 <= 250)
+ {
+ int b1 = input.readUnsignedByte();
+
+ return (b0 - 247) * 256 + b1 + 108;
+ }
+ else if (b0 >= 251 && b0 <= 254)
+ {
+ int b1 = input.readUnsignedByte();
+
+ return -(b0 - 251) * 256 - b1 - 108;
+ }
+ else if (b0 == 255)
+ {
+ int b1 = input.readUnsignedByte();
+ int b2 = 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 (int) (short)(b1 << 8 | b2);
+ }
+ else
+ {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private int getMaskLength()
+ {
+ int length = 1;
+
+ int hintCount = hstemCount + vstemCount;
+ while ((hintCount -= 8) > 0)
+ {
+ length++;
+ }
+
+ return length;
+ }
+
+ private List<Number> peekNumbers()
+ {
+ List<Number> numbers = new ArrayList<Number>();
+
+ for (int i = sequence.size() - 1; i > -1; i--)
+ {
+ Object object = sequence.get(i);
+
+ if (object instanceof Number)
+ {
+ Number number = (Number) object;
+
+ numbers.add(0, number);
+
+ continue;
+ }
+
+ return numbers;
+ }
+
+ return numbers;
+ }
+}