diff options
author | Luis Bernardo <lbernardo@apache.org> | 2013-12-03 10:51:24 +0000 |
---|---|---|
committer | Luis Bernardo <lbernardo@apache.org> | 2013-12-03 10:51:24 +0000 |
commit | 9a7c9f11ff9ed5bad9f100b2eb6fa140bcd04e03 (patch) | |
tree | 02f934fce52b41c68d29e173cbea5464d1a04eb7 /lib | |
parent | 9b1bf2de4a098a494142c27f0dc3f4d2b8327f80 (diff) | |
download | xmlgraphics-fop-9a7c9f11ff9ed5bad9f100b2eb6fa140bcd04e03.tar.gz xmlgraphics-fop-9a7c9f11ff9ed5bad9f100b2eb6fa140bcd04e03.zip |
replaced fontbox snapshot jar by a patched released jar (patch files added to lib)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1547340 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'lib')
-rw-r--r-- | lib/fontbox-1.8.3-patched.jar (renamed from lib/fontbox-1.8.0-SNAPSHOT.jar) | bin | 207498 -> 208340 bytes | |||
-rw-r--r-- | lib/pdfbox-1645.patch | 395 | ||||
-rw-r--r-- | lib/pdfbox-1646.patch | 738 |
3 files changed, 1133 insertions, 0 deletions
diff --git a/lib/fontbox-1.8.0-SNAPSHOT.jar b/lib/fontbox-1.8.3-patched.jar Binary files differindex e20e1ad7b..57460be06 100644 --- a/lib/fontbox-1.8.0-SNAPSHOT.jar +++ b/lib/fontbox-1.8.3-patched.jar diff --git a/lib/pdfbox-1645.patch b/lib/pdfbox-1645.patch new file mode 100644 index 000000000..f9dda73fb --- /dev/null +++ b/lib/pdfbox-1645.patch @@ -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 index 000000000..b076ce224 --- /dev/null +++ b/lib/pdfbox-1646.patch @@ -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 ++} |