This is done by creating glyph names using Adobe's convention (/u1234) and adding a CharStrings table that maps those glyph names to the actual glyph index. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@990225 13f79535-47bb-0310-9956-ffa450edef68tags/fop-1_1rc1^2
@@ -27,6 +27,8 @@ import java.util.Set; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; | |||
/** | |||
* Generic SingleByte font | |||
*/ | |||
@@ -46,6 +48,8 @@ public class SingleByteFont extends CustomFont { | |||
private List cmaps; | |||
private PostScriptVersion ttPostScriptVersion; | |||
/** | |||
* Main constructor. | |||
*/ | |||
@@ -335,6 +339,27 @@ public class SingleByteFont extends CustomFont { | |||
} | |||
} | |||
/** | |||
* Sets the version of the PostScript table stored in the TrueType font represented by | |||
* this instance. | |||
* | |||
* @param version version of the <q>post</q> table | |||
*/ | |||
public void setTrueTypePostScriptVersion(PostScriptVersion version) { | |||
ttPostScriptVersion = version; | |||
} | |||
/** | |||
* Returns the version of the PostScript table stored in the TrueType font represented by | |||
* this instance. | |||
* | |||
* @return the version of the <q>post</q> table | |||
*/ | |||
public PostScriptVersion getTrueTypePostScriptVersion() { | |||
assert getFontType() == FontType.TRUETYPE; | |||
return ttPostScriptVersion; | |||
} | |||
/** TODO remove */ | |||
public void setCMaps(List cmaps) { | |||
this.cmaps = cmaps; |
@@ -41,10 +41,94 @@ 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" | |||
}; | |||
/** Set to true to get even more debug output than with level DEBUG */ | |||
public static final boolean TRACE_ENABLED = false; | |||
@@ -64,7 +148,7 @@ public class TTFFile { | |||
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 | |||
@@ -159,6 +243,27 @@ public class TTFFile { | |||
} | |||
} | |||
/** | |||
* Version of the PostScript table (<q>post</q>) contained in this font. | |||
*/ | |||
public static final class PostScriptVersion { | |||
/** PostScript table version 1.0. */ | |||
public static final PostScriptVersion V1 = new PostScriptVersion(); | |||
/** PostScript table version 2.0. */ | |||
public static final PostScriptVersion V2 = new PostScriptVersion(); | |||
/** PostScript table version 3.0. */ | |||
public static final PostScriptVersion V3 = new PostScriptVersion(); | |||
/** Unknown version of the PostScript table. */ | |||
public static final PostScriptVersion UNKNOWN = new PostScriptVersion(); | |||
private PostScriptVersion() { } | |||
} | |||
/** | |||
* Position inputstream to position indicated | |||
* in the dirtab offset + offset | |||
@@ -604,6 +709,10 @@ public class TTFFile { | |||
} | |||
} | |||
PostScriptVersion getPostScriptVersion() { | |||
return postScriptVersion; | |||
} | |||
/** | |||
* Returns the font family names of the font. | |||
* @return Set The family names (a Set of Strings) | |||
@@ -964,7 +1073,7 @@ public class TTFFile { | |||
*/ | |||
private void readPostScript(FontFileReader in) throws IOException { | |||
seekTab(in, "post", 0); | |||
postFormat = in.readTTFLong(); | |||
int postFormat = in.readTTFLong(); | |||
italicAngle = in.readTTFULong(); | |||
underlinePosition = in.readTTFShort(); | |||
underlineThickness = in.readTTFShort(); | |||
@@ -977,12 +1086,14 @@ public class TTFFile { | |||
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 | |||
@@ -1015,11 +1126,11 @@ public class TTFFile { | |||
//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 | |||
@@ -1035,9 +1146,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; | |||
} | |||
} | |||
@@ -36,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. | |||
@@ -162,6 +164,7 @@ public class TTFFontLoader extends FontLoader { | |||
returnFont.setFirstChar(ttf.getFirstChar()); | |||
returnFont.setLastChar(ttf.getLastChar()); | |||
singleFont.setCMaps(ttf.getCMaps()); | |||
singleFont.setTrueTypePostScriptVersion(ttf.getPostScriptVersion()); | |||
copyWidthsSingleByte(ttf); | |||
} | |||
@@ -187,6 +190,9 @@ public class TTFFontLoader extends FontLoader { | |||
if (codePoint <= 0) { | |||
int glyphIndex = ce.getGlyphStartIndex() + u - ce.getUnicodeStart(); | |||
String glyphName = ttf.getGlyphName(glyphIndex); | |||
if (glyphName == "" && ttf.getPostScriptVersion() != PostScriptVersion.V2) { | |||
glyphName = "u" + HexEncoder.encode(u); | |||
} | |||
if (glyphName != "") { | |||
String unicode = Character.toString(u); | |||
NamedCharacter nc = new NamedCharacter(glyphName, unicode); |
@@ -55,6 +55,8 @@ import org.apache.fop.fonts.SingleByteEncoding; | |||
import org.apache.fop.fonts.SingleByteFont; | |||
import org.apache.fop.fonts.Typeface; | |||
import org.apache.fop.fonts.truetype.TTFCmapEntry; | |||
import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; | |||
import org.apache.fop.util.HexEncoder; | |||
/** | |||
* Utility code for font handling in PostScript. | |||
@@ -132,8 +134,16 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { | |||
SingleByteEncoding encoding = sbf.getAdditionalEncoding(i); | |||
defineEncoding(gen, encoding); | |||
String postFix = "_" + (i + 1); | |||
PSResource derivedFontRes = defineDerivedFont(gen, tf.getFontName(), | |||
tf.getFontName() + postFix, encoding.getName()); | |||
PSResource derivedFontRes; | |||
if (tf.getFontType() == FontType.TRUETYPE | |||
&& sbf.getTrueTypePostScriptVersion() != PostScriptVersion.V2) { | |||
derivedFontRes = defineDerivedTrueTypeFont(gen, eventProducer, | |||
tf.getFontName(), tf.getFontName() + postFix, encoding, | |||
sbf.getCMaps()); | |||
} else { | |||
derivedFontRes = defineDerivedFont(gen, tf.getFontName(), | |||
tf.getFontName() + postFix, encoding.getName()); | |||
} | |||
fontResources.put(key + postFix, | |||
PSFontResource.createFontResource(derivedFontRes)); | |||
} | |||
@@ -334,7 +344,10 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { | |||
} | |||
private static int getGlyphIndex(String glyphName, List cmaps) { | |||
char c = Glyphs.getUnicodeSequenceForGlyphName(glyphName).charAt(0); | |||
return getGlyphIndex(Glyphs.getUnicodeSequenceForGlyphName(glyphName).charAt(0), cmaps); | |||
} | |||
private static int getGlyphIndex(char c, List cmaps) { | |||
for (Iterator iter = cmaps.iterator(); iter.hasNext();) { | |||
TTFCmapEntry cmap = (TTFCmapEntry) iter.next(); | |||
if (cmap.getUnicodeStart() <= c && c <= cmap.getUnicodeEnd()) { | |||
@@ -591,4 +604,42 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { | |||
return res; | |||
} | |||
private static PSResource defineDerivedTrueTypeFont(PSGenerator gen, | |||
PSEventProducer eventProducer, String baseFontName, String fontName, | |||
SingleByteEncoding encoding, List cmaps) throws IOException { | |||
PSResource res = new PSResource(PSResource.TYPE_FONT, fontName); | |||
gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE, res); | |||
gen.commentln("%XGCDependencies: font " + baseFontName); | |||
gen.commentln("%XGC+ encoding " + encoding.getName()); | |||
gen.writeln("/" + baseFontName + " findfont"); | |||
gen.writeln("dup length dict begin"); | |||
gen.writeln(" {1 index /FID ne {def} {pop pop} ifelse} forall"); | |||
gen.writeln(" /Encoding " + encoding.getName() + " def"); | |||
gen.writeln(" /CharStrings 256 dict dup begin"); | |||
String[] charNameMap = encoding.getCharNameMap(); | |||
char[] unicodeCharMap = encoding.getUnicodeCharMap(); | |||
assert charNameMap.length == unicodeCharMap.length; | |||
for (int i = 0; i < charNameMap.length; i++) { | |||
String glyphName = charNameMap[i]; | |||
gen.write(" /"); | |||
gen.write(glyphName); | |||
gen.write(" "); | |||
if (glyphName.equals(".notdef")) { | |||
gen.write(0); | |||
} else { | |||
gen.write(getGlyphIndex(unicodeCharMap[i], cmaps)); | |||
} | |||
gen.writeln(" def"); | |||
} | |||
gen.writeln(" end readonly def"); | |||
gen.writeln(" currentdict"); | |||
gen.writeln("end"); | |||
gen.writeln("/" + fontName + " exch definefont pop"); | |||
gen.writeDSCComment(DSCConstants.END_RESOURCE); | |||
gen.getResourceTracker().registerSuppliedResource(res); | |||
return res; | |||
} | |||
} |
@@ -55,6 +55,7 @@ import org.apache.fop.render.intermediate.IFState; | |||
import org.apache.fop.traits.BorderProps; | |||
import org.apache.fop.traits.RuleStyle; | |||
import org.apache.fop.util.CharUtilities; | |||
import org.apache.fop.util.HexEncoder; | |||
/** | |||
* IFPainter implementation that produces PostScript. |
@@ -50,6 +50,7 @@ import org.apache.fop.fonts.LazyFont; | |||
import org.apache.fop.fonts.MultiByteFont; | |||
import org.apache.fop.svg.NativeTextPainter; | |||
import org.apache.fop.util.CharUtilities; | |||
import org.apache.fop.util.HexEncoder; | |||
/** | |||
* Renders the attributed character iterator of a text node. |
@@ -17,12 +17,12 @@ | |||
/* $Id$ */ | |||
package org.apache.fop.render.ps; | |||
package org.apache.fop.util; | |||
/** | |||
* A helper class to hex-encoded representations of numbers. | |||
* A helper class create to hex-encoded representations of numbers. | |||
*/ | |||
final class HexEncoder { | |||
public final class HexEncoder { | |||
private HexEncoder() { } | |||
@@ -34,7 +34,7 @@ final class HexEncoder { | |||
* @param width required length of the string | |||
* @return an hex-encoded representation of the number | |||
*/ | |||
static String encode(int n, int width) { | |||
public static String encode(int n, int width) { | |||
char[] digits = new char[width]; | |||
for (int i = width - 1; i >= 0; i--) { | |||
int digit = n & 0xF; | |||
@@ -50,7 +50,7 @@ final class HexEncoder { | |||
* @param c a character | |||
* @return an hex-encoded representation of the character | |||
*/ | |||
static String encode(char c) { | |||
public static String encode(char c) { | |||
return encode(c, 4); | |||
} | |||
@@ -24,10 +24,10 @@ import junit.framework.TestSuite; | |||
import org.apache.fop.events.BasicEventTestCase; | |||
import org.apache.fop.pdf.PDFObjectTestCase; | |||
import org.apache.fop.render.ps.HexEncoderTestCase; | |||
import org.apache.fop.traits.BorderPropsTestCase; | |||
import org.apache.fop.util.ColorUtilTestCase; | |||
import org.apache.fop.util.ElementListUtilsTestCase; | |||
import org.apache.fop.util.HexEncoderTestCase; | |||
import org.apache.fop.util.PDFNumberTestCase; | |||
import org.apache.fop.util.XMLResourceBundleTestCase; | |||
@@ -17,7 +17,7 @@ | |||
/* $Id$ */ | |||
package org.apache.fop.render.ps; | |||
package org.apache.fop.util; | |||
import junit.framework.TestCase; | |||