]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
replaced fontbox snapshot jar by a patched released jar (patch files added to lib)
authorLuis Bernardo <lbernardo@apache.org>
Tue, 3 Dec 2013 10:51:24 +0000 (10:51 +0000)
committerLuis Bernardo <lbernardo@apache.org>
Tue, 3 Dec 2013 10:51:24 +0000 (10:51 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1547340 13f79535-47bb-0310-9956-ffa450edef68

lib/fontbox-1.8.0-SNAPSHOT.jar [deleted file]
lib/fontbox-1.8.3-patched.jar [new file with mode: 0644]
lib/pdfbox-1645.patch [new file with mode: 0644]
lib/pdfbox-1646.patch [new file with mode: 0644]

diff --git a/lib/fontbox-1.8.0-SNAPSHOT.jar b/lib/fontbox-1.8.0-SNAPSHOT.jar
deleted file mode 100644 (file)
index e20e1ad..0000000
Binary files a/lib/fontbox-1.8.0-SNAPSHOT.jar and /dev/null differ
diff --git a/lib/fontbox-1.8.3-patched.jar b/lib/fontbox-1.8.3-patched.jar
new file mode 100644 (file)
index 0000000..57460be
Binary files /dev/null and b/lib/fontbox-1.8.3-patched.jar differ
diff --git a/lib/pdfbox-1645.patch b/lib/pdfbox-1645.patch
new file mode 100644 (file)
index 0000000..f9dda73
--- /dev/null
@@ -0,0 +1,395 @@
+Index: fontbox/src/test/java/org/apache/fontbox/cff/CharStringRendererTest.java
+===================================================================
+--- fontbox/src/test/java/org/apache/fontbox/cff/CharStringRendererTest.java   (revision 0)
++++ fontbox/src/test/java/org/apache/fontbox/cff/CharStringRendererTest.java   (revision 0)
+@@ -0,0 +1,28 @@
++package org.apache.fontbox.cff;
++
++import java.util.ArrayList;
++import java.util.List;
++
++import org.junit.Test;
++
++import static org.junit.Assert.assertTrue;
++
++public class CharStringRendererTest {
++
++    @Test
++    public void testArgumentValidation() {
++        CharStringRenderer renderer = new CharStringRenderer();
++        List<Integer> numbers = new ArrayList<Integer>();
++        for (int i = 0;i < 4;i++) {
++            numbers.add(1);
++        }
++        assertTrue(renderer.hasValidArguments("vhcurveto", numbers));
++        numbers.add(1);
++        assertTrue(renderer.hasValidArguments("vvcurveto", numbers));
++        for (int i = 0;i < 3;i++) {
++            numbers.add(1);
++        }
++        assertTrue(renderer.hasValidArguments("rcurveline", numbers));
++    }
++
++}
+Index: fontbox/src/main/java/org/apache/fontbox/cff/AFMFormatter.java
+===================================================================
+--- fontbox/src/main/java/org/apache/fontbox/cff/AFMFormatter.java     (revision 1546564)
++++ fontbox/src/main/java/org/apache/fontbox/cff/AFMFormatter.java     (working copy)
+@@ -27,7 +27,7 @@
+ /**
+  * This class creates all needed AFM font metric data from a CFFFont ready to be read from a AFMPaser.
+- * 
++ *
+  * @author Villu Ruusmann
+  * @version $Revision$
+  */
+@@ -125,7 +125,7 @@
+             metric.name = mapping.getName();
+             renderer.render(mapping.toType1Sequence());
+             metric.width = renderer.getWidth();
+-            metric.bounds = renderer.getBounds();
++            metric.bounds = renderer.getBounds2D();
+             metrics.add(metric);
+         }
+         return metrics;
+@@ -150,7 +150,7 @@
+     }
+     /**
+-     * This class represents the metric of one single character. 
++     * This class represents the metric of one single character.
+      *
+      */
+     private static class CharMetric implements Comparable<CharMetric>
+Index: fontbox/src/main/java/org/apache/fontbox/cff/CharStringRenderer.java
+===================================================================
+--- fontbox/src/main/java/org/apache/fontbox/cff/CharStringRenderer.java       (revision 1546564)
++++ fontbox/src/main/java/org/apache/fontbox/cff/CharStringRenderer.java       (working copy)
+@@ -16,9 +16,11 @@
+  */
+ package org.apache.fontbox.cff;
++import java.awt.Point;
+ import java.awt.geom.GeneralPath;
+ import java.awt.geom.Point2D;
+ import java.awt.geom.Rectangle2D;
++import java.util.HashMap;
+ import java.util.List;
+ import org.apache.commons.logging.Log;
+@@ -33,7 +35,7 @@
+ {
+     // TODO CharStringRenderer as abstract Class with two inherited classes according to the Charsstring type....
+       private static final Log LOG = LogFactory.getLog(CharStringRenderer.class);
+-      
++
+       private boolean isCharstringType1 = true;
+     private boolean isFirstCommand = true;
+@@ -42,6 +44,8 @@
+     private Point2D referencePoint = null;
+     private int width = 0;
+     private boolean hasNonEndCharOp = false;
++    private int[] bbox = {0,0,0,0};
++    private HashMap<String, String> vStrings;
+     /**
+      * Constructor for the char string renderer.
+@@ -100,7 +104,7 @@
+     private void handleCommandType2(List<Integer> numbers, CharStringCommand command)
+     {
+         String name = CharStringCommand.TYPE2_VOCABULARY.get(command.getKey());
+-
++        checkArguments(name, numbers);
+         if (!hasNonEndCharOp)
+         {
+             hasNonEndCharOp = !"endchar".equals(name);
+@@ -176,7 +180,7 @@
+                 setWidth(numbers.get(0));
+                 rmoveTo(numbers.get(1), numbers.get(2));
+             }
+-            else
++            else if (numbers.size() == 2)
+             {
+                 rmoveTo(numbers.get(0), numbers.get(1));
+             }
+@@ -192,7 +196,7 @@
+                 setWidth(numbers.get(0));
+                 rmoveTo(numbers.get(1), Integer.valueOf(0));
+             }
+-            else
++            else if (numbers.size() == 1)
+             {
+                 rmoveTo(numbers.get(0), Integer.valueOf(0));
+             }
+@@ -284,6 +288,61 @@
+         }
+     }
++    void checkArguments(String name, List<Integer> numbers) {
++        if (name == null) {
++            return;
++        }
++        boolean valid = hasValidArguments(name, numbers);
++        if (!valid) {
++            //Initialize the validation strings if not already done
++            if (vStrings == null) {
++                vStrings = new HashMap<String, String>();
++                vStrings.put("vmoveto", "1 || 2");
++                vStrings.put("rlineto", "3 || % 2");
++                vStrings.put("rrcurveto", "7 || % 6");
++                vStrings.put("rlinecurve", "% 2 || 6 + % 2");
++                vStrings.put("rcurveline", "% 6 || 2 + % 6");
++                vStrings.put("rmoveto", "2 || 3");
++                vStrings.put("hmoveto", "1 || 2");
++                vStrings.put("vhcurveto", "% 4 || 1 + % 4");
++                vStrings.put("hvcurveto", "% 4 || 1 + % 4");
++                vStrings.put("vvcurveto", "% 4 || 1 + % 4");
++            }
++            LOG.info(String.format("Font has an unexpected number of parameters for operator '%s'. Arguments "+
++                    "size %d did not match pattern '%s'", name, numbers.size(),
++                    vStrings.get(name)));
++        }
++    }
++
++    boolean hasValidArguments(String name, List<Integer> numbers) {
++        boolean valid = true;
++        if (name.equals("vmoveto")) {
++            valid = (numbers.size() == 1 || numbers.size() == 2);
++        }
++        if (name.equals("rlineto")) {
++            valid = (numbers.size() == 3 || numbers.size() % 2 == 0);
++        }
++        if (name.equals("rrcurveto")) {
++            valid = (numbers.size() == 7 || numbers.size() % 6 == 0);
++        }
++        if (name.equals("rlinecurve")) {
++            valid = (numbers.size() % 2 == 0 || (numbers.size() - 6) % 2 == 0);
++        }
++        if (name.equals("rcurveline")) {
++            valid = (numbers.size() % 6 == 0 || (numbers.size() - 2) % 6 == 0);
++        }
++        if (name.equals("rmoveto")) {
++            valid = (numbers.size() == 2 || numbers.size() == 3);
++        }
++        if (name.equals("hmoveto")) {
++            valid = (numbers.size() == 1 || numbers.size() == 2);
++        }
++        if (name.equals("vvcurveto") || name.equals("vhcurveto") || name.equals("hvcurveto")) {
++            valid = (numbers.size() % 4 == 0 || (numbers.size() - 1) % 4 == 0);
++        }
++        return valid;
++    }
++
+     /**
+      *
+      * @param numbers
+@@ -353,11 +412,14 @@
+         Point2D point = referencePoint;
+         if (point == null)
+         {
+-            point = path.getCurrentPoint();
+-            if (point == null)
++            if (path.getCurrentPoint() == null)
+             {
+                 point = sidebearingPoint;
+             }
++            else
++            {
++                point = path.getCurrentPoint();
++            }
+         }
+         referencePoint = null;
+         path.moveTo((float)(point.getX() + dx.doubleValue()),
+@@ -397,15 +459,20 @@
+     private void rlineTo(Number dx, Number dy)
+     {
+         Point2D point = path.getCurrentPoint();
+-        path.lineTo((float)(point.getX() + dx.doubleValue()),
+-                (float)(point.getY() + dy.doubleValue()));
++        if (point != null) {
++            updateBBox(dx.intValue(), dy.intValue());
++            path.lineTo((float)(point.getX() + dx.doubleValue()),
++                    (float)(point.getY() + dy.doubleValue()));
++        }
+     }
+     private void rrlineTo(List<Integer> numbers)
+     {
+         for (int i = 0;i < numbers.size();i += 2)
+         {
+-            rlineTo(numbers.get(i), numbers.get(i + 1));
++            if (numbers.size() - i >= 2) {
++                rlineTo(numbers.get(i), numbers.get(i + 1));
++            }
+         }
+     }
+@@ -415,13 +482,15 @@
+         {
+             for (int i = 0;i < numbers.size();i += 6)
+             {
+-                float x1 = numbers.get(i);
+-                float y1 = numbers.get(i + 1);
+-                float x2 = numbers.get(i + 2);
+-                float y2 = numbers.get(i + 3);
+-                float x3 = numbers.get(i + 4);
+-                float y3 = numbers.get(i + 5);
+-                rrcurveTo(x1, y1, x2, y2, x3, y3);
++                if (numbers.size() - i >= 6) {
++                    float x1 = numbers.get(i);
++                    float y1 = numbers.get(i + 1);
++                    float x2 = numbers.get(i + 2);
++                    float y2 = numbers.get(i + 3);
++                    float x3 = numbers.get(i + 4);
++                    float y3 = numbers.get(i + 5);
++                    rrcurveTo(x1, y1, x2, y2, x3, y3);
++                }
+             }
+         }
+     }
+@@ -429,14 +498,42 @@
+     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 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);
++        Point2D p0 = path.getCurrentPoint();
++        if (p0 != null) {
++            float x1 = (float) p0.getX() + dx1.floatValue();
++            float y1 = (float) p0.getY() + dy1.floatValue();
++            float x2 = x1 + dx2.floatValue();
++            float y2 = y1 + dy2.floatValue();
++            float x3 = x2 + dx3.floatValue();
++            float y3 = y2 + dy3.floatValue( );
++
++            Point p1 = new Point((int)x1, (int)y1);
++            Point p2 = new Point((int)x2, (int)y2);
++            Point p3 = new Point((int)x3, (int)y3);
++
++            updateBBox((int)p0.getX(), (int)p0.getY());
++            updateBBox((int)p3.getX(), (int)p3.getY());
++
++            int[] abc = calculateABC((int)p0.getX(), p1.x, p2.x, p3.x);
++            double[] txs = getT(abc);
++            for (double tx : txs) {
++                if (tx > 0 && tx < 1) {
++                    int[] XandY = getXandY(tx, new Point((int)p0.getX(), (int)p0.getY()), p1, p2, p3);
++                    updateBBox(XandY[0], XandY[1]);
++                }
++            }
++
++            abc = calculateABC((int)p0.getY(), p1.y, p2.y, p3.y);
++            double[] tys = getT(abc);
++            for (double ty : tys) {
++                if (ty > 0 && ty < 1) {
++                    int[] XandY = getXandY(ty, new Point((int)p0.getX(), (int)p0.getY()), p1, p2, p3);
++                    updateBBox(XandY[0], XandY[1]);
++                }
++            }
++
++            path.curveTo(x1, y1, x2, y2, x3, y3);
++        }
+     }
+@@ -646,7 +743,9 @@
+     private void closePath()
+     {
+         referencePoint = path.getCurrentPoint();
+-        path.closePath();
++        if (referencePoint != null) {
++            path.closePath();
++        }
+     }
+     private void pointSb(Number x, Number y)
+@@ -658,11 +757,15 @@
+      * Returns the bounds of the renderer path.
+      * @return the bounds as Rectangle2D
+      */
+-     public Rectangle2D getBounds()
++     public int[] getBounds()
+     {
+-         return path.getBounds2D();
++         return bbox;
+     }
++     public Rectangle2D getBounds2D() {
++         return path.getBounds2D();
++     }
++
+      /**
+       * Returns the width of the current command.
+       * @return the width
+@@ -676,4 +779,61 @@
+      {
+          this.width = aWidth;
+      }
+-}
+\ No newline at end of file
++
++     private int[] calculateABC(int p0, int p1, int p2, int p3) {
++         int[] abc = new int[3];
++         abc[0] = p0 - 3 * p1 + 3 * p2 - p3;
++         abc[1] = 2 * (-p0 + 2 * p1 - p2);
++         abc[2] = p0 - p1;
++         return abc;
++     }
++
++     private double[] getT(int[] abc) {
++         double[] t = {-1, -1};
++         int a = abc[0];
++         int b = abc[1];
++         int c = abc[2];
++         double s = Math.pow(b, 2) - 4 * a * c;
++         if (a == 0) {
++             if (b != 0) {
++                 t[0] = -c / b;
++             }
++             return t;
++         } else if (s > 0) {
++             t[0] = (-b + Math.sqrt(s)) / 2 / a;
++             t[1] = (-b - Math.sqrt(s)) / 2 / a;
++             return t;
++         } else if (s == 0) {
++             t[0] = -b / 2 / a;
++             return t;
++         } else {
++             return t;
++         }
++     }
++
++     private int[] getXandY(double t, Point p0, Point p1, Point p2, Point p3) {
++         int[] XandY = new int[2];
++         double p0Coeff = Math.pow(1 - t, 3);
++         double p1Coeff = 3 * t * Math.pow(1 - t, 2);
++         double p2Coeff = 3 *  Math.pow(t, 2) * (1 - t);
++         double p3Coeff = Math.pow(t, 3);
++         double x = p0Coeff * p0.x + p1Coeff * p1.x + p2Coeff * p2.x + p3Coeff * p3.x;
++         double y = p0Coeff * p0.y + p1Coeff * p1.y + p2Coeff * p2.y + p3Coeff * p3.y;
++         XandY[0] = (int)x;
++         XandY[1] = (int)y;
++         return XandY;
++     }
++
++     private void updateBBox(int x, int y) {
++         if (x < bbox[0]) {
++             bbox[0] = x;
++         } else if (x > bbox[2]) {
++             bbox[2] = x;
++         }
++         if (y < bbox[1]) {
++             bbox[1] = y;
++         } else if (y > bbox[3]) {
++             bbox[3] = y;
++         }
++     }
++}
diff --git a/lib/pdfbox-1646.patch b/lib/pdfbox-1646.patch
new file mode 100644 (file)
index 0000000..b076ce2
--- /dev/null
@@ -0,0 +1,738 @@
+Index: fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java
+===================================================================
+--- fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java        (revision 1546564)
++++ fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java        (working copy)
+@@ -36,7 +36,7 @@
+ import org.apache.fontbox.cff.encoding.CFFStandardEncoding;
+ /**
+- * This class represents a parser for a CFF font. 
++ * This class represents a parser for a CFF font.
+  * @author Villu Ruusmann
+  * @version $Revision: 1.0 $
+  */
+@@ -107,7 +107,11 @@
+         {
+             input.setPosition(0);
+         }
++      return parse(input);
++    }
++    public List<CFFFont> parse(CFFDataInput input) throws IOException {
++        this.input = input;
+         header = readHeader(input);
+         nameIndex = readIndexData(input);
+         topDictIndex = readIndexData(input);
+@@ -119,6 +123,7 @@
+         {
+             CFFFont font = parseFont(i);
+             font.setGlobalSubrIndex(globalSubrIndex);
++            font.constructMappings();
+             fonts.add(font);
+         }
+         return fonts;
+@@ -145,7 +150,7 @@
+         return cffHeader;
+     }
+-    private static IndexData readIndexData(CFFDataInput input) throws IOException
++    public static IndexData readIndexData(CFFDataInput input) throws IOException
+     {
+         int count = input.readCard16();
+         IndexData index = new IndexData(count);
+@@ -179,7 +184,8 @@
+         return dict;
+     }
+-    private static DictData.Entry readEntry(CFFDataInput input) throws IOException
++    private static DictData.Entry readEntry(CFFDataInput input)
++            throws IOException
+     {
+         DictData.Entry entry = new DictData.Entry();
+         while (true)
+@@ -211,13 +217,15 @@
+         return entry;
+     }
+-    private static CFFOperator readOperator(CFFDataInput input, int b0) throws IOException
++    private static CFFOperator readOperator(CFFDataInput input, int b0)
++            throws IOException
+     {
+         CFFOperator.Key key = readOperatorKey(input, b0);
+         return CFFOperator.getOperator(key);
+     }
+-    private static CFFOperator.Key readOperatorKey(CFFDataInput input, int b0) throws IOException
++    private static CFFOperator.Key readOperatorKey(CFFDataInput input, int b0)
++            throws IOException
+     {
+         if (b0 == 12)
+         {
+@@ -227,7 +235,8 @@
+         return new CFFOperator.Key(b0);
+     }
+-    private static Integer readIntegerNumber(CFFDataInput input, int b0) throws IOException
++    private static Integer readIntegerNumber(CFFDataInput input, int b0)
++            throws IOException
+     {
+         if (b0 == 28)
+         {
+@@ -263,7 +272,8 @@
+         }
+     }
+-    private static Double readRealNumber(CFFDataInput input, int b0) throws IOException
++    private static Double readRealNumber(CFFDataInput input, int b0)
++            throws IOException
+     {
+         StringBuffer sb = new StringBuffer();
+         boolean done = false;
+@@ -446,9 +456,9 @@
+                 throw new IOException("FDArray is missing for a CIDKeyed Font.");
+             }
+-            int fontDictOffset = fdArrayEntry.getNumber(0).intValue();
+-            input.setPosition(fontDictOffset);
+-            IndexData fdIndex = readIndexData(input);
++              int fontDictOffset = fdArrayEntry.getNumber(0).intValue();
++              input.setPosition(fontDictOffset);
++              IndexData fdIndex = readIndexData(input);
+             List<Map<String, Object>> privateDictionaries = new LinkedList<Map<String, Object>>();
+             List<Map<String, Object>> fontDictionaries = new LinkedList<Map<String, Object>>();
+@@ -577,8 +587,8 @@
+         {
+             return CFFStandardString.getName(index);
+         }
+-        if (index - 391 <= stringIndex.getCount())
+-        {
++        if (index - 391 < stringIndex.getCount()) 
++              {
+             DataInput dataInput = new DataInput(stringIndex.getBytes(index - 391));
+             return dataInput.getString();
+         }
+@@ -620,7 +630,8 @@
+         return entry != null ? entry.getArray() : defaultValue;
+     }
+-    private CFFEncoding readEncoding(CFFDataInput dataInput, int[] gids) throws IOException
++    private CFFEncoding readEncoding(CFFDataInput dataInput, int[] gids)
++            throws IOException
+     {
+         int format = dataInput.readCard8();
+         int baseFormat = format & 0x7f;
+@@ -639,7 +650,8 @@
+         }
+     }
+-    private Format0Encoding readFormat0Encoding(CFFDataInput dataInput, int format, int[] gids) throws IOException
++    private Format0Encoding readFormat0Encoding(CFFDataInput dataInput, int format,
++            int[] gids) throws IOException
+     {
+         Format0Encoding encoding = new Format0Encoding();
+         encoding.format = format;
+@@ -657,7 +669,8 @@
+         return encoding;
+     }
+-    private Format1Encoding readFormat1Encoding(CFFDataInput dataInput, int format, int[] gids) throws IOException
++    private Format1Encoding readFormat1Encoding(CFFDataInput dataInput, int format,
++            int[] gids) throws IOException
+     {
+         Format1Encoding encoding = new Format1Encoding();
+         encoding.format = format;
+@@ -683,7 +696,8 @@
+         return encoding;
+     }
+-    private void readSupplement(CFFDataInput dataInput, EmbeddedEncoding encoding) throws IOException
++    private void readSupplement(CFFDataInput dataInput, EmbeddedEncoding encoding)
++            throws IOException
+     {
+         encoding.nSups = dataInput.readCard8();
+         encoding.supplement = new EmbeddedEncoding.Supplement[encoding.nSups];
+@@ -738,15 +752,14 @@
+         fdselect.fds = new int[nGlyphs];
+         for (int i = 0; i < fdselect.fds.length; i++)
+         {
+-            fdselect.fds[i] = dataInput.readCard8();
+-
++              fdselect.fds[i] = dataInput.readCard8();
+         }
+         return fdselect;
+     }
+     /**
+      * Read the Format 3 of the FDSelect data structure.
+-     * 
++     *
+      * @param dataInput
+      * @param format
+      * @param nGlyphs
+@@ -768,7 +781,6 @@
+             r3.first = dataInput.readCard16();
+             r3.fd = dataInput.readCard8();
+             fdselect.range3[i] = r3;
+-
+         }
+         fdselect.sentinel = dataInput.readCard16();
+@@ -902,7 +914,8 @@
+         }
+     }
+-    private CFFCharset readCharset(CFFDataInput dataInput, int nGlyphs) throws IOException
++    private CFFCharset readCharset(CFFDataInput dataInput, int nGlyphs)
++            throws IOException
+     {
+         int format = dataInput.readCard8();
+         if (format == 0)
+@@ -923,7 +936,8 @@
+         }
+     }
+-    private Format0Charset readFormat0Charset(CFFDataInput dataInput, int format, int nGlyphs) throws IOException
++    private Format0Charset readFormat0Charset(CFFDataInput dataInput, int format,
++            int nGlyphs) throws IOException
+     {
+         Format0Charset charset = new Format0Charset();
+         charset.format = format;
+@@ -936,7 +950,8 @@
+         return charset;
+     }
+-    private Format1Charset readFormat1Charset(CFFDataInput dataInput, int format, int nGlyphs) throws IOException
++    private Format1Charset readFormat1Charset(CFFDataInput dataInput, int format,
++            int nGlyphs) throws IOException
+     {
+         Format1Charset charset = new Format1Charset();
+         charset.format = format;
+@@ -957,7 +972,8 @@
+         return charset;
+     }
+-    private Format2Charset readFormat2Charset(CFFDataInput dataInput, int format, int nGlyphs) throws IOException
++    private Format2Charset readFormat2Charset(CFFDataInput dataInput, int format,
++            int nGlyphs) throws IOException
+     {
+         Format2Charset charset = new Format2Charset();
+         charset.format = format;
+@@ -981,7 +997,7 @@
+     }
+     /**
+-     * Inner class holding the header of a CFF font. 
++     * Inner class holding the header of a CFF font.
+      */
+     private static class Header
+     {
+@@ -999,7 +1015,7 @@
+     }
+     /**
+-     * Inner class holding the DictData of a CFF font. 
++     * Inner class holding the DictData of a CFF font.
+      */
+     private static class DictData
+     {
+@@ -1030,7 +1046,7 @@
+         }
+         /**
+-         * {@inheritDoc} 
++         * {@inheritDoc}
+          */
+         public String toString()
+         {
+@@ -1038,7 +1054,7 @@
+         }
+         /**
+-         * Inner class holding an operand of a CFF font. 
++         * Inner class holding an operand of a CFF font.
+          */
+         private static class Entry
+         {
+@@ -1100,7 +1116,7 @@
+     }
+     /**
+-     * Inner class representing an embedded CFF encoding. 
++     * Inner class representing an embedded CFF encoding.
+      */
+     abstract static class EmbeddedEncoding extends CFFEncoding
+     {
+@@ -1124,7 +1140,7 @@
+         }
+         /**
+-         * Inner class representing a supplement for an encoding. 
++         * Inner class representing a supplement for an encoding.
+          */
+         static class Supplement
+         {
+@@ -1150,7 +1166,7 @@
+     }
+     /**
+-     * Inner class representing a Format0 encoding. 
++     * Inner class representing a Format0 encoding.
+      */
+     private static class Format0Encoding extends EmbeddedEncoding
+     {
+@@ -1167,7 +1183,7 @@
+     }
+     /**
+-     * Inner class representing a Format1 encoding. 
++     * Inner class representing a Format1 encoding.
+      */
+     private static class Format1Encoding extends EmbeddedEncoding
+     {
+@@ -1183,7 +1199,7 @@
+         }
+         /**
+-         * Inner class representing a range of an encoding. 
++         * Inner class representing a range of an encoding.
+          */
+         private static class Range1
+         {
+@@ -1193,13 +1209,20 @@
+             @Override
+             public String toString()
+             {
+-                return getClass().getName() + "[first=" + first + ", nLeft=" + nLeft + "]";
++                return getClass().getName() + "[first=" + first + ", nLeft="
++                        + nLeft + "]";
+             }
++
++            @Override
++            public boolean equals(Object obj) {
++                Range1 r = (Range1)obj;
++                return (first == r.first && nLeft == r.nLeft);
++            }
+         }
+     }
+     /**
+-     * Inner class representing an embedded CFF charset. 
++     * Inner class representing an embedded CFF charset.
+      */
+     abstract static class EmbeddedCharset extends CFFCharset
+     {
+@@ -1211,7 +1234,7 @@
+     }
+     /**
+-     * Inner class representing a Format0 charset. 
++     * Inner class representing a Format0 charset.
+      */
+     private static class Format0Charset extends EmbeddedCharset
+     {
+@@ -1226,7 +1249,7 @@
+     }
+     /**
+-     * Inner class representing a Format1 charset. 
++     * Inner class representing a Format1 charset.
+      */
+     private static class Format1Charset extends EmbeddedCharset
+     {
+@@ -1240,7 +1263,7 @@
+         }
+         /**
+-         * Inner class representing a range of a charset. 
++         * Inner class representing a range of a charset.
+          */
+         private static class Range1
+         {
+@@ -1256,7 +1279,7 @@
+     }
+     /**
+-     * Inner class representing a Format2 charset. 
++     * Inner class representing a Format2 charset.
+      */
+     private static class Format2Charset extends EmbeddedCharset
+     {
+@@ -1270,7 +1293,7 @@
+         }
+         /**
+-         * Inner class representing a range of a charset. 
++         * Inner class representing a range of a charset.
+          */
+         private static class Range2
+         {
+@@ -1284,4 +1307,8 @@
+             }
+         }
+     }
++
++    public IndexData getStringIndex() {
++        return stringIndex;
++    }
+ }
+Index: fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java
+===================================================================
+--- fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java  (revision 1546564)
++++ fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java  (working copy)
+@@ -31,7 +31,7 @@
+ /**
+  * This class represents a CFF/Type2 Font.
+- * 
++ *
+  * @author Villu Ruusmann
+  * @version $Revision$
+  */
+@@ -44,6 +44,8 @@
+       private CFFEncoding fontEncoding = null;
+       private CFFCharset fontCharset = null;
+       private Map<String, byte[]> charStringsDict = new LinkedHashMap<String, byte[]>();
++    Map<Integer, Mapping> sidMappings = null;
++    ArrayList<Mapping> gidMappings = null;
+       private IndexData globalSubrIndex = null;
+       private IndexData localSubrIndex = null;
+@@ -97,6 +99,7 @@
+                       topDict.put(name, value);
+               }
+       }
++
+       /** 
+        * Returns the top dictionary.
+        * @return the dictionary
+@@ -107,7 +110,7 @@
+       }
+       /**
+-       * Adds the given key/value pair to the private dictionary. 
++       * Adds the given key/value pair to the private dictionary.
+        * @param name the given key
+        * @param value the given value
+        */
+@@ -118,7 +121,8 @@
+                       privateDict.put(name, value);
+               }
+       }
+-      /** 
++
++      /**
+        * Returns the private dictionary.
+        * @return the dictionary
+        */
+@@ -127,14 +131,60 @@
+               return privateDict;
+       }
++    /**
++     * Returns a mapping for a given GID
++     * @param GID The given GID
++     * @return The found mapping
++     */
++    public Mapping getMapping(int GID) {
++        return sidMappings.get(GID);
++    }
++
+       /**
+-       * Get the mapping (code/SID/charname/bytes) for this font.
+-       * @return mappings for codes < 256 and for codes > = 256
+-       */
+-      public Collection<Mapping> getMappings()
++     * Get the mapping (code/SID/charname/bytes) for this font.
++     * @return mappings for codes < 256 and for codes > = 256
++     */
++      public Collection<Mapping> getMappings() {
++        constructMappings();
++          return sidMappings.values();
++      }
++
++    /**
++     * Gets the GID mappings list.
++     */
++      public ArrayList<Mapping> getGIDMappings() {
++          return gidMappings;
++      }
++
++      private void constructGIDMap() {
++          gidMappings = new ArrayList<Mapping>();
++          Mapping notdef = new Mapping();
++          notdef.setName(".notdef");
++          gidMappings.add(notdef);
++        for (CFFCharset.Entry entry : fontCharset.getEntries())
++        {
++            String name = entry.getName();
++            byte[] bytes = this.charStringsDict.get(name);
++            if (bytes == null)
++            {
++                continue;
++            }
++            Mapping mapping = new Mapping();
++            mapping.setSID(entry.getSID());
++            mapping.setName(name);
++            mapping.setBytes(bytes);
++            gidMappings.add(mapping);
++        }
++      }
++
++    /**
++     * Construct the mappings.
++     */
++      public void constructMappings()
+       {
+-              List<Mapping> mappings = new ArrayList<Mapping>();
+-              Set<String> mappedNames = new HashSet<String>();
++          constructGIDMap();
++          sidMappings = new LinkedHashMap<Integer, Mapping>();
++          Set<String> mappedNames = new HashSet<String>();
+               for (CFFEncoding.Entry entry : fontEncoding.getEntries())
+               {
+                       String charName = fontCharset.getName(entry.getSID());
+@@ -153,7 +203,7 @@
+                       mapping.setSID(entry.getSID());
+                       mapping.setName(charName);
+                       mapping.setBytes(bytes);
+-                      mappings.add(mapping);
++                      sidMappings.put(mapping.getSID(), mapping);
+                       mappedNames.add(charName);
+               }
+               if (fontEncoding instanceof CFFParser.EmbeddedEncoding)
+@@ -177,7 +227,7 @@
+                               mapping.setSID(supplement.getGlyph());
+                               mapping.setName(charName);
+                               mapping.setBytes(bytes);
+-                              mappings.add(mapping);
++                              sidMappings.put(mapping.getSID(), mapping);
+                               mappedNames.add(charName);
+                       }
+               }
+@@ -185,7 +235,7 @@
+               int code = 256;
+               for (CFFCharset.Entry entry : fontCharset.getEntries())
+               {
+-                      String name = entry.getName();
++                  String name = entry.getName();
+                       if (mappedNames.contains(name))
+                       {
+                               continue;
+@@ -201,11 +251,10 @@
+                       mapping.setName(name);
+                       mapping.setBytes(bytes);
+-                      mappings.add(mapping);
++                      sidMappings.put(mapping.getSID(), mapping);
+                       mappedNames.add(name);
+               }
+-              return mappings;
+       }
+       /**
+@@ -215,34 +264,43 @@
+        * @return -1 if the SID is missing from the Font.
+        * @throws IOException
+        */
+-      public int getWidth(int SID) throws IOException {
+-              int nominalWidth = privateDict.containsKey("nominalWidthX") ? ((Number)privateDict.get("nominalWidthX")).intValue() : 0;
+-              int defaultWidth = privateDict.containsKey("defaultWidthX") ? ((Number)privateDict.get("defaultWidthX")).intValue() : 1000 ;
+-              
+-              for (Mapping m : getMappings() ){
+-                      if (m.getSID() == SID) {
++    public int getWidth(int SID) throws IOException {
++        int nominalWidth = privateDict.containsKey("nominalWidthX") ? ((Number) privateDict.get("nominalWidthX")).intValue() : 0;
++        int defaultWidth = privateDict.containsKey("defaultWidthX") ? ((Number) privateDict.get("defaultWidthX")).intValue() : 1000;
++        Mapping m = sidMappings.get(SID);
++        if (m != null) {
++            CharStringRenderer csr = getRendererForMapping(m);
++            // ---- If the CharString has a Width nominalWidthX must be added,
++            // otherwise it is the default width.
++            return csr.getWidth() != 0 ? csr.getWidth() + nominalWidth : defaultWidth;
++        }
+-                              CharStringRenderer csr = null;
+-                              if (((Number)getProperty("CharstringType")).intValue() == 2 ) {
+-                                      List<Object> lSeq = m.toType2Sequence();
+-                                      csr = new CharStringRenderer(false);
+-                                      csr.render(lSeq);
+-                              } else {
+-                                      List<Object> lSeq = m.toType1Sequence();
+-                                      csr = new CharStringRenderer();
+-                                      csr.render(lSeq);
+-                              }
++        // ---- SID Width not found, return the nodef width
++        return getNotDefWidth(defaultWidth, nominalWidth);
++    }
+-                              // ---- If the CharString has a Width nominalWidthX must be added, 
+-                              //          otherwise it is the default width.
+-                              return csr.getWidth() != 0 ? csr.getWidth() + nominalWidth : defaultWidth;
+-                      }
+-              }
++    private CharStringRenderer getRendererForMapping(Mapping m) throws IOException {
++        CharStringRenderer csr = null;
++        if (((Number) getProperty("CharstringType")).intValue() == 2) {
++            List<Object> lSeq = m.toType2Sequence();
++            csr = new CharStringRenderer(false);
++            csr.render(lSeq);
++        } else {
++            List<Object> lSeq = m.toType1Sequence();
++            csr = new CharStringRenderer();
++            csr.render(lSeq);
++        }
++        return csr;
++    }
+-              // ---- SID Width not found, return the nodef width
+-              return getNotDefWidth(defaultWidth, nominalWidth);
+-      }
+-      
++    /**
++     * Returns the witdth of the .notdef character.
++     * 
++     * @param defaultWidth default width
++     * @param nominalWidth nominal width
++     * @return the calculated width for the .notdef character
++     * @throws IOException if something went wrong
++     */
+       protected int getNotDefWidth(int defaultWidth, int nominalWidth) throws IOException {
+               CharStringRenderer csr;
+               byte[] glyphDesc = this.getCharStringsDict().get(".notdef");
+@@ -260,6 +318,36 @@
+               return csr.getWidth() != 0 ? csr.getWidth() + nominalWidth : defaultWidth;
+       }
+       
++    /**
++     * Return the Width value of the given Glyph identifier
++     *
++     * @param SID
++     * @return -1 if the SID is missing from the Font.
++     * @throws IOException
++     */
++    public int[] getBoundingBox(int SID) throws IOException {
++        Mapping m = sidMappings.get(SID);
++        if (m != null) {
++            CharStringRenderer csr = getRendererForMapping(m);
++            return csr.getBounds();
++        }
++        // ---- SID Width not found, return the nodef width
++        return new int[4];
++    }
++
++    /**
++     * Gets the name of a character from the given SID
++     * @param SID The given SID
++     * @return The name of the found character
++     */
++    public String getNameOfCharFromCode(int SID) {
++        if (sidMappings.get(SID) != null) {
++            return sidMappings.get(SID).getName();
++        } else {
++            return "";
++        }
++    }
++
+       /**
+        * Returns the CFFEncoding of the font.
+        * @return the encoding
+@@ -336,50 +424,51 @@
+                               + charStringsDict + "]";
+       }
++    /**
++     * Sets the global subroutine index data.
++     * @param globalSubrIndex the IndexData object containing the global subroutines
++     */
++    public void setGlobalSubrIndex(IndexData globalSubrIndexValue) {
++        globalSubrIndex = globalSubrIndexValue;
++    }
+-      /**
+-       * Sets the global subroutine index data.
+-       * @param globalSubrIndex the IndexData object containing the global subroutines 
+-       */
+-      public void setGlobalSubrIndex(IndexData globalSubrIndex) {
+-              this.globalSubrIndex = globalSubrIndex;
+-      }
++    /**
++     * Returns the global subroutine index data.
++     * @return the dictionary
++     */
++    public IndexData getGlobalSubrIndex()
++    {
++        return globalSubrIndex;
++    }
+-      /** 
+-       * Returns the global subroutine index data.
+-       * @return the dictionary
+-       */
+-      public IndexData getGlobalSubrIndex() {
+-              return globalSubrIndex;
+-      }
++    /**
++     * Returns the local subroutine index data.
++     * @return the dictionary
++     */
++    public IndexData getLocalSubrIndex()
++    {
++        return localSubrIndex;
++    }
+-      /** 
+-       * Returns the local subroutine index data.
+-       * @return the dictionary
+-       */
+-      public IndexData getLocalSubrIndex() {
+-              return localSubrIndex;
+-      }
++    /**
++     * Sets the local subroutine index data.
++     * @param localSubrIndexValue the IndexData object containing the local subroutines
++     */
++    public void setLocalSubrIndex(IndexData localSubrIndexValue) {
++        localSubrIndex = localSubrIndexValue;
++    }
+-      /**
+-       * Sets the local subroutine index data.
+-       * @param localSubrIndex the IndexData object containing the local subroutines 
+-       */
+-      public void setLocalSubrIndex(IndexData localSubrIndex) {
+-              this.localSubrIndex = localSubrIndex;   
+-      }
++    /**
++     * This class is used for the font mapping.
++     * 
++     */
++    public class Mapping
++    {
++        private int mappedCode;
++        private int mappedSID;
++        private String mappedName;
++        private byte[] mappedBytes;
+-      /**
+-       * This class is used for the font mapping.
+-       *
+-       */
+-      public class Mapping
+-      {
+-              private int mappedCode;
+-              private int mappedSID;
+-              private String mappedName;
+-              private byte[] mappedBytes;
+-
+               /**
+                * Converts the mapping into a Type1-sequence.
+                * @return the Type1-sequence
+@@ -458,4 +547,4 @@
+                       this.mappedBytes = bytes;
+               }
+       }
+-}
+\ No newline at end of file
++}