You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by vh...@apache.org on 2012/06/22 20:07:09 UTC
svn commit: r1352986 [2/3] - in /xmlgraphics/fop/trunk: ./ lib/
src/documentation/content/xdocs/trunk/ src/java/org/apache/fop/afp/apps/
src/java/org/apache/fop/afp/parser/
src/java/org/apache/fop/complexscripts/fonts/
src/java/org/apache/fop/fonts/ sr...
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFFile.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFFile.java?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFFile.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFFile.java Fri Jun 22 18:07:04 2012
@@ -20,11 +20,18 @@
package org.apache.fop.fonts.truetype;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.BitSet;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -36,6 +43,7 @@ import org.apache.fop.complexscripts.fon
import org.apache.fop.complexscripts.fonts.GlyphPositioningTable;
import org.apache.fop.complexscripts.fonts.GlyphSubstitutionTable;
import org.apache.fop.complexscripts.fonts.OTFAdvancedTypographicTableReader;
+import org.apache.fop.fonts.CMapSegment;
import org.apache.fop.fonts.FontUtil;
/**
@@ -46,10 +54,100 @@ import org.apache.fop.fonts.FontUtil;
public class TTFFile {
static final byte NTABS = 24;
- static final int NMACGLYPHS = 258;
static final int MAX_CHAR_CODE = 255;
static final int ENC_BUF_SIZE = 1024;
+ private static final String[] MAC_GLYPH_ORDERING = {
+ /* 0x000 */
+ ".notdef", ".null", "nonmarkingreturn", "space",
+ "exclam", "quotedbl", "numbersign", "dollar",
+ "percent", "ampersand", "quotesingle", "parenleft",
+ "parenright", "asterisk", "plus", "comma",
+ /* 0x010 */
+ "hyphen", "period", "slash", "zero",
+ "one", "two", "three", "four",
+ "five", "six", "seven", "eight",
+ "nine", "colon", "semicolon", "less",
+ /* 0x020 */
+ "equal", "greater", "question", "at",
+ "A", "B", "C", "D",
+ "E", "F", "G", "H",
+ "I", "J", "K", "L",
+ /* 0x030 */
+ "M", "N", "O", "P",
+ "Q", "R", "S", "T",
+ "U", "V", "W", "X",
+ "Y", "Z", "bracketleft", "backslash",
+ /* 0x040 */
+ "bracketright", "asciicircum", "underscore", "grave",
+ "a", "b", "c", "d",
+ "e", "f", "g", "h",
+ "i", "j", "k", "l",
+ /* 0x050 */
+ "m", "n", "o", "p",
+ "q", "r", "s", "t",
+ "u", "v", "w", "x",
+ "y", "z", "braceleft", "bar",
+ /* 0x060 */
+ "braceright", "asciitilde", "Adieresis", "Aring",
+ "Ccedilla", "Eacute", "Ntilde", "Odieresis",
+ "Udieresis", "aacute", "agrave", "acircumflex",
+ "adieresis", "atilde", "aring", "ccedilla",
+ /* 0x070 */
+ "eacute", "egrave", "ecircumflex", "edieresis",
+ "iacute", "igrave", "icircumflex", "idieresis",
+ "ntilde", "oacute", "ograve", "ocircumflex",
+ "odieresis", "otilde", "uacute", "ugrave",
+ /* 0x080 */
+ "ucircumflex", "udieresis", "dagger", "degree",
+ "cent", "sterling", "section", "bullet",
+ "paragraph", "germandbls", "registered", "copyright",
+ "trademark", "acute", "dieresis", "notequal",
+ /* 0x090 */
+ "AE", "Oslash", "infinity", "plusminus",
+ "lessequal", "greaterequal", "yen", "mu",
+ "partialdiff", "summation", "product", "pi",
+ "integral", "ordfeminine", "ordmasculine", "Omega",
+ /* 0x0A0 */
+ "ae", "oslash", "questiondown", "exclamdown",
+ "logicalnot", "radical", "florin", "approxequal",
+ "Delta", "guillemotleft", "guillemotright", "ellipsis",
+ "nonbreakingspace", "Agrave", "Atilde", "Otilde",
+ /* 0x0B0 */
+ "OE", "oe", "endash", "emdash",
+ "quotedblleft", "quotedblright", "quoteleft", "quoteright",
+ "divide", "lozenge", "ydieresis", "Ydieresis",
+ "fraction", "currency", "guilsinglleft", "guilsinglright",
+ /* 0x0C0 */
+ "fi", "fl", "daggerdbl", "periodcentered",
+ "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
+ "Ecircumflex", "Aacute", "Edieresis", "Egrave",
+ "Iacute", "Icircumflex", "Idieresis", "Igrave",
+ /* 0x0D0 */
+ "Oacute", "Ocircumflex", "apple", "Ograve",
+ "Uacute", "Ucircumflex", "Ugrave", "dotlessi",
+ "circumflex", "tilde", "macron", "breve",
+ "dotaccent", "ring", "cedilla", "hungarumlaut",
+ /* 0x0E0 */
+ "ogonek", "caron", "Lslash", "lslash",
+ "Scaron", "scaron", "Zcaron", "zcaron",
+ "brokenbar", "Eth", "eth", "Yacute",
+ "yacute", "Thorn", "thorn", "minus",
+ /* 0x0F0 */
+ "multiply", "onesuperior", "twosuperior", "threesuperior",
+ "onehalf", "onequarter", "threequarters", "franc",
+ "Gbreve", "gbreve", "Idotaccent", "Scedilla",
+ "scedilla", "Cacute", "cacute", "Ccaron",
+ /* 0x100 */
+ "ccaron", "dcroat"
+ };
+
+ /** The FontFileReader used to read this TrueType font. */
+ protected FontFileReader fontFile;
+
+ /** Set to true to get even more debug output than with level DEBUG */
+ public static final boolean TRACE_ENABLED = false;
+
private final String encoding = "WinAnsiEncoding"; // Default encoding
private final short firstChar = 0;
@@ -61,33 +159,31 @@ public class TTFFile {
/**
* Table directory
*/
- protected Map dirTabs;
- private Map<Integer, Map<Integer, Integer>> kerningTab; // for CIDs
+ protected Map<TTFTableName, TTFDirTabEntry> dirTabs;
+ private Map<Integer, Map<Integer, Integer>> kerningTab; // for CIDs
private Map<Integer, Map<Integer, Integer>> ansiKerningTab; // For winAnsiEncoding
- private List cmaps;
- private Set unicodeMappings;
+ private List<CMapSegment> cmaps;
+ private Set<UnicodeMapping> unicodeMappings;
private int upem; // unitsPerEm from "head" table
private int nhmtx; // Number of horizontal metrics
- private int postFormat;
+ private PostScriptVersion postScriptVersion;
private int locaFormat;
/**
* Offset to last loca
*/
protected long lastLoca = 0;
private int numberOfGlyphs; // Number of glyphs in font (read from "maxp" table)
- private int nmGlyphs; // Used in fixWidths - remove?
/**
* Contains glyph data
*/
protected TTFMtxEntry[] mtxTab; // Contains glyph data
- private final int[] mtxEncoded = null;
private String postScriptName = "";
private String fullName = "";
private String notice = "";
- private final Set familyNames = new java.util.HashSet(); //Set<String>
+ private Set<String> familyNames = new HashSet<String>();
private String subFamilyName = "";
private long italicAngle = 0;
@@ -116,12 +212,12 @@ public class TTFFile {
private short lastChar = 0;
private int[] ansiWidth;
- private Map ansiIndex;
+ private Map<Integer, List<Integer>> ansiIndex;
// internal mapping of glyph indexes to unicode indexes
// used for quick mappings in this class
- private final Map glyphToUnicodeMap = new java.util.HashMap();
- private final Map unicodeToGlyphMap = new java.util.HashMap();
+ private final Map<Integer, Integer> glyphToUnicodeMap = new HashMap<Integer, Integer> ();
+ private final Map<Integer, Integer> unicodeToGlyphMap = new HashMap<Integer, Integer> ();
private TTFDirTabEntry currentDirTab;
@@ -136,6 +232,10 @@ public class TTFFile {
*/
protected Log log = LogFactory.getLog(TTFFile.class);
+ public TTFFile() {
+ this(true, false);
+ }
+
/**
* Constructor
* @param useKerning true if kerning data should be loaded
@@ -147,9 +247,9 @@ public class TTFFile {
}
/**
- * Key-value helper class
+ * Key-value helper class.
*/
- class UnicodeMapping implements Comparable {
+ final class UnicodeMapping implements Comparable {
private final int unicodeIndex;
private final int glyphIndex;
@@ -217,12 +317,26 @@ public class TTFFile {
}
/**
+ * Version of the PostScript table (<q>post</q>) contained in this font.
+ */
+ public static enum PostScriptVersion {
+ /** PostScript table version 1.0. */
+ V1,
+ /** PostScript table version 2.0. */
+ V2,
+ /** PostScript table version 3.0. */
+ V3,
+ /** Unknown version of the PostScript table. */
+ UNKNOWN;
+ }
+
+ /**
* Obtain directory table entry.
* @param name (tag) of entry
* @return a directory table entry or null if none found
*/
- public TTFDirTabEntry getDirectoryEntry ( String name ) {
- return (TTFDirTabEntry) dirTabs.get ( name );
+ public TTFDirTabEntry getDirectoryEntry(TTFTableName name) {
+ return dirTabs.get(name);
}
/**
@@ -234,11 +348,11 @@ public class TTFFile {
* @return true if seek succeeded
* @throws IOException if I/O exception occurs during seek
*/
- public boolean seekTab(FontFileReader in, String name,
+ public boolean seekTab(FontFileReader in, TTFTableName tableName,
long offset) throws IOException {
- TTFDirTabEntry dt = getDirectoryEntry ( name );
+ TTFDirTabEntry dt = dirTabs.get(tableName);
if (dt == null) {
- log.error("Dirtab " + name + " not found.");
+ log.error("Dirtab " + tableName.getName() + " not found.");
return false;
} else {
in.seekSet(dt.getOffset() + offset);
@@ -274,12 +388,12 @@ public class TTFFile {
* Set the unicodeIndex in the TTFMtxEntries and fills in the
* cmaps vector.
*/
- private boolean readCMAP(FontFileReader in) throws IOException {
+ private boolean readCMAP() throws IOException {
unicodeMappings = new java.util.TreeSet();
- seekTab(in, "cmap", 2);
- int numCMap = in.readTTFUShort(); // Number of cmap subtables
+ seekTab(fontFile, TTFTableName.CMAP, 2);
+ int numCMap = fontFile.readTTFUShort(); // Number of cmap subtables
long cmapUniOffset = 0;
long symbolMapOffset = 0;
@@ -289,9 +403,9 @@ public class TTFFile {
//Read offset for all tables. We are only interested in the unicode table
for (int i = 0; i < numCMap; i++) {
- int cmapPID = in.readTTFUShort();
- int cmapEID = in.readTTFUShort();
- long cmapOffset = in.readTTFULong();
+ int cmapPID = fontFile.readTTFUShort();
+ int cmapEID = fontFile.readTTFUShort();
+ long cmapOffset = fontFile.readTTFLong();
if (log.isDebugEnabled()) {
log.debug("Platform ID: " + cmapPID + " Encoding: " + cmapEID);
@@ -306,9 +420,9 @@ public class TTFFile {
}
if (cmapUniOffset > 0) {
- return readUnicodeCmap(in, cmapUniOffset, 1);
+ return readUnicodeCmap(cmapUniOffset, 1);
} else if (symbolMapOffset > 0) {
- return readUnicodeCmap(in, symbolMapOffset, 0);
+ return readUnicodeCmap(symbolMapOffset, 0);
} else {
log.fatal("Unsupported TrueType font: No Unicode or Symbol cmap table"
+ " not present. Aborting");
@@ -317,26 +431,26 @@ public class TTFFile {
}
private boolean readUnicodeCmap // CSOK: MethodLength
- (FontFileReader in, long cmapUniOffset, int encodingID)
+ (long cmapUniOffset, int encodingID)
throws IOException {
//Read CMAP table and correct mtxTab.index
int mtxPtr = 0;
// Read unicode cmap
- seekTab(in, "cmap", cmapUniOffset);
- int cmapFormat = in.readTTFUShort();
- /*int cmap_length =*/ in.readTTFUShort(); //skip cmap length
+ seekTab(fontFile, TTFTableName.CMAP, cmapUniOffset);
+ int cmapFormat = fontFile.readTTFUShort();
+ /*int cmap_length =*/ fontFile.readTTFUShort(); //skip cmap length
if (log.isDebugEnabled()) {
log.debug("CMAP format: " + cmapFormat);
}
if (cmapFormat == 4) {
- in.skip(2); // Skip version number
- int cmapSegCountX2 = in.readTTFUShort();
- int cmapSearchRange = in.readTTFUShort();
- int cmapEntrySelector = in.readTTFUShort();
- int cmapRangeShift = in.readTTFUShort();
+ fontFile.skip(2); // Skip version number
+ int cmapSegCountX2 = fontFile.readTTFUShort();
+ int cmapSearchRange = fontFile.readTTFUShort();
+ int cmapEntrySelector = fontFile.readTTFUShort();
+ int cmapRangeShift = fontFile.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug("segCountX2 : " + cmapSegCountX2);
@@ -352,26 +466,26 @@ public class TTFFile {
int[] cmapRangeOffsets = new int[cmapSegCountX2 / 2];
for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
- cmapEndCounts[i] = in.readTTFUShort();
+ cmapEndCounts[i] = fontFile.readTTFUShort();
}
- in.skip(2); // Skip reservedPad
+ fontFile.skip(2); // Skip reservedPad
for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
- cmapStartCounts[i] = in.readTTFUShort();
+ cmapStartCounts[i] = fontFile.readTTFUShort();
}
for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
- cmapDeltas[i] = in.readTTFShort();
+ cmapDeltas[i] = fontFile.readTTFShort();
}
//int startRangeOffset = in.getCurrentPos();
for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
- cmapRangeOffsets[i] = in.readTTFUShort();
+ cmapRangeOffsets[i] = fontFile.readTTFUShort();
}
- int glyphIdArrayOffset = in.getCurrentPos();
+ int glyphIdArrayOffset = fontFile.getCurrentPos();
BitSet eightBitGlyphs = new BitSet(256);
@@ -413,19 +527,17 @@ public class TTFFile {
+ (j - cmapStartCounts[i])
+ (i)
- cmapSegCountX2 / 2) * 2;
- in.seekSet(glyphOffset);
- glyphIdx = (in.readTTFUShort() + cmapDeltas[i])
+ fontFile.seekSet(glyphOffset);
+ glyphIdx = (fontFile.readTTFUShort() + cmapDeltas[i])
& 0xffff;
unicodeMappings.add(new UnicodeMapping(glyphIdx, j));
mtxTab[glyphIdx].getUnicodeIndex().add(new Integer(j));
// Also add winAnsiWidth
- List v = (List)ansiIndex.get(new Integer(j));
+ List<Integer> v = ansiIndex.get(new Integer(j));
if (v != null) {
- Iterator e = v.listIterator();
- while (e.hasNext()) {
- Integer aIdx = (Integer)e.next();
+ for (Integer aIdx : v) {
ansiWidth[aIdx.intValue()]
= mtxTab[glyphIdx].getWx();
@@ -466,11 +578,9 @@ public class TTFFile {
}
// Also add winAnsiWidth
- List v = (List)ansiIndex.get(new Integer(j));
+ List<Integer> v = ansiIndex.get(new Integer(j));
if (v != null) {
- Iterator e = v.listIterator();
- while (e.hasNext()) {
- Integer aIdx = (Integer)e.next();
+ for (Integer aIdx : v) {
ansiWidth[aIdx.intValue()] = mtxTab[glyphIdx].getWx();
}
}
@@ -548,14 +658,14 @@ public class TTFFile {
// Create an index hash to the ansiWidth
// Can't just index the winAnsiEncoding when inserting widths
// same char (eg bullet) is repeated more than one place
- ansiIndex = new java.util.HashMap();
+ ansiIndex = new HashMap<Integer, List<Integer>>();
for (int i = 32; i < Glyphs.WINANSI_ENCODING.length; i++) {
Integer ansi = new Integer(i);
Integer uni = new Integer(Glyphs.WINANSI_ENCODING[i]);
- List v = (List)ansiIndex.get(uni);
+ List<Integer> v = ansiIndex.get(uni);
if (v == null) {
- v = new java.util.ArrayList();
+ v = new ArrayList<Integer>();
ansiIndex.put(uni, v);
}
v.add(ansi);
@@ -574,12 +684,12 @@ public class TTFFile {
* @throws IOException In case of an I/O problem
*/
public boolean readFont(FontFileReader in, String name) throws IOException {
-
+ fontFile = in;
/*
* Check if TrueType collection, and that the name
* exists in the collection
*/
- if (!checkTTC(in, name)) {
+ if (!checkTTC(name)) {
if (name == null) {
throw new IllegalArgumentException(
"For TrueType collection you must specify which font "
@@ -590,26 +700,26 @@ public class TTFFile {
}
}
- readDirTabs(in);
- readFontHeader(in);
- getNumGlyphs(in);
+ readDirTabs();
+ readFontHeader();
+ getNumGlyphs();
if (log.isDebugEnabled()) {
log.debug("Number of glyphs in font: " + numberOfGlyphs);
}
- readHorizontalHeader(in);
- readHorizontalMetrics(in);
+ readHorizontalHeader();
+ readHorizontalMetrics();
initAnsiWidths();
- readPostScript(in);
- readOS2(in);
+ readPostScript();
+ readOS2();
determineAscDesc();
if (!isCFF) {
- readIndexToLocation(in);
- readGlyf(in);
+ readIndexToLocation();
+ readGlyf();
}
- readName(in);
- boolean pcltFound = readPCLT(in);
+ readName();
+ boolean pcltFound = readPCLT();
// Read cmap table and fill in ansiwidths
- boolean valid = readCMAP(in);
+ boolean valid = readCMAP();
if (!valid) {
return false;
}
@@ -617,7 +727,7 @@ public class TTFFile {
createCMaps();
if ( useKerning ) {
- readKerning(in);
+ readKerning();
}
// Read advanced typographic tables.
@@ -640,33 +750,47 @@ public class TTFFile {
return true;
}
+ /**
+ * Reads a font.
+ *
+ * @param in FontFileReader to read from
+ * @param name Name to be checked for in the font file
+ * @param glyphs Map of glyphs (glyphs has old index as (Integer) key and
+ * new index as (Integer) value)
+ * @throws IOException in case of an I/O problem
+ */
+ public void readFont(FontFileReader in, String name,
+ Map<Integer, Integer> glyphs) throws IOException {
+ readFont(in, name);
+ }
+
private void createCMaps() {
- cmaps = new java.util.ArrayList();
- TTFCmapEntry tce = new TTFCmapEntry();
+ cmaps = new ArrayList<CMapSegment>();
+ int unicodeStart;
+ int glyphStart;
+ int unicodeEnd;
- Iterator e = unicodeMappings.iterator();
- UnicodeMapping um = (UnicodeMapping)e.next();
+ Iterator<UnicodeMapping> e = unicodeMappings.iterator();
+ UnicodeMapping um = e.next();
UnicodeMapping lastMapping = um;
- tce.setUnicodeStart(um.getUnicodeIndex());
- tce.setGlyphStartIndex(um.getGlyphIndex());
+ unicodeStart = um.getUnicodeIndex();
+ glyphStart = um.getGlyphIndex();
while (e.hasNext()) {
- um = (UnicodeMapping)e.next();
+ um = e.next();
if (((lastMapping.getUnicodeIndex() + 1) != um.getUnicodeIndex())
|| ((lastMapping.getGlyphIndex() + 1) != um.getGlyphIndex())) {
- tce.setUnicodeEnd(lastMapping.getUnicodeIndex());
- cmaps.add(tce);
-
- tce = new TTFCmapEntry();
- tce.setUnicodeStart(um.getUnicodeIndex());
- tce.setGlyphStartIndex(um.getGlyphIndex());
+ unicodeEnd = lastMapping.getUnicodeIndex();
+ cmaps.add(new CMapSegment(unicodeStart, unicodeEnd, glyphStart));
+ unicodeStart = um.getUnicodeIndex();
+ glyphStart = um.getGlyphIndex();
}
lastMapping = um;
}
- tce.setUnicodeEnd(um.getUnicodeIndex());
- cmaps.add(tce);
+ unicodeEnd = lastMapping.getUnicodeIndex();
+ cmaps.add(new CMapSegment(unicodeStart, unicodeEnd, glyphStart));
}
/**
@@ -681,11 +805,15 @@ public class TTFFile {
}
}
+ PostScriptVersion getPostScriptVersion() {
+ return postScriptVersion;
+ }
+
/**
* Returns the font family names of the font.
* @return Set The family names (a Set of Strings)
*/
- public Set getFamilyNames() {
+ public Set<String> getFamilyNames() {
return familyNames;
}
@@ -730,19 +858,30 @@ public class TTFFile {
}
/**
+ * Returns the number of bytes necessary to pad the currentPosition so that a table begins
+ * on a 4-byte boundary.
+ * @param currentPosition the position to pad.
+ * @return int the number of bytes to pad.
+ */
+ protected int getPadSize(int currentPosition) {
+ int padSize = 4 - (currentPosition % 4);
+ return padSize < 4 ? padSize : 0;
+ }
+
+ /**
* Returns the Flags attribute of the font.
* @return int The Flags
*/
public int getFlags() {
int flags = 32; // Use Adobe Standard charset
if (italicAngle != 0) {
- flags = flags | 64;
+ flags |= 64;
}
if (isFixedPitch != 0) {
- flags = flags | 2;
+ flags |= 2;
}
if (hasSerifs) {
- flags = flags | 1;
+ flags |= 1;
}
return flags;
}
@@ -780,7 +919,6 @@ public class TTFFile {
}
/**
- * Returns the font bounding box.
* @return int[] The font bbox
*/
public int[] getFontBBox() {
@@ -886,11 +1024,10 @@ public class TTFFile {
* FontFileReader and fill the global HashMap dirTabs
* with the table name (String) as key and a TTFDirTabEntry
* as value.
- * @param in FontFileReader to read the table directory from
* @throws IOException in case of an I/O problem
*/
- protected void readDirTabs(FontFileReader in) throws IOException {
- int sfntVersion = in.readTTFLong(); // TTF_FIXED_SIZE (4 bytes)
+ protected void readDirTabs() throws IOException {
+ int sfntVersion = fontFile.readTTFLong(); // TTF_FIXED_SIZE (4 bytes)
switch (sfntVersion) {
case 0x10000:
log.debug("sfnt version: OpenType 1.0");
@@ -909,42 +1046,45 @@ public class TTFFile {
log.debug("Unknown sfnt version: " + Integer.toHexString(sfntVersion));
break;
}
- int ntabs = in.readTTFUShort();
- in.skip(6); // 3xTTF_USHORT_SIZE
+ int ntabs = fontFile.readTTFUShort();
+ fontFile.skip(6); // 3xTTF_USHORT_SIZE
- dirTabs = new java.util.HashMap();
+ dirTabs = new HashMap<TTFTableName, TTFDirTabEntry>();
TTFDirTabEntry[] pd = new TTFDirTabEntry[ntabs];
log.debug("Reading " + ntabs + " dir tables");
+
for (int i = 0; i < ntabs; i++) {
pd[i] = new TTFDirTabEntry();
- dirTabs.put(pd[i].read(in), pd[i]);
+ String tableName = pd[i].read(fontFile);
+ dirTabs.put(TTFTableName.getValue(tableName), pd[i]);
}
+ dirTabs.put(TTFTableName.TABLE_DIRECTORY,
+ new TTFDirTabEntry(0L, fontFile.getCurrentPos()));
log.debug("dir tables: " + dirTabs.keySet());
}
/**
* Read the "head" table, this reads the bounding box and
* sets the upem (unitsPerEM) variable
- * @param in FontFileReader to read the header from
* @throws IOException in case of an I/O problem
*/
- protected void readFontHeader(FontFileReader in) throws IOException {
- seekTab(in, "head", 2 * 4 + 2 * 4);
- int flags = in.readTTFUShort();
+ protected void readFontHeader() throws IOException {
+ seekTab(fontFile, TTFTableName.HEAD, 2 * 4 + 2 * 4);
+ int flags = fontFile.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug("flags: " + flags + " - " + Integer.toString(flags, 2));
}
- upem = in.readTTFUShort();
+ upem = fontFile.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug("unit per em: " + upem);
}
- in.skip(16);
+ fontFile.skip(16);
- fontBBox1 = in.readTTFShort();
- fontBBox2 = in.readTTFShort();
- fontBBox3 = in.readTTFShort();
- fontBBox4 = in.readTTFShort();
+ fontBBox1 = fontFile.readTTFShort();
+ fontBBox2 = fontFile.readTTFShort();
+ fontBBox3 = fontFile.readTTFShort();
+ fontBBox4 = fontFile.readTTFShort();
if (log.isDebugEnabled()) {
log.debug("font bbox: xMin=" + fontBBox1
+ " yMin=" + fontBBox2
@@ -952,19 +1092,18 @@ public class TTFFile {
+ " yMax=" + fontBBox4);
}
- in.skip(2 + 2 + 2);
+ fontFile.skip(2 + 2 + 2);
- locaFormat = in.readTTFShort();
+ locaFormat = fontFile.readTTFShort();
}
/**
* Read the number of glyphs from the "maxp" table
- * @param in FontFileReader to read the number of glyphs from
* @throws IOException in case of an I/O problem
*/
- protected void getNumGlyphs(FontFileReader in) throws IOException {
- seekTab(in, "maxp", 4);
- numberOfGlyphs = in.readTTFUShort();
+ protected void getNumGlyphs() throws IOException {
+ seekTab(fontFile, TTFTableName.MAXP, 4);
+ numberOfGlyphs = fontFile.readTTFUShort();
}
@@ -972,17 +1111,16 @@ public class TTFFile {
* Read the "hhea" table to find the ascender and descender and
* size of "hmtx" table, as a fixed size font might have only
* one width.
- * @param in FontFileReader to read the hhea table from
* @throws IOException in case of an I/O problem
*/
- protected void readHorizontalHeader(FontFileReader in)
+ protected void readHorizontalHeader()
throws IOException {
- seekTab(in, "hhea", 4);
- hheaAscender = in.readTTFShort();
- hheaDescender = in.readTTFShort();
+ seekTab(fontFile, TTFTableName.HHEA, 4);
+ hheaAscender = fontFile.readTTFShort();
+ hheaDescender = fontFile.readTTFShort();
- in.skip(2 + 2 + 3 * 2 + 8 * 2);
- nhmtx = in.readTTFUShort();
+ fontFile.skip(2 + 2 + 3 * 2 + 8 * 2);
+ nhmtx = fontFile.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug("hhea.Ascender: " + formatUnitsForDebug(hheaAscender));
@@ -996,12 +1134,11 @@ public class TTFFile {
* in the mtxTab array. If the number of metrics is less
* than the number of glyphs (eg fixed size fonts), extend
* the mtxTab array and fill in the missing widths
- * @param in FontFileReader to read the hmtx table from
* @throws IOException in case of an I/O problem
*/
- protected void readHorizontalMetrics(FontFileReader in)
+ protected void readHorizontalMetrics()
throws IOException {
- seekTab(in, "hmtx", 0);
+ seekTab(fontFile, TTFTableName.HMTX, 0);
int mtxSize = Math.max(numberOfGlyphs, nhmtx);
mtxTab = new TTFMtxEntry[mtxSize];
@@ -1013,8 +1150,8 @@ public class TTFFile {
mtxTab[i] = new TTFMtxEntry();
}
for (int i = 0; i < nhmtx; i++) {
- mtxTab[i].setWx(in.readTTFUShort());
- mtxTab[i].setLsb(in.readTTFUShort());
+ mtxTab[i].setWx(fontFile.readTTFUShort());
+ mtxTab[i].setLsb(fontFile.readTTFUShort());
if (log.isTraceEnabled()) {
log.trace(" width[" + i + "] = "
@@ -1027,7 +1164,7 @@ public class TTFFile {
int lastWidth = mtxTab[nhmtx - 1].getWx();
for (int i = nhmtx; i < mtxSize; i++) {
mtxTab[i].setWx(lastWidth);
- mtxTab[i].setLsb(in.readTTFUShort());
+ mtxTab[i].setLsb(fontFile.readTTFUShort());
}
}
}
@@ -1037,35 +1174,37 @@ public class TTFFile {
* Read the "post" table
* containing the PostScript names of the glyphs.
*/
- private void readPostScript(FontFileReader in) throws IOException {
- seekTab(in, "post", 0);
- postFormat = in.readTTFLong();
- italicAngle = in.readTTFULong();
- underlinePosition = in.readTTFShort();
- underlineThickness = in.readTTFShort();
- isFixedPitch = in.readTTFULong();
+ private void readPostScript() throws IOException {
+ seekTab(fontFile, TTFTableName.POST, 0);
+ int postFormat = fontFile.readTTFLong();
+ italicAngle = fontFile.readTTFULong();
+ underlinePosition = fontFile.readTTFShort();
+ underlineThickness = fontFile.readTTFShort();
+ isFixedPitch = fontFile.readTTFULong();
//Skip memory usage values
- in.skip(4 * 4);
+ fontFile.skip(4 * 4);
log.debug("PostScript format: 0x" + Integer.toHexString(postFormat));
switch (postFormat) {
case 0x00010000:
log.debug("PostScript format 1");
- for (int i = 0; i < Glyphs.MAC_GLYPH_NAMES.length; i++) {
- mtxTab[i].setName(Glyphs.MAC_GLYPH_NAMES[i]);
+ postScriptVersion = PostScriptVersion.V1;
+ for (int i = 0; i < MAC_GLYPH_ORDERING.length; i++) {
+ mtxTab[i].setName(MAC_GLYPH_ORDERING[i]);
}
break;
case 0x00020000:
log.debug("PostScript format 2");
+ postScriptVersion = PostScriptVersion.V2;
int numGlyphStrings = 0;
// Read Number of Glyphs
- int l = in.readTTFUShort();
+ int l = fontFile.readTTFUShort();
// Read indexes
for (int i = 0; i < l; i++) {
- mtxTab[i].setIndex(in.readTTFUShort());
+ mtxTab[i].setIndex(fontFile.readTTFUShort());
if (mtxTab[i].getIndex() > 257) {
//Index is not in the Macintosh standard set
@@ -1085,16 +1224,16 @@ public class TTFFile {
+ " set. Total number of glyphs=" + l);
}
for (int i = 0; i < psGlyphsBuffer.length; i++) {
- psGlyphsBuffer[i] = in.readTTFString(in.readTTFUByte());
+ psGlyphsBuffer[i] = fontFile.readTTFString(fontFile.readTTFUByte());
}
//Set glyph names
for (int i = 0; i < l; i++) {
- if (mtxTab[i].getIndex() < NMACGLYPHS) {
- mtxTab[i].setName(Glyphs.MAC_GLYPH_NAMES[mtxTab[i].getIndex()]);
+ if (mtxTab[i].getIndex() < MAC_GLYPH_ORDERING.length) {
+ mtxTab[i].setName(MAC_GLYPH_ORDERING[mtxTab[i].getIndex()]);
} else {
if (!mtxTab[i].isIndexReserved()) {
- int k = mtxTab[i].getIndex() - NMACGLYPHS;
+ int k = mtxTab[i].getIndex() - MAC_GLYPH_ORDERING.length;
if (log.isTraceEnabled()) {
log.trace(k + " i=" + i + " mtx=" + mtxTab.length
@@ -1110,9 +1249,11 @@ public class TTFFile {
case 0x00030000:
// PostScript format 3 contains no glyph names
log.debug("PostScript format 3");
+ postScriptVersion = PostScriptVersion.V3;
break;
default:
log.error("Unknown PostScript format: " + postFormat);
+ postScriptVersion = PostScriptVersion.UNKNOWN;
}
}
@@ -1120,60 +1261,60 @@ public class TTFFile {
/**
* Read the "OS/2" table
*/
- private void readOS2(FontFileReader in) throws IOException {
+ private void readOS2() throws IOException {
// Check if font is embeddable
- TTFDirTabEntry os2Entry = getDirectoryEntry ( "OS/2" );
+ TTFDirTabEntry os2Entry = dirTabs.get(TTFTableName.OS2);
if (os2Entry != null) {
- seekTab(in, "OS/2", 0);
- int version = in.readTTFUShort();
+ seekTab(fontFile, TTFTableName.OS2, 0);
+ int version = fontFile.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug("OS/2 table: version=" + version
+ ", offset=" + os2Entry.getOffset() + ", len=" + os2Entry.getLength());
}
- in.skip(2); //xAvgCharWidth
- this.usWeightClass = in.readTTFUShort();
+ fontFile.skip(2); //xAvgCharWidth
+ this.usWeightClass = fontFile.readTTFUShort();
// usWidthClass
- in.skip(2);
+ fontFile.skip(2);
- int fsType = in.readTTFUShort();
+ int fsType = fontFile.readTTFUShort();
if (fsType == 2) {
isEmbeddable = false;
} else {
isEmbeddable = true;
}
- in.skip(11 * 2);
- in.skip(10); //panose array
- in.skip(4 * 4); //unicode ranges
- in.skip(4);
- in.skip(3 * 2);
+ fontFile.skip(11 * 2);
+ fontFile.skip(10); //panose array
+ fontFile.skip(4 * 4); //unicode ranges
+ fontFile.skip(4);
+ fontFile.skip(3 * 2);
int v;
- os2Ascender = in.readTTFShort(); //sTypoAscender
- os2Descender = in.readTTFShort(); //sTypoDescender
+ os2Ascender = fontFile.readTTFShort(); //sTypoAscender
+ os2Descender = fontFile.readTTFShort(); //sTypoDescender
if (log.isDebugEnabled()) {
log.debug("sTypoAscender: " + os2Ascender
+ " -> internal " + convertTTFUnit2PDFUnit(os2Ascender));
log.debug("sTypoDescender: " + os2Descender
+ " -> internal " + convertTTFUnit2PDFUnit(os2Descender));
}
- v = in.readTTFShort(); //sTypoLineGap
+ v = fontFile.readTTFShort(); //sTypoLineGap
if (log.isDebugEnabled()) {
log.debug("sTypoLineGap: " + v);
}
- v = in.readTTFUShort(); //usWinAscent
+ v = fontFile.readTTFUShort(); //usWinAscent
if (log.isDebugEnabled()) {
log.debug("usWinAscent: " + formatUnitsForDebug(v));
}
- v = in.readTTFUShort(); //usWinDescent
+ v = fontFile.readTTFUShort(); //usWinDescent
if (log.isDebugEnabled()) {
log.debug("usWinDescent: " + formatUnitsForDebug(v));
}
//version 1 OS/2 table might end here
if (os2Entry.getLength() >= 78 + (2 * 4) + (2 * 2)) {
- in.skip(2 * 4);
- this.os2xHeight = in.readTTFShort(); //sxHeight
- this.os2CapHeight = in.readTTFShort(); //sCapHeight
+ fontFile.skip(2 * 4);
+ this.os2xHeight = fontFile.readTTFShort(); //sxHeight
+ this.os2CapHeight = fontFile.readTTFShort(); //sCapHeight
if (log.isDebugEnabled()) {
log.debug("sxHeight: " + this.os2xHeight);
log.debug("sCapHeight: " + this.os2CapHeight);
@@ -1187,42 +1328,40 @@ public class TTFFile {
/**
* Read the "loca" table.
- * @param in FontFileReader to read from
* @throws IOException In case of a I/O problem
*/
- protected final void readIndexToLocation(FontFileReader in)
+ protected final void readIndexToLocation()
throws IOException {
- if (!seekTab(in, "loca", 0)) {
+ if (!seekTab(fontFile, TTFTableName.LOCA, 0)) {
throw new IOException("'loca' table not found, happens when the font file doesn't"
+ " contain TrueType outlines (trying to read an OpenType CFF font maybe?)");
}
for (int i = 0; i < numberOfGlyphs; i++) {
- mtxTab[i].setOffset(locaFormat == 1 ? in.readTTFULong()
- : (in.readTTFUShort() << 1));
+ mtxTab[i].setOffset(locaFormat == 1 ? fontFile.readTTFULong()
+ : (fontFile.readTTFUShort() << 1));
}
- lastLoca = (locaFormat == 1 ? in.readTTFULong()
- : (in.readTTFUShort() << 1));
+ lastLoca = (locaFormat == 1 ? fontFile.readTTFULong()
+ : (fontFile.readTTFUShort() << 1));
}
/**
* Read the "glyf" table to find the bounding boxes.
- * @param in FontFileReader to read from
* @throws IOException In case of a I/O problem
*/
- private void readGlyf(FontFileReader in) throws IOException {
- TTFDirTabEntry dirTab = getDirectoryEntry ( "glyf" );
+ private void readGlyf() throws IOException {
+ TTFDirTabEntry dirTab = dirTabs.get(TTFTableName.GLYF);
if (dirTab == null) {
throw new IOException("glyf table not found, cannot continue");
}
for (int i = 0; i < (numberOfGlyphs - 1); i++) {
if (mtxTab[i].getOffset() != mtxTab[i + 1].getOffset()) {
- in.seekSet(dirTab.getOffset() + mtxTab[i].getOffset());
- in.skip(2);
+ fontFile.seekSet(dirTab.getOffset() + mtxTab[i].getOffset());
+ fontFile.skip(2);
final int[] bbox = {
- in.readTTFShort(),
- in.readTTFShort(),
- in.readTTFShort(),
- in.readTTFShort()};
+ fontFile.readTTFShort(),
+ fontFile.readTTFShort(),
+ fontFile.readTTFShort(),
+ fontFile.readTTFShort()};
mtxTab[i].setBoundingBox(bbox);
} else {
mtxTab[i].setBoundingBox(mtxTab[0].getBoundingBox());
@@ -1230,17 +1369,17 @@ public class TTFFile {
}
- long n = dirTab.getOffset();
+ long n = (dirTabs.get(TTFTableName.GLYF)).getOffset();
for (int i = 0; i < numberOfGlyphs; i++) {
if ((i + 1) >= mtxTab.length
|| mtxTab[i].getOffset() != mtxTab[i + 1].getOffset()) {
- in.seekSet(n + mtxTab[i].getOffset());
- in.skip(2);
+ fontFile.seekSet(n + mtxTab[i].getOffset());
+ fontFile.skip(2);
final int[] bbox = {
- in.readTTFShort(),
- in.readTTFShort(),
- in.readTTFShort(),
- in.readTTFShort()};
+ fontFile.readTTFShort(),
+ fontFile.readTTFShort(),
+ fontFile.readTTFShort(),
+ fontFile.readTTFShort()};
mtxTab[i].setBoundingBox(bbox);
} else {
/**@todo Verify that this is correct, looks like a copy/paste bug (jm)*/
@@ -1261,34 +1400,33 @@ public class TTFFile {
/**
* Read the "name" table.
- * @param in FontFileReader to read from
* @throws IOException In case of a I/O problem
*/
- private void readName(FontFileReader in) throws IOException {
- seekTab(in, "name", 2);
- int i = in.getCurrentPos();
- int n = in.readTTFUShort();
- int j = in.readTTFUShort() + i - 2;
+ private void readName() throws IOException {
+ seekTab(fontFile, TTFTableName.NAME, 2);
+ int i = fontFile.getCurrentPos();
+ int n = fontFile.readTTFUShort();
+ int j = fontFile.readTTFUShort() + i - 2;
i += 2 * 2;
while (n-- > 0) {
// getLogger().debug("Iteration: " + n);
- in.seekSet(i);
- final int platformID = in.readTTFUShort();
- final int encodingID = in.readTTFUShort();
- final int languageID = in.readTTFUShort();
+ fontFile.seekSet(i);
+ final int platformID = fontFile.readTTFUShort();
+ final int encodingID = fontFile.readTTFUShort();
+ final int languageID = fontFile.readTTFUShort();
- int k = in.readTTFUShort();
- int l = in.readTTFUShort();
+ int k = fontFile.readTTFUShort();
+ int l = fontFile.readTTFUShort();
if (((platformID == 1 || platformID == 3)
&& (encodingID == 0 || encodingID == 1))) {
- in.seekSet(j + in.readTTFUShort());
+ fontFile.seekSet(j + fontFile.readTTFUShort());
String txt;
if (platformID == 3) {
- txt = in.readTTFString(l, encodingID);
+ txt = fontFile.readTTFString(l, encodingID);
} else {
- txt = in.readTTFString(l);
+ txt = fontFile.readTTFString(l);
}
if (log.isDebugEnabled()) {
@@ -1332,21 +1470,20 @@ public class TTFFile {
/**
* Read the "PCLT" table to find xHeight and capHeight.
- * @param in FontFileReader to read from
* @throws IOException In case of a I/O problem
*/
- private boolean readPCLT(FontFileReader in) throws IOException {
- TTFDirTabEntry dirTab = getDirectoryEntry ( "PCLT" );
+ private boolean readPCLT() throws IOException {
+ TTFDirTabEntry dirTab = dirTabs.get(TTFTableName.PCLT);
if (dirTab != null) {
- in.seekSet(dirTab.getOffset() + 4 + 4 + 2);
- xHeight = in.readTTFUShort();
+ fontFile.seekSet(dirTab.getOffset() + 4 + 4 + 2);
+ xHeight = fontFile.readTTFUShort();
log.debug("xHeight from PCLT: " + formatUnitsForDebug(xHeight));
- in.skip(2 * 2);
- capHeight = in.readTTFUShort();
+ fontFile.skip(2 * 2);
+ capHeight = fontFile.readTTFUShort();
log.debug("capHeight from PCLT: " + formatUnitsForDebug(capHeight));
- in.skip(2 + 16 + 8 + 6 + 1 + 1);
+ fontFile.skip(2 + 16 + 8 + 6 + 1 + 1);
- int serifStyle = in.readTTFUByte();
+ int serifStyle = fontFile.readTTFUByte();
serifStyle = serifStyle >> 6;
serifStyle = serifStyle & 3;
if (serifStyle == 1) {
@@ -1476,19 +1613,18 @@ public class TTFFile {
/**
* Read the kerning table, create a table for both CIDs and
* winAnsiEncoding.
- * @param in FontFileReader to read from
* @throws IOException In case of a I/O problem
*/
- private void readKerning(FontFileReader in) throws IOException {
+ private void readKerning() throws IOException {
// Read kerning
- kerningTab = new java.util.HashMap();
- ansiKerningTab = new java.util.HashMap();
- TTFDirTabEntry dirTab = getDirectoryEntry ( "kern" );
+ kerningTab = new HashMap<Integer, Map<Integer, Integer>>();
+ ansiKerningTab = new HashMap<Integer, Map<Integer, Integer>>();
+ TTFDirTabEntry dirTab = dirTabs.get(TTFTableName.KERN);
if (dirTab != null) {
- seekTab(in, "kern", 2);
- for (int n = in.readTTFUShort(); n > 0; n--) {
- in.skip(2 * 2);
- int k = in.readTTFUShort();
+ seekTab(fontFile, TTFTableName.KERN, 2);
+ for (int n = fontFile.readTTFUShort(); n > 0; n--) {
+ fontFile.skip(2 * 2);
+ int k = fontFile.readTTFUShort();
if (!((k & 1) != 0) || (k & 2) != 0 || (k & 4) != 0) {
return;
}
@@ -1496,12 +1632,12 @@ public class TTFFile {
continue;
}
- k = in.readTTFUShort();
- in.skip(3 * 2);
+ k = fontFile.readTTFUShort();
+ fontFile.skip(3 * 2);
while (k-- > 0) {
- int i = in.readTTFUShort();
- int j = in.readTTFUShort();
- int kpx = in.readTTFShort();
+ int i = fontFile.readTTFUShort();
+ int j = fontFile.readTTFUShort();
+ int kpx = fontFile.readTTFShort();
if (kpx != 0) {
// CID kerning table entry, using unicode indexes
final Integer iObj = glyphToUnicode(i);
@@ -1515,9 +1651,9 @@ public class TTFFile {
log.debug("Ignoring kerning pair because Unicode index was"
+ " found for the second glyph " + i);
} else {
- Map adjTab = kerningTab.get(iObj);
+ Map<Integer, Integer> adjTab = kerningTab.get(iObj);
if (adjTab == null) {
- adjTab = new java.util.HashMap();
+ adjTab = new HashMap<Integer, Integer>();
}
adjTab.put(u2, new Integer(convertTTFUnit2PDFUnit(kpx)));
kerningTab.put(iObj, adjTab);
@@ -1529,16 +1665,12 @@ public class TTFFile {
// Create winAnsiEncoded kerning table from kerningTab
// (could probably be simplified, for now we remap back to CID indexes and
// then to winAnsi)
- Iterator ae = kerningTab.keySet().iterator();
- while (ae.hasNext()) {
- Integer unicodeKey1 = (Integer)ae.next();
+ for (Integer unicodeKey1 : kerningTab.keySet()) {
Integer cidKey1 = unicodeToGlyph(unicodeKey1.intValue());
- Map<Integer, Integer> akpx = new java.util.HashMap();
- Map ckpx = kerningTab.get(unicodeKey1);
+ Map<Integer, Integer> akpx = new HashMap<Integer, Integer>();
+ Map<Integer, Integer> ckpx = kerningTab.get(unicodeKey1);
- Iterator aee = ckpx.keySet().iterator();
- while (aee.hasNext()) {
- Integer unicodeKey2 = (Integer)aee.next();
+ for (Integer unicodeKey2 : ckpx.keySet()) {
Integer cidKey2 = unicodeToGlyph(unicodeKey2.intValue());
Integer kern = (Integer)ckpx.get(unicodeKey2);
@@ -1567,10 +1699,71 @@ public class TTFFile {
}
/**
- * Return a List with TTFCmapEntry.
- * @return A list of TTFCmapEntry objects
+ * Streams a font.
+ * @param ttfOut The interface for streaming TrueType tables.
+ * @exception IOException file write error
+ */
+ public void stream(TTFOutputStream ttfOut) throws IOException {
+ SortedSet<Map.Entry<TTFTableName, TTFDirTabEntry>> sortedDirTabs = sortDirTabMap(dirTabs);
+ byte[] file = fontFile.getAllBytes();
+ TTFTableOutputStream tableOut = ttfOut.getTableOutputStream();
+ TTFGlyphOutputStream glyphOut = ttfOut.getGlyphOutputStream();
+ ttfOut.startFontStream();
+ for (Map.Entry<TTFTableName, TTFDirTabEntry> entry : sortedDirTabs) {
+ int offset = (int) entry.getValue().getOffset();
+ int paddedLength = (int) entry.getValue().getLength();
+ paddedLength += getPadSize(offset + paddedLength);
+ if (entry.getKey().equals(TTFTableName.GLYF)) {
+ streamGlyf(glyphOut, file, offset, paddedLength);
+ } else {
+ tableOut.streamTable(file, offset, paddedLength);
+ }
+ }
+ ttfOut.endFontStream();
+ }
+
+ private void streamGlyf(TTFGlyphOutputStream glyphOut, byte[] fontFile, int tableOffset,
+ int tableLength) throws IOException {
+ //Stream all but the last glyph
+ int glyphStart = 0;
+ int glyphEnd = 0;
+ glyphOut.startGlyphStream();
+ for (int i = 0; i < mtxTab.length - 1; i++) {
+ glyphStart = (int) mtxTab[i].getOffset() + tableOffset;
+ glyphEnd = (int) mtxTab[i + 1].getOffset() + tableOffset;
+ glyphOut.streamGlyph(fontFile, glyphStart, glyphEnd - glyphStart);
+ }
+ glyphOut.streamGlyph(fontFile, glyphEnd, (tableOffset + tableLength) - glyphEnd);
+ glyphOut.endGlyphStream();
+ }
+
+ /**
+ * Returns the order in which the tables in a TrueType font should be written to file.
+ * @param directoryTabs the map that is to be sorted.
+ * @return TTFTablesNames[] an array of table names sorted in the order they should appear in
+ * the TTF file.
+ */
+ SortedSet<Map.Entry<TTFTableName, TTFDirTabEntry>>
+ sortDirTabMap(Map<TTFTableName, TTFDirTabEntry> directoryTabs) {
+ SortedSet<Map.Entry<TTFTableName, TTFDirTabEntry>> sortedSet
+ = new TreeSet<Map.Entry<TTFTableName, TTFDirTabEntry>>(
+ new Comparator<Map.Entry<TTFTableName, TTFDirTabEntry>>() {
+
+ public int compare(Entry<TTFTableName, TTFDirTabEntry> o1,
+ Entry<TTFTableName, TTFDirTabEntry> o2) {
+ return (int) (o1.getValue().getOffset() - o2.getValue().getOffset());
+ }
+ });
+ sortedSet.addAll(directoryTabs.entrySet());
+ return sortedSet;
+ }
+
+ /**
+ * Returns this font's character to glyph mapping.
+ *
+ * @return the font's cmap
*/
- public List getCMaps() {
+ public List<CMapSegment> getCMaps() {
return cmaps;
}
@@ -1579,24 +1772,23 @@ public class TTFFile {
* name exists in the collection.
* If it does, set offset in fontfile to the beginning of
* the Table Directory for that font.
- * @param in FontFileReader to read from
* @param name The name to check
* @return True if not collection or font name present, false otherwise
* @throws IOException In case of an I/O problem
*/
- protected final boolean checkTTC(FontFileReader in, String name) throws IOException {
- String tag = in.readTTFString(4);
+ protected final boolean checkTTC(String name) throws IOException {
+ String tag = fontFile.readTTFString(4);
if ("ttcf".equals(tag)) {
// This is a TrueType Collection
- in.skip(4);
+ fontFile.skip(4);
// Read directory offsets
- int numDirectories = (int)in.readTTFULong();
+ int numDirectories = (int)fontFile.readTTFULong();
// int numDirectories=in.readTTFUShort();
long[] dirOffsets = new long[numDirectories];
for (int i = 0; i < numDirectories; i++) {
- dirOffsets[i] = in.readTTFULong();
+ dirOffsets[i] = fontFile.readTTFULong();
}
log.info("This is a TrueType collection file with "
@@ -1610,10 +1802,10 @@ public class TTFFile {
// Is found, just to show all the names
long dirTabOffset = 0;
for (int i = 0; (i < numDirectories); i++) {
- in.seekSet(dirOffsets[i]);
- readDirTabs(in);
+ fontFile.seekSet(dirOffsets[i]);
+ readDirTabs();
- readName(in);
+ readName();
if (fullName.equals(name)) {
found = true;
@@ -1631,10 +1823,10 @@ public class TTFFile {
subFamilyName = "";
}
- in.seekSet(dirTabOffset);
+ fontFile.seekSet(dirTabOffset);
return found;
} else {
- in.seekSet(0);
+ fontFile.seekSet(0);
return true;
}
}
@@ -1646,8 +1838,7 @@ public class TTFFile {
* @throws IOException In case of an I/O problem
*/
public final List<String> getTTCnames(FontFileReader in) throws IOException {
- List<String> fontNames = new java.util.ArrayList<String>();
-
+ List<String> fontNames = new ArrayList<String>();
String tag = in.readTTFString(4);
if ("ttcf".equals(tag)) {
@@ -1667,9 +1858,9 @@ public class TTFFile {
for (int i = 0; (i < numDirectories); i++) {
in.seekSet(dirOffsets[i]);
- readDirTabs(in);
+ readDirTabs();
- readName(in);
+ readName();
log.info(fullName);
fontNames.add(fullName);
@@ -1695,13 +1886,13 @@ public class TTFFile {
* doesn't matter...
*/
private Integer[] unicodeToWinAnsi(int unicode) {
- List ret = new java.util.ArrayList();
+ List<Integer> ret = new ArrayList<Integer>();
for (int i = 32; i < Glyphs.WINANSI_ENCODING.length; i++) {
if (unicode == Glyphs.WINANSI_ENCODING[i]) {
ret.add(new Integer(i));
}
}
- return (Integer[])ret.toArray(new Integer[0]);
+ return ret.toArray(new Integer[0]);
}
/**
@@ -1744,7 +1935,7 @@ public class TTFFile {
* @return unicode code point
*/
private Integer glyphToUnicode(int glyphIndex) {
- return (Integer) glyphToUnicodeMap.get(new Integer(glyphIndex));
+ return glyphToUnicodeMap.get(new Integer(glyphIndex));
}
/**
@@ -1755,7 +1946,7 @@ public class TTFFile {
*/
private Integer unicodeToGlyph(int unicodeIndex) throws IOException {
final Integer result
- = (Integer) unicodeToGlyphMap.get(new Integer(unicodeIndex));
+ = unicodeToGlyphMap.get(new Integer(unicodeIndex));
if (result == null) {
throw new IOException(
"Glyph index not found for unicode value " + unicodeIndex);
@@ -1763,6 +1954,10 @@ public class TTFFile {
return result;
}
+ String getGlyphName(int glyphIndex) {
+ return mtxTab[glyphIndex].getName();
+ }
+
/**
* Determine if advanced (typographic) table is present.
* @return true if advanced (typographic) table is present
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java Fri Jun 22 18:07:04 2012
@@ -21,17 +21,14 @@ package org.apache.fop.fonts.truetype;
import java.io.IOException;
import java.io.InputStream;
-import java.util.Iterator;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.io.IOUtils;
-import org.apache.xmlgraphics.fonts.Glyphs;
-
-import org.apache.fop.fonts.BFEntry;
import org.apache.fop.fonts.CIDFontType;
+import org.apache.fop.fonts.CMapSegment;
+import org.apache.fop.fonts.EmbeddingMode;
import org.apache.fop.fonts.EncodingMode;
import org.apache.fop.fonts.FontLoader;
import org.apache.fop.fonts.FontResolver;
@@ -39,6 +36,8 @@ import org.apache.fop.fonts.FontType;
import org.apache.fop.fonts.MultiByteFont;
import org.apache.fop.fonts.NamedCharacter;
import org.apache.fop.fonts.SingleByteFont;
+import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion;
+import org.apache.fop.util.HexEncoder;
/**
* Loads a TrueType font into memory directly from the original font file.
@@ -49,6 +48,7 @@ public class TTFFontLoader extends FontL
private SingleByteFont singleFont;
private final String subFontName;
private EncodingMode encodingMode;
+ private EmbeddingMode embeddingMode;
/**
* Default constructor
@@ -56,7 +56,7 @@ public class TTFFontLoader extends FontL
* @param resolver the FontResolver for font URI resolution
*/
public TTFFontLoader(String fontFileURI, FontResolver resolver) {
- this(fontFileURI, null, true, EncodingMode.AUTO, true, true, resolver);
+ this(fontFileURI, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO, true, true, resolver);
}
/**
@@ -65,24 +65,28 @@ public class TTFFontLoader extends FontL
* @param subFontName the sub-fontname of a font in a TrueType Collection (or null for normal
* TrueType fonts)
* @param embedded indicates whether the font is embedded or referenced
+ * @param embeddingMode the embedding mode of the font
* @param encodingMode the requested encoding mode
* @param useKerning true to enable loading kerning info if available, false to disable
* @param useAdvanced true to enable loading advanced info if available, false to disable
* @param resolver the FontResolver for font URI resolution
*/
public TTFFontLoader(String fontFileURI, String subFontName,
- boolean embedded, EncodingMode encodingMode, boolean useKerning,
- boolean useAdvanced, FontResolver resolver) {
+ boolean embedded, EmbeddingMode embeddingMode, EncodingMode encodingMode,
+ boolean useKerning, boolean useAdvanced, FontResolver resolver) {
super(fontFileURI, embedded, useKerning, useAdvanced, resolver);
this.subFontName = subFontName;
this.encodingMode = encodingMode;
+ this.embeddingMode = embeddingMode;
if (this.encodingMode == EncodingMode.AUTO) {
this.encodingMode = EncodingMode.CID; //Default to CID mode for TrueType
}
+ if (this.embeddingMode == EmbeddingMode.AUTO) {
+ this.embeddingMode = EmbeddingMode.SUBSET;
+ }
}
/** {@inheritDoc} */
- @Override
protected void read() throws IOException {
read(this.subFontName);
}
@@ -145,29 +149,20 @@ public class TTFFontLoader extends FontL
returnFont.setItalicAngle(Integer.parseInt(ttf.getItalicAngle()));
returnFont.setMissingWidth(0);
returnFont.setWeight(ttf.getWeightClass());
-
+ returnFont.setEmbeddingMode(this.embeddingMode);
if (isCid) {
multiFont.setCIDType(CIDFontType.CIDTYPE2);
int[] wx = ttf.getWidths();
multiFont.setWidthArray(wx);
- List entries = ttf.getCMaps();
- BFEntry[] bfentries = new BFEntry[entries.size()];
- int pos = 0;
- Iterator iter = ttf.getCMaps().listIterator();
- while (iter.hasNext()) {
- TTFCmapEntry ce = (TTFCmapEntry)iter.next();
- bfentries[pos] = new BFEntry(ce.getUnicodeStart(), ce.getUnicodeEnd(),
- ce.getGlyphStartIndex());
- pos++;
- }
- multiFont.setBFEntries(bfentries);
} else {
singleFont.setFontType(FontType.TRUETYPE);
singleFont.setEncoding(ttf.getCharSetName());
returnFont.setFirstChar(ttf.getFirstChar());
returnFont.setLastChar(ttf.getLastChar());
+ singleFont.setTrueTypePostScriptVersion(ttf.getPostScriptVersion());
copyWidthsSingleByte(ttf);
}
+ returnFont.setCMap(getCMap(ttf));
if (useKerning) {
copyKerning(ttf, isCid);
@@ -186,23 +181,30 @@ public class TTFFontLoader extends FontL
}
}
+ private CMapSegment[] getCMap(TTFFile ttf) {
+ CMapSegment[] array = new CMapSegment[ttf.getCMaps().size()];
+ return ttf.getCMaps().toArray(array);
+ }
+
private void copyWidthsSingleByte(TTFFile ttf) {
int[] wx = ttf.getWidths();
for (int i = singleFont.getFirstChar(); i <= singleFont.getLastChar(); i++) {
singleFont.setWidth(i, ttf.getCharWidth(i));
}
- Iterator iter = ttf.getCMaps().listIterator();
- while (iter.hasNext()) {
- TTFCmapEntry ce = (TTFCmapEntry)iter.next();
- if (ce.getUnicodeStart() < 0xFFFE) {
- for (char u = (char)ce.getUnicodeStart(); u <= ce.getUnicodeEnd(); u++) {
+
+ for (CMapSegment segment : ttf.getCMaps()) {
+ if (segment.getUnicodeStart() < 0xFFFE) {
+ for (char u = (char)segment.getUnicodeStart(); u <= segment.getUnicodeEnd(); u++) {
int codePoint = singleFont.getEncoding().mapChar(u);
if (codePoint <= 0) {
- String unicode = Character.toString(u);
- String charName = Glyphs.stringToGlyph(unicode);
- if (charName.length() > 0) {
- NamedCharacter nc = new NamedCharacter(charName, unicode);
- int glyphIndex = ce.getGlyphStartIndex() + u - ce.getUnicodeStart();
+ int glyphIndex = segment.getGlyphStartIndex() + u - segment.getUnicodeStart();
+ String glyphName = ttf.getGlyphName(glyphIndex);
+ if (glyphName.length() == 0 && ttf.getPostScriptVersion() != PostScriptVersion.V2) {
+ glyphName = "u" + HexEncoder.encode(u);
+ }
+ if (glyphName.length() > 0) {
+ String unicode = Character.toString(u);
+ NamedCharacter nc = new NamedCharacter(glyphName, unicode);
singleFont.addUnencodedCharacter(nc, wx[glyphIndex]);
}
}
@@ -225,7 +227,6 @@ public class TTFFontLoader extends FontL
}
for (Integer kpx1 : kerningSet) {
-
Map<Integer, Integer> h2;
if (isCid) {
h2 = ttf.getKerning().get(kpx1);
---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org