diff options
author | Jeremias Maerki <jeremias@apache.org> | 2011-07-02 10:18:35 +0000 |
---|---|---|
committer | Jeremias Maerki <jeremias@apache.org> | 2011-07-02 10:18:35 +0000 |
commit | fa9fc6d171686e319bf56a844c78a8c2f5afe723 (patch) | |
tree | a864a15824fb7c6ab8494530b48972f6b5f4f84c /src/java | |
parent | 20dd19ff66999b69b40a3138d562287927deff66 (diff) | |
download | xmlgraphics-fop-fa9fc6d171686e319bf56a844c78a8c2f5afe723.tar.gz xmlgraphics-fop-fa9fc6d171686e319bf56a844c78a8c2f5afe723.zip |
Bugfix: AFMFile sometimes indirectly caused wrong assignments of char widths to code points in a single-byte encoding due to mapping multiple characters to the same code points (see overridePrimaryEncoding).
Fixed some FindBugs issues.
Added some generics.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1142189 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java')
-rw-r--r-- | src/java/org/apache/fop/fonts/type1/AFMFile.java | 100 |
1 files changed, 64 insertions, 36 deletions
diff --git a/src/java/org/apache/fop/fonts/type1/AFMFile.java b/src/java/org/apache/fop/fonts/type1/AFMFile.java index 427a87691..f6bc3b163 100644 --- a/src/java/org/apache/fop/fonts/type1/AFMFile.java +++ b/src/java/org/apache/fop/fonts/type1/AFMFile.java @@ -22,10 +22,12 @@ package org.apache.fop.fonts.type1; import java.awt.geom.Dimension2D; import java.awt.geom.RectangularShape; import java.util.Collections; -import java.util.Iterator; import java.util.List; import java.util.Map; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import org.apache.xmlgraphics.java2d.Dimension2DDouble; import org.apache.fop.fonts.NamedCharacter; @@ -36,6 +38,9 @@ import org.apache.fop.fonts.SingleByteEncoding; */ public class AFMFile { + /** logging instance */ + private static final Log LOG = LogFactory.getLog(AFMFile.class); + private String fontName; private String fullName; private String familyName; @@ -56,15 +61,13 @@ public class AFMFile { private AFMWritingDirectionMetrics[] writingDirectionMetrics = new AFMWritingDirectionMetrics[3]; - private List charMetrics = new java.util.ArrayList(); - //List<AFMCharMetrics> - private Map charNameToMetrics = new java.util.HashMap(); - //Map<String, AFMCharMetrics> + private List<AFMCharMetrics> charMetrics = new java.util.ArrayList<AFMCharMetrics>(); + private Map<String, AFMCharMetrics> charNameToMetrics + = new java.util.HashMap<String, AFMCharMetrics>(); private int firstChar = -1; private int lastChar = -1; - private Map kerningMap; - //Map<String, Map<String, Dimension2D>> + private Map<String, Map<String, Dimension2D>> kerningMap; /** * Default constructor. @@ -365,14 +368,14 @@ public class AFMFile { * @return the character metrics or null if there's no such character */ public AFMCharMetrics getChar(String name) { - return (AFMCharMetrics)this.charNameToMetrics.get(name); + return this.charNameToMetrics.get(name); } /** * Returns the list of AFMCharMetrics instances representing all the available characters. * @return a List of AFMCharMetrics instances */ - public List getCharMetrics() { + public List<AFMCharMetrics> getCharMetrics() { return Collections.unmodifiableList(this.charMetrics); } @@ -384,11 +387,11 @@ public class AFMFile { */ public void addXKerning(String name1, String name2, double kx) { if (this.kerningMap == null) { - this.kerningMap = new java.util.HashMap(); + this.kerningMap = new java.util.HashMap<String, Map<String, Dimension2D>>(); } - Map entries = (Map)this.kerningMap.get(name1); + Map<String, Dimension2D> entries = this.kerningMap.get(name1); if (entries == null) { - entries = new java.util.HashMap(); + entries = new java.util.HashMap<String, Dimension2D>(); this.kerningMap.put(name1, entries); } entries.put(name2, new Dimension2DDouble(kx, 0)); @@ -406,40 +409,37 @@ public class AFMFile { * Creates and returns a kerning map for writing mode 0 (ltr) with character codes. * @return the kerning map or null if there is no kerning information. */ - public Map createXKerningMapEncoded() { + public Map<Integer, Map<Integer, Integer>> createXKerningMapEncoded() { if (!hasKerning()) { return null; } - Map m = new java.util.HashMap(); - Iterator iterFrom = this.kerningMap.entrySet().iterator(); - while (iterFrom.hasNext()) { - Map.Entry entryFrom = (Map.Entry)iterFrom.next(); - String name1 = (String)entryFrom.getKey(); + Map<Integer, Map<Integer, Integer>> m + = new java.util.HashMap<Integer, Map<Integer, Integer>>(); + for (Map.Entry<String, Map<String, Dimension2D>> entryFrom : this.kerningMap.entrySet()) { + String name1 = entryFrom.getKey(); AFMCharMetrics chm1 = getChar(name1); if (chm1 == null || !chm1.hasCharCode()) { continue; } - Map container = null; - Map entriesTo = (Map)entryFrom.getValue(); - Iterator iterTo = entriesTo.entrySet().iterator(); - while (iterTo.hasNext()) { - Map.Entry entryTo = (Map.Entry)iterTo.next(); - String name2 = (String)entryTo.getKey(); + Map<Integer, Integer> container = null; + Map<String, Dimension2D> entriesTo = entryFrom.getValue(); + for (Map.Entry<String, Dimension2D> entryTo : entriesTo.entrySet()) { + String name2 = entryTo.getKey(); AFMCharMetrics chm2 = getChar(name2); if (chm2 == null || !chm2.hasCharCode()) { continue; } if (container == null) { - Integer k1 = new Integer(chm1.getCharCode()); - container = (Map)m.get(k1); + Integer k1 = Integer.valueOf(chm1.getCharCode()); + container = m.get(k1); if (container == null) { - container = new java.util.HashMap(); + container = new java.util.HashMap<Integer, Integer>(); m.put(k1, container); } } - Dimension2D dim = (Dimension2D)entryTo.getValue(); - container.put(new Integer(chm2.getCharCode()), - new Integer((int)Math.round(dim.getWidth()))); + Dimension2D dim = entryTo.getValue(); + container.put(Integer.valueOf(chm2.getCharCode()), + Integer.valueOf((int)Math.round(dim.getWidth()))); } } return m; @@ -451,14 +451,41 @@ public class AFMFile { * @param encoding the encoding to replace the one given in the AFM */ public void overridePrimaryEncoding(SingleByteEncoding encoding) { - Iterator iter = this.charMetrics.iterator(); - while (iter.hasNext()) { - AFMCharMetrics cm = (AFMCharMetrics)iter.next(); + if (LOG.isDebugEnabled()) { + LOG.debug("Overriding primary encoding of " + getFontName() + " with: " + encoding); + } + AFMCharMetrics[] mapped = new AFMCharMetrics[256]; + for (AFMCharMetrics cm : this.charMetrics) { NamedCharacter nc = cm.getCharacter(); if (nc.hasSingleUnicodeValue()) { - int mapped = encoding.mapChar(nc.getSingleUnicodeValue()); - if (mapped > 0) { - cm.setCharCode(mapped); + int codePoint = encoding.mapChar(nc.getSingleUnicodeValue()); + if (codePoint > 0) { + if (mapped[codePoint] != null) { + if (LOG.isDebugEnabled()) { + AFMCharMetrics other = mapped[codePoint]; + String msg = "Not mapping character " + nc + " to code point " + + codePoint + " (" + Integer.toHexString(codePoint) + ") in " + + encoding + ". " + + other + " has already been assigned that code point."; + if (other.getUnicodeSequence() + .equals(nc.getUnicodeSequence())) { + msg += " This is a specialized glyph for the" + + " same Unicode character."; + //TODO should these be mapped to a private Unicode area to make + //them accessible? + } else { + msg += " This is a similar character."; + } + if (cm.getWidthX() != other.getWidthX()) { + msg += " They have differing widths: " + + cm.getWidthX() + " vs. " + other.getWidthX(); + } + LOG.debug(msg); + } + } else { + cm.setCharCode(codePoint); + mapped[codePoint] = cm; + } } else { cm.setCharCode(-1); } @@ -470,6 +497,7 @@ public class AFMFile { } /** {@inheritDoc} */ + @Override public String toString() { return "AFM: " + getFullName(); } |