Browse Source

Added possibility to use glyphs outside WinAnsiEncoding for TrueType fonts that are not embedded in the PostScript file, and that don't have a list of glyph names ('post' table version 3).

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-ffa450edef68
tags/fop-1_1rc1^2
Vincent Hennebert 13 years ago
parent
commit
519ac01c92

+ 25
- 0
src/java/org/apache/fop/fonts/SingleByteFont.java View File

@@ -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;

+ 121
- 8
src/java/org/apache/fop/fonts/truetype/TTFFile.java View File

@@ -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;
}
}


+ 6
- 0
src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java View File

@@ -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);

+ 54
- 3
src/java/org/apache/fop/render/ps/PSFontUtils.java View File

@@ -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;
}

}

+ 1
- 0
src/java/org/apache/fop/render/ps/PSPainter.java View File

@@ -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.

+ 1
- 0
src/java/org/apache/fop/render/ps/PSTextPainter.java View File

@@ -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.

src/java/org/apache/fop/render/ps/HexEncoder.java → src/java/org/apache/fop/util/HexEncoder.java View File

@@ -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);
}


+ 1
- 1
test/java/org/apache/fop/UtilityCodeTestSuite.java View File

@@ -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;


test/java/org/apache/fop/render/ps/HexEncoderTestCase.java → test/java/org/apache/fop/util/HexEncoderTestCase.java View File

@@ -17,7 +17,7 @@

/* $Id$ */

package org.apache.fop.render.ps;
package org.apache.fop.util;

import junit.framework.TestCase;


Loading…
Cancel
Save