aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorfotis <fotis@unknown>2001-02-27 12:30:36 +0000
committerfotis <fotis@unknown>2001-02-27 12:30:36 +0000
commit375b678502231f5577d5b18550c35678d11e11d8 (patch)
treee4a11a39dc47debb1465ec80f686c553caa5a4a6 /src
parent440ec1d3a5601f93e8798acd8a6325c39a19ddd9 (diff)
downloadxmlgraphics-fop-375b678502231f5577d5b18550c35678d11e11d8.tar.gz
xmlgraphics-fop-375b678502231f5577d5b18550c35678d11e11d8.zip
enabling CID keyed truetype fonts; this gives support
for other encodings than WinAnsiEncoding (eg japanese, chinese, arabic, iso-whatever, etc). Also makes font inclusion easier Tore Engvig git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@194095 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
-rw-r--r--src/org/apache/fop/configuration/Configuration.java11
-rw-r--r--src/org/apache/fop/configuration/ConfigurationParser.java82
-rw-r--r--src/org/apache/fop/configuration/ConfigurationReader.java58
-rw-r--r--src/org/apache/fop/configuration/FontInfo.java44
-rw-r--r--src/org/apache/fop/configuration/FontTriplet.java39
-rw-r--r--src/org/apache/fop/fonts/Glyphs.java249
-rw-r--r--src/org/apache/fop/fonts/PFMFile.java6
-rw-r--r--src/org/apache/fop/fonts/TTFCmapEntry.java41
-rw-r--r--src/org/apache/fop/fonts/TTFDirTabEntry.java62
-rw-r--r--src/org/apache/fop/fonts/TTFFile.java1474
-rw-r--r--src/org/apache/fop/fonts/TTFMtxEntry.java45
-rw-r--r--src/org/apache/fop/fonts/apps/PFMReader.java230
-rw-r--r--src/org/apache/fop/fonts/apps/TTFReader.java392
-rw-r--r--src/org/apache/fop/layout/FontInfo.java17
-rw-r--r--src/org/apache/fop/layout/FontState.java154
-rw-r--r--src/org/apache/fop/layout/LineArea.java34
-rw-r--r--src/org/apache/fop/pdf/PDFCIDFont.java37
-rw-r--r--src/org/apache/fop/pdf/PDFCIDFontDescriptor.java1
-rw-r--r--src/org/apache/fop/pdf/PDFCMap.java71
-rw-r--r--src/org/apache/fop/pdf/PDFDocument.java138
-rw-r--r--src/org/apache/fop/pdf/PDFFont.java10
-rw-r--r--src/org/apache/fop/pdf/PDFFontDescriptor.java5
-rw-r--r--src/org/apache/fop/pdf/PDFFontType0.java24
-rw-r--r--src/org/apache/fop/pdf/PDFWArray.java2
-rw-r--r--src/org/apache/fop/render/pdf/CIDFont.java29
-rw-r--r--src/org/apache/fop/render/pdf/CMap.java55
-rw-r--r--src/org/apache/fop/render/pdf/Font.java40
-rw-r--r--src/org/apache/fop/render/pdf/FontReader.java334
-rw-r--r--src/org/apache/fop/render/pdf/FontSetup.java52
-rw-r--r--src/org/apache/fop/render/pdf/PDFRenderer.java128
-rw-r--r--src/org/apache/fop/render/pdf/fonts/BFEntry.java73
-rw-r--r--src/org/apache/fop/render/pdf/fonts/MultiByteFont.java236
-rw-r--r--src/org/apache/fop/render/pdf/fonts/SingleByteFont.java196
33 files changed, 3262 insertions, 1107 deletions
diff --git a/src/org/apache/fop/configuration/Configuration.java b/src/org/apache/fop/configuration/Configuration.java
index 844fede9e..088982841 100644
--- a/src/org/apache/fop/configuration/Configuration.java
+++ b/src/org/apache/fop/configuration/Configuration.java
@@ -220,6 +220,17 @@ public class Configuration {
/**
+ * method to access fonts values in the standard configuration
+ *
+ * @param key a string containing the key value for the configuration value
+ * @return Hashtable a Hashtable containing the values
+ * null if the key is not defined.
+ */
+ public static Vector getFonts() {
+ return (Vector) Configuration.getValue("fonts", Configuration.STANDARD);
+ }
+
+ /**
* initializes this configuration
* @param config contains the configuration information
*/
diff --git a/src/org/apache/fop/configuration/ConfigurationParser.java b/src/org/apache/fop/configuration/ConfigurationParser.java
index c5c3d620b..1dab0e2b7 100644
--- a/src/org/apache/fop/configuration/ConfigurationParser.java
+++ b/src/org/apache/fop/configuration/ConfigurationParser.java
@@ -7,14 +7,19 @@
package org.apache.fop.configuration;
+//sax
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
+
+//java
import java.util.Hashtable;
import java.util.Vector;
+//fop
import org.apache.fop.messaging.MessageHandler;
+
/**
* SAX2 Handler which retrieves the configuration information and stores them in Configuration.
* Normally this class doesn't need to be accessed directly.
@@ -28,6 +33,8 @@ public class ConfigurationParser extends DefaultHandler {
private final int IN_LIST = 8;
private final int IN_SUBENTRY = 16;
private final int IN_SUBKEY = 32;
+ private final int IN_FONTS = 64;
+ private final int IN_FONT = 128;
private final int STRING = 0;
private final int LIST = 1;
@@ -62,6 +69,23 @@ public class ConfigurationParser extends DefaultHandler {
/** determines role / target of configuration information, default is standard */
private String role = "standard";
+ //stores fonts
+ private Vector fontList = null;
+
+ //stores information on one font
+ private FontInfo fontInfo = null;
+
+ //stores information on a font triplet
+ private FontTriplet fontTriplet = null;
+
+ //information on a font
+ private String fontName, metricsFile, embedFile, kerningAsString;
+ private boolean kerning;
+ private Vector fontTriplets;
+
+ //information on a font triplet
+ private String fontTripletName, weight, style;
+
public void startDocument() {
configuration = Configuration.getConfiguration();
}
@@ -93,6 +117,25 @@ public class ConfigurationParser extends DefaultHandler {
role = attributes.getValue("role");
}
} else if (localName.equals("configuration") ) {
+ } else if (localName.equals("fonts") ) { //list of fonts starts
+ fontList = new Vector (10);
+ } else if (localName.equals("font") ) {
+ kerningAsString = attributes.getValue("kerning");
+ if (kerningAsString.equalsIgnoreCase("yes")) {
+ kerning = true;
+ } else {
+ kerning = false;
+ }
+ metricsFile = attributes.getValue("metrics-file");
+ embedFile = attributes.getValue("embed-file");
+ fontName = attributes.getValue("name");
+ fontTriplets = new Vector(5);
+ } else if (localName.equals("font-triplet") ) {
+ fontTripletName = attributes.getValue("name");
+ weight = attributes.getValue("weight");
+ style = attributes.getValue("style");
+ fontTriplet = new FontTriplet(fontTripletName,weight,style);
+ fontTriplets.addElement(fontTriplet);
} else {
//to make sure that user knows about false tag
MessageHandler.errorln(
@@ -117,20 +160,31 @@ public class ConfigurationParser extends DefaultHandler {
}
status = OUT;
role = "standard";
- key = "";
- value = "";
- } else if (localName.equals("subentry")) {
- map.put(subkey, value);
- status -= IN_SUBENTRY;
- key = "";
- value = "";
- } else if (localName.equals("key")) {
- status -= IN_KEY;
- } else if (localName.equals("list")) {
- status -= IN_LIST;
- value = "";
- } else if (localName.equals("value")) {
- status -= IN_VALUE;
+ key = "";
+ value = "";
+ } else if (localName.equals("subentry")) {
+ map.put(subkey, value);
+ status -= IN_SUBENTRY;
+ key = "";
+ value = "";
+ } else if (localName.equals("key")) {
+ status -= IN_KEY;
+ } else if (localName.equals("list")) {
+ status -= IN_LIST;
+ value = "";
+ } else if (localName.equals("value")) {
+ status -= IN_VALUE;
+ } else if (localName.equals("fonts") ) {
+ this.store("standard", "fonts", fontList);
+ } else if (localName.equals("font") ) {
+ fontInfo = new FontInfo(fontName,metricsFile,kerning,fontTriplets,embedFile);
+ fontList.addElement(fontInfo);
+ fontTriplets = null;
+ metricsFile = null;
+ embedFile = null;
+ fontName = null;
+ kerningAsString = "";
+ } else if (localName.equals("font-triplet") ) {
}
}
diff --git a/src/org/apache/fop/configuration/ConfigurationReader.java b/src/org/apache/fop/configuration/ConfigurationReader.java
index 92d7c338a..edde15624 100644
--- a/src/org/apache/fop/configuration/ConfigurationReader.java
+++ b/src/org/apache/fop/configuration/ConfigurationReader.java
@@ -1,9 +1,53 @@
-/*
- * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
- * For details on use and redistribution please refer to the
- * LICENSE file included with these sources."
- */
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Fop" and "Apache Software Foundation" must not be used to
+ endorse or promote products derived from this software without prior
+ written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation and was originally created by
+ James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ Software Foundation, please see <http://www.apache.org/>.
+ */
package org.apache.fop.configuration;
@@ -31,7 +75,7 @@ import org.apache.fop.configuration.Configuration;
* }
* </code>
* Once the configuration has been setup, the information can be accessed with
- * the methods of Configuration.
+ * the methods of StandardConfiguration.
*/
public class ConfigurationReader {
@@ -103,7 +147,7 @@ public class ConfigurationReader {
*
* @return the created SAX parser
*/
- static XMLReader createParser() {
+ public static XMLReader createParser() {
String parserClassName = System.getProperty("org.xml.sax.parser");
if (parserClassName == null) {
parserClassName = "org.apache.xerces.parsers.SAXParser";
diff --git a/src/org/apache/fop/configuration/FontInfo.java b/src/org/apache/fop/configuration/FontInfo.java
new file mode 100644
index 000000000..07af6b12b
--- /dev/null
+++ b/src/org/apache/fop/configuration/FontInfo.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources."
+ */
+
+
+package org.apache.fop.configuration;
+
+import java.util.Vector;
+
+/**
+ * FontInfo contains meta information on fonts (where is the metrics file etc.)
+ */
+
+public class FontInfo {
+ private String metricsFile, embedFile, name;
+ private boolean kerning;
+ private Vector fontTriplets;
+
+ public FontInfo (String name, String metricsFile, boolean kerning,
+ Vector fontTriplets, String embedFile) {
+ this.name = name;
+ this.metricsFile = metricsFile;
+ this.embedFile = embedFile;
+ this.kerning = kerning;
+ this.fontTriplets = fontTriplets;
+ }
+
+ public String getMetricsFile() {
+ return metricsFile;
+ }
+ public String getEmbedFile() {
+ return embedFile;
+ }
+ public boolean getKerning() {
+ return kerning;
+ }
+ public Vector getFontTriplets() {
+ return fontTriplets;
+ }
+
+}
+
diff --git a/src/org/apache/fop/configuration/FontTriplet.java b/src/org/apache/fop/configuration/FontTriplet.java
new file mode 100644
index 000000000..d5e927d6f
--- /dev/null
+++ b/src/org/apache/fop/configuration/FontTriplet.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources."
+ */
+
+
+package org.apache.fop.configuration;
+
+/**
+ * FontTriplet contains information on name, weight, style of one font
+ */
+
+
+public class FontTriplet {
+ private String name, weight, style;
+ public FontTriplet(String name, String weight, String style) {
+ this.name = name;
+ this.weight = weight;
+ this.style = style;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getWeight() {
+ return weight;
+ }
+
+ public String getStyle() {
+ return style;
+ }
+
+}
+
+
+
+
diff --git a/src/org/apache/fop/fonts/Glyphs.java b/src/org/apache/fop/fonts/Glyphs.java
index cba61bcdb..99fc076e3 100644
--- a/src/org/apache/fop/fonts/Glyphs.java
+++ b/src/org/apache/fop/fonts/Glyphs.java
@@ -604,7 +604,254 @@ public class Glyphs {
"yacute",
"thorn",
"ydieresis"};
-
+
+ /** The characters in WinAnsiEncoding */
+ public static char[] winAnsiEncoding = {
+ // not used until char 32
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ // 0x20
+ ' ',
+ '\u0021',
+ '\"',
+ '\u0023',
+ '$',
+ '%',
+ '&',
+ '\'',
+ '(',
+ ')',
+ '*',
+ '+',
+ ',',
+ '\u002d',
+ '\u002e',
+ '/',
+ // 0x30
+ '0',
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ ':',
+ ';',
+ '<',
+ '=',
+ '>',
+ '?',
+ '@',
+ // 0x40
+ 'A',
+ 'B',
+ 'C',
+ 'D',
+ 'E',
+ 'F',
+ 'G',
+ 'H',
+ 'I',
+ 'J',
+ 'K',
+ 'L',
+ 'M',
+ 'N',
+ 'O',
+ // 0x50
+ 'P',
+ 'Q',
+ 'R',
+ 'S',
+ 'T',
+ 'U',
+ 'V',
+ 'W',
+ 'X',
+ 'Y',
+ 'Z',
+ '\u005b',
+ '\\',
+ '\u005d',
+ '\u005e',
+ '_',
+ // 0x60
+ '\u2018',
+ 'a',
+ 'b',
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ 'g',
+ 'h',
+ 'i',
+ 'j',
+ 'k',
+ 'l',
+ 'm',
+ 'n',
+ 'o',
+ // 0x70
+ 'p',
+ 'q',
+ 'r',
+ 's',
+ 't',
+ 'u',
+ 'v',
+ 'w',
+ 'x',
+ 'y',
+ 'z',
+ '\u007b',
+ '\u007c',
+ '\u007d',
+ '\u007e',
+ '\u2022',
+ // 0x80
+ '\u20ac',
+ '\u2022',
+ '\u201a',
+ '\u0192',
+ '\u201e',
+ '\u2026',
+ '\u2020',
+ '\u2021',
+ '\u02c6',
+ '\u2030',
+ '\u0160',
+ '\u2039',
+ '\u0152',
+ '\u2022',
+ '\u017d',
+ '\u2022',
+ // 0x90
+ '\u2022',
+ '\u2018', // quoteleft
+ '\u2019', // quoteright
+ '\u201c', // quotedblleft
+ '\u201d', // quotedblright
+ '\u2022', // bullet
+ '\u2013', // endash
+ '\u2014', // emdash
+ '~',
+ '\u2022', // bullet
+ '\u0161',
+ '\u203a',
+ '\u0153',
+ '\u2022',
+ '\u017e',
+ '\u0178',
+ // 0xA0
+ ' ',
+ '\u00a1',
+ '\u00a2',
+ '£',
+ '\u00a4',
+ '\u00a5',
+ '\u00a6',
+ '\u00a7',
+ '\u00a8',
+ '\u00a9',
+ '\u00aa',
+ '\u00ab',
+ '\u00ac',
+ '\u00ad',
+ '\u00ae',
+ '\u00af',
+ // 0xb0
+ '\u00b0',
+ '\u00b1',
+ '\u00b2',
+ '\u00b3',
+ '\u00b4',
+ '\u00b5', // This is hand-coded, the rest is assumption
+ '\u00b6', // and *might* not be correct...
+ '\u00b7',
+ '\u00b8',
+ '\u00b9',
+ '\u00ba',
+ '\u00bb',
+ '\u00bc',
+ '\u00bd',
+ '\u00be',
+ '\u00bf',
+ // 0xc0
+ '\u00c0',
+ '\u00c1',
+ '\u00c2',
+ '\u00c3',
+ '\u00c4',
+ '\u00c5', // Aring
+ '\u00c6', // AE
+ '\u00c7',
+ '\u00c8',
+ '\u00c9',
+ '\u00ca',
+ '\u00cb',
+ '\u00cc',
+ '\u00cd',
+ '\u00ce',
+ '\u00cf',
+ // 0xd0
+ '\u00d0',
+ '\u00d1',
+ '\u00d2',
+ '\u00d3',
+ '\u00d4',
+ '\u00d5',
+ '\u00d6',
+ '\u00d7',
+ '\u00d8', // Oslash
+ '\u00d9',
+ '\u00da',
+ '\u00db',
+ '\u00dc',
+ '\u00dd',
+ '\u00de',
+ '\u00df',
+ // 0xe0
+ '\u00e0',
+ '\u00e1',
+ '\u00e2',
+ '\u00e3',
+ '\u00e4',
+ '\u00e5', // aring
+ '\u00e6', // ae
+ '\u00e7',
+ '\u00e8',
+ '\u00e9',
+ '\u00ea',
+ '\u00eb',
+ '\u00ec',
+ '\u00ed',
+ '\u00ee',
+ '\u00ef',
+ // 0xf0
+ '\u00f0',
+ '\u00f1',
+ '\u00f2',
+ '\u00f3',
+ '\u00f4',
+ '\u00f5',
+ '\u00f6',
+ '\u00f7',
+ '\u00f8',
+ '\u00f9',
+ '\u00fa',
+ '\u00fb',
+ '\u00fc',
+ '\u00fd',
+ '\u00fe',
+ '\u00ff'
+ };
+
static String[] unicode_glyphs={
"\u0041", "A",
"\u00C6", "AE",
diff --git a/src/org/apache/fop/fonts/PFMFile.java b/src/org/apache/fop/fonts/PFMFile.java
index 5ebb011cc..f1cae42d3 100644
--- a/src/org/apache/fop/fonts/PFMFile.java
+++ b/src/org/apache/fop/fonts/PFMFile.java
@@ -203,11 +203,11 @@ public class PFMFile {
String glyph1=Glyphs.tex8r[g1];
String glyph2=Glyphs.tex8r[g2];
- Hashtable adjTab=(Hashtable)kerningTab.get(glyph1);
+ Hashtable adjTab=(Hashtable)kerningTab.get(new Integer(g1));
if (adjTab==null)
adjTab=new Hashtable();
- adjTab.put(glyph2, new Integer(adj));
- kerningTab.put(glyph1, adjTab);
+ adjTab.put(new Integer(g2), new Integer(adj));
+ kerningTab.put(new Integer(g1), adjTab);
}
}
diff --git a/src/org/apache/fop/fonts/TTFCmapEntry.java b/src/org/apache/fop/fonts/TTFCmapEntry.java
index af1eb5c00..3e8dd746a 100644
--- a/src/org/apache/fop/fonts/TTFCmapEntry.java
+++ b/src/org/apache/fop/fonts/TTFCmapEntry.java
@@ -50,11 +50,38 @@
*/
package org.apache.fop.fonts;
-class TTFCmapEntry {
- int platform_id;
- int encoding_id;
- long offset;
-
- TTFCmapEntry() {
- }
+/**
+ * The CMap entry contains information of a Unicode range and the
+ * the glyph indexes related to the range
+ */
+public class TTFCmapEntry {
+ public int unicodeStart;
+ public int unicodeEnd;
+ public int glyphStartIndex;
+
+ TTFCmapEntry() {
+ unicodeStart = 0;
+ unicodeEnd = 0;
+ glyphStartIndex = 0;
+ }
+
+ TTFCmapEntry (int unicodeStart,
+ int unicodeEnd,
+ int glyphStartIndex) {
+ this.unicodeStart = unicodeStart;
+ this.unicodeEnd = unicodeEnd;
+ this.glyphStartIndex = glyphStartIndex;
+ }
+
+ public boolean equals (Object o) {
+ if (o instanceof TTFCmapEntry) {
+ TTFCmapEntry ce = (TTFCmapEntry)o;
+ if (ce.unicodeStart == this.unicodeStart &&
+ ce.unicodeEnd == this.unicodeEnd &&
+ ce.glyphStartIndex == this.glyphStartIndex)
+ return true;
+ }
+ return false;
+ }
+
}
diff --git a/src/org/apache/fop/fonts/TTFDirTabEntry.java b/src/org/apache/fop/fonts/TTFDirTabEntry.java
index 42fed9f3a..30f0c4cfe 100644
--- a/src/org/apache/fop/fonts/TTFDirTabEntry.java
+++ b/src/org/apache/fop/fonts/TTFDirTabEntry.java
@@ -52,34 +52,36 @@ package org.apache.fop.fonts;
import java.io.*;
class TTFDirTabEntry {
- byte[] tag;
- int checksum;
- long offset;
- long length;
-
- TTFDirTabEntry() {
- tag = new byte[4];
- }
-
- /** Read Dir Tab, return tag name */
- public String read(FontFileReader in) throws IOException {
- tag[0]=in.readTTFByte();
- tag[1]=in.readTTFByte();
- tag[2]=in.readTTFByte();
- tag[3]=in.readTTFByte();
-
- in.skip(4); // Skip checksum
-
- offset=in.readTTFULong();
- length=in.readTTFULong();
-
- System.out.println ("Read dir tab [" + tag[0]+
- " "+tag[1] +
- " "+tag[2] +
- " "+tag[3] +
- "] offset: " + offset +
- " length: " + length +
- " name: " + new String(tag));
- return new String(tag, "ISO-8859-1");
- }
+ byte[] tag;
+ int checksum;
+ long offset;
+ long length;
+
+ TTFDirTabEntry() {
+ tag = new byte[4];
+ }
+
+ /** Read Dir Tab, return tag name */
+ public String read(FontFileReader in) throws IOException {
+ tag[0]=in.readTTFByte();
+ tag[1]=in.readTTFByte();
+ tag[2]=in.readTTFByte();
+ tag[3]=in.readTTFByte();
+
+ in.skip(4); // Skip checksum
+
+ offset=in.readTTFULong();
+ length=in.readTTFULong();
+
+ /*
+ System.out.println ("Read dir tab [" + tag[0]+
+ " "+tag[1] +
+ " "+tag[2] +
+ " "+tag[3] +
+ "] offset: " + offset +
+ " length: " + length +
+ " name: " + new String(tag));
+ */
+ return new String(tag, "ISO-8859-1");
+ }
}
diff --git a/src/org/apache/fop/fonts/TTFFile.java b/src/org/apache/fop/fonts/TTFFile.java
index 06987e77a..02c49bfe1 100644
--- a/src/org/apache/fop/fonts/TTFFile.java
+++ b/src/org/apache/fop/fonts/TTFFile.java
@@ -50,274 +50,823 @@
*/
package org.apache.fop.fonts;
import java.io.*;
+import java.util.Enumeration;
import java.util.Hashtable;
+import java.util.Vector;
+/**
+ * Reads a TrueType file or a TrueType Collection.
+ * The TrueType spec can be found at the Microsoft
+ * Typography site: http://www.microsoft.com/truetype/
+ */
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;
-
- boolean is_embeddable=true;
- boolean hasSerifs=true;
- Hashtable dirTabs;
- Hashtable kerningTab;
-
- /** Position inputstream to position indicated
- in the dirtab offset + offset */
- void seek_tab(FontFileReader in, String name, long offset)
- throws IOException {
- TTFDirTabEntry dt=(TTFDirTabEntry)dirTabs.get(name);
- if (dt==null) {
- System.out.println("Dirtab " + name + " not found.");
- return;
- }
-
- in.seek_set(dt.offset+offset);
- }
-
- int get_ttf_funit(int n) {
- int ret;
- if (n < 0) {
- long rest1=n % upem;
- long storrest=1000*rest1;
- long ledd2=rest1/storrest;
- ret = -((-1000*n)/upem - (int)ledd2);
- } else {
- ret = (n/upem)*1000 + ((n % upem)*1000)/upem;
- }
-
- return ret;
- }
-
- int upem;
- int ntabs;
- int nhmtx;
- int post_format;
- int loca_format;
- int nglyphs;
- int nmglyphs;
- int names_count;
-
-
-
- TTFDirTabEntry dir_tab;
- TTFMtxEntry mtx_tab[];
- int[] mtx_encoded=null;
- boolean reencoded=false;
- String enc_names;
-
- String fontName="";
- String fullName="";
- String notice="";
- String familyName="";
- String subFamilyName="";
-
- long italicAngle = 0;
- long isFixedPitch = 0;
- int fontBBox1 = 0;
- int fontBBox2 = 0;
- int fontBBox3 = 0;
- int fontBBox4 = 0;
- int capHeight = 0;
- int underlinePosition = 0;
- int underlineThickness = 0;
- int xHeight = 0;
- int ascender = 0;
- int descender = 0;
-
- public void readFont(FontFileReader in) throws IOException {
- int i, j, k, l, platform_id, encoding_id, language_id;
- long n;
- TTFDirTabEntry[] pd;
- TTFMtxEntry[] pm;
- String[] ps_glyphs_buf;
-
- in.skip(4); // TTF_FIXED_SIZE
- ntabs=in.readTTFUShort();
- in.skip(6); // 3xTTF_USHORT_SIZE;
-
- // Read Dir tabs
- dirTabs=new Hashtable();
- pd=new TTFDirTabEntry[ntabs];
- //System.out.println("Reading " + ntabs + " dir tables");
- for (i=0; i < ntabs; i++) {
- pd[i]=new TTFDirTabEntry();
- dirTabs.put(pd[i].read(in),
- pd[i]);
- }
-
- seek_tab(in, "head", 2*4 + 2*4 + 2);
- upem=in.readTTFUShort();
-
- in.skip(16);
-
- fontBBox1=in.readTTFShort();
- fontBBox2=in.readTTFShort();
- fontBBox3=in.readTTFShort();
- fontBBox4=in.readTTFShort();
-
- in.skip(2+2+2);
-
- loca_format=in.readTTFShort();
-
- seek_tab(in, "maxp", 4);
- nglyphs=in.readTTFUShort();
- //System.out.println("nglyphs= " + nglyphs);
- mtx_tab=new TTFMtxEntry[nglyphs];
-
- for (i=0; i < nglyphs; i++)
- mtx_tab[i]=new TTFMtxEntry();
-
- seek_tab(in, "hhea", 4);
- ascender=in.readTTFShort(); // Use sTypoAscender in "OS/2" table?
- descender=in.readTTFShort(); // Use sTypoDescender in "OS/2" table?
-
- in.skip(2+2+3*2+8*2);
- nhmtx=in.readTTFUShort();
- //System.out.println("nhmtx: " + nhmtx);
- seek_tab(in, "hmtx", 0);
- for (i=0; i < nhmtx; i++) {
- mtx_tab[i].wx=in.readTTFUShort();
- in.skip(2);
- }
- // NB: Her skal det settes mer wx.
-
- seek_tab(in, "post", 0);
- post_format=in.readTTFLong();
- italicAngle=in.readTTFULong();
- //System.out.println("Italic angle: " + italicAngle);
- underlinePosition=in.readTTFShort();
- underlineThickness=in.readTTFShort();
- isFixedPitch=in.readTTFULong();
-
- in.skip(4*4);
-
- switch (post_format) {
- case 0x00010000:
- //System.out.println("Postscript format 1");
- for (i=0; i<Glyphs.mac_glyph_names.length; i++) {
- mtx_tab[i].name=Glyphs.mac_glyph_names[i];
- }
- break;
- case 0x00020000:
- //System.out.println("Postscript format 2");
- l = in.readTTFUShort();
- for (i=0; i < l ; i++) {
- mtx_tab[i].index=in.readTTFUShort();
- }
-
- TTFDirTabEntry dirTab=
- (TTFDirTabEntry)dirTabs.get("post");
- if (dirTab==null)
- System.out.println("Can't find table 'post'");
-
- n=dirTab.length - (in.getCurrentPos() - dirTab.offset);
- ps_glyphs_buf=new String[(int)n];
- int nn=(ps_glyphs_buf.length < nglyphs) ?
- ps_glyphs_buf.length : nglyphs;
- //System.out.println("Reading " + n + " glyphnames");
- for (i=0; i < nn; i++) {
- ps_glyphs_buf[i]=in.readTTFString(in.readTTFUByte());
- }
-
- for (i=0; i < l; i++) {
- if (mtx_tab[i].index < NMACGLYPHS) {
- mtx_tab[i].name = Glyphs.mac_glyph_names[mtx_tab[i].index];
- } else {
- k = mtx_tab[i].index - NMACGLYPHS ;
- mtx_tab[i].name=ps_glyphs_buf[k];
+ static final byte NTABS = 24;
+ static final int NMACGLYPHS = 258;
+ static final int MAX_CHAR_CODE = 255;
+ static final int ENC_BUF_SIZE = 1024;
+
+ static String encoding="WinAnsiEncoding"; // Deafult encoding
+ short firstChar=0;
+ boolean is_embeddable=true;
+ boolean hasSerifs=true;
+ Hashtable dirTabs; // Table directory
+ Hashtable kerningTab; // for CIDs
+ Hashtable ansiKerningTab; // For winAnsiEncoding
+ Vector cmaps;
+ Vector unicodeMapping; //
+
+ int upem; // unitsPerEm from "head" table
+ int nhmtx; // Number of horizontal metrics
+ int post_format;
+ int loca_format;
+ int nglyphs; // Number of glyphs in font (read from "maxp" table)
+ int nmglyphs; // Used in fixWidths - remove?
+
+ TTFMtxEntry mtx_tab[]; // Contains glyph data
+ int[] mtx_encoded=null;
+
+ String fontName="";
+ String fullName="";
+ String notice="";
+ String familyName="";
+ String subFamilyName="";
+
+ long italicAngle = 0;
+ long isFixedPitch = 0;
+ int fontBBox1 = 0;
+ int fontBBox2 = 0;
+ int fontBBox3 = 0;
+ int fontBBox4 = 0;
+ int capHeight = 0;
+ int underlinePosition = 0;
+ int underlineThickness = 0;
+ int xHeight = 0;
+ int ascender = 0;
+ int descender = 0;
+
+ short lastChar = 0;
+
+ int ansiWidth[];
+ Hashtable ansiIndex;
+
+ /** Position inputstream to position indicated
+ in the dirtab offset + offset */
+ void seek_tab(FontFileReader in, String name, long offset)
+ throws IOException {
+ TTFDirTabEntry dt=(TTFDirTabEntry)dirTabs.get(name);
+ if (dt==null) {
+ System.out.println("Dirtab " + name + " not found.");
+ return;
+ }
+
+ in.seek_set(dt.offset+offset);
+ }
+
+ /** Convert from truetype unit to pdf unit based on the
+ * unitsPerEm field in the "head" table
+ @param n truetype unit
+ @return pdf unit
+ */
+ int get_ttf_funit(int n) {
+ int ret;
+ if (n < 0) {
+ long rest1=n % upem;
+ long storrest=1000*rest1;
+ long ledd2=rest1/storrest;
+ ret = -((-1000*n)/upem - (int)ledd2);
+ } else {
+ ret = (n/upem)*1000 + ((n % upem)*1000)/upem;
+ }
+
+ return ret;
+ }
+
+ /** Read the cmap table,
+ * return false if the table is not present or only unsupported
+ * tables are present. Currently only unicode cmaps are supported.
+ * Set the unicodeIndex in the TTFMtxEntries and fills in the
+ * cmaps vector.
+ */
+ private boolean readCMAP(FontFileReader in)
+ throws IOException {
+
+ unicodeMapping = new Vector();
+
+ /** Read CMAP table and correct mtx_tab.index*/
+ int mtxPtr=0;
+
+ seek_tab(in, "cmap", 2);
+ int num_cmap=in.readTTFUShort(); // Number of cmap subtables
+ long cmap_unioffset=0;
+
+ //System.out.println(num_cmap+" cmap tables");
+
+ /* Read offset for all tables
+ We are only interested in the unicode table
+ */
+ for (int i=0; i< num_cmap; i++) {
+ int cmap_pid=in.readTTFUShort();
+ int cmap_eid=in.readTTFUShort();
+ long cmap_offset=in.readTTFULong();
+
+ //System.out.println("Platform ID: "+cmap_pid+
+ // " Encoding: "+cmap_eid);
+
+ if (cmap_pid==3 && cmap_eid==1)
+ cmap_unioffset=cmap_offset;
+ }
+
+ if (cmap_unioffset <= 0) {
+ System.out.println("Unicode cmap table not present");
+ return false;
+ }
+
+ // Read unicode cmap
+ seek_tab(in, "cmap", cmap_unioffset);
+ int cmap_format=in.readTTFUShort();
+ int cmap_length=in.readTTFUShort();
+
+ //System.out.println("CMAP format: "+cmap_format);
+ if (cmap_format==4) {
+ in.skip(2); // Skip version number
+ int cmap_segCountX2=in.readTTFUShort();
+ int cmap_searchRange=in.readTTFUShort();
+ int cmap_entrySelector=in.readTTFUShort();
+ int cmap_rangeShift=in.readTTFUShort();
+
+ /*
+ System.out.println("segCountX2 : "+cmap_segCountX2);
+ System.out.println("searchRange : "+cmap_searchRange);
+ System.out.println("entrySelector: "+cmap_entrySelector);
+ System.out.println("rangeShift : "+cmap_rangeShift);
+ */
+
+ int cmap_endCounts[]=new int[cmap_segCountX2/2];
+ int cmap_startCounts[]=new int[cmap_segCountX2/2];
+ int cmap_deltas[]=new int[cmap_segCountX2/2];
+ int cmap_rangeOffsets[]=new int[cmap_segCountX2/2];
+
+ for (int i=0; i < (cmap_segCountX2/2); i++) {
+ cmap_endCounts[i]=in.readTTFUShort();
+ }
+
+ in.skip(2); // Skip reservedPad
+
+ for (int i=0; i < (cmap_segCountX2/2); i++) {
+ cmap_startCounts[i]=in.readTTFUShort();
+ }
+
+ for (int i=0; i < (cmap_segCountX2/2); i++) {
+ cmap_deltas[i]=in.readTTFShort();
+ }
+
+ int startRangeOffset=in.getCurrentPos();
+
+ for (int i=0; i < (cmap_segCountX2/2); i++) {
+ cmap_rangeOffsets[i]=in.readTTFShort();
+ }
+
+ int glyphIdArrayOffset=in.getCurrentPos();
+
+ // Insert the unicode id for the glyphs in mtx_tab
+ // and fill in the cmaps Vector
+
+ for (int i = 0; i < cmap_startCounts.length; i++) {
+ /*
+ System.out.println(i+ ": "+cmap_startCounts[i]+
+ " - "+cmap_endCounts[i]);
+ */
+ for (int j=cmap_startCounts[i];
+ j <= cmap_endCounts[i]; j++) {
+
+ // Update lastChar
+ if (j < 256 && j > lastChar)
+ lastChar = (short)j;
+
+ if (mtxPtr < mtx_tab.length) {
+ if (cmap_rangeOffsets[i] != 0) {
+ int glyphOffset = glyphIdArrayOffset+
+ ((cmap_rangeOffsets[i]/2)+
+ (j-cmap_startCounts[i])+
+ (i)-
+ cmap_segCountX2/2)*2;
+ in.seek_set(glyphOffset);
+ int glyphIdx=(in.readTTFUShort()+
+ cmap_deltas[i]) & 0xffff;
+
+ unicodeMapping.addElement(
+ new UnicodeMapping(glyphIdx, j));
+ mtx_tab[glyphIdx].unicodeIndex.addElement(new Integer(j));
+
+
+ // Also add winAnsiWidth
+ if (false) {
+ int d = j;
+ if (j > 127)
+ d = (int)
+ org.apache.fop.render.pdf.CodePointMapping.map[j];
+ if (d < ansiWidth.length)
+ ansiWidth[d] = mtx_tab[glyphIdx].wx;
+ } else {
+ Vector v=
+ (Vector)ansiIndex.get(new Integer(j));
+ if (v != null) {
+ for (Enumeration e=v.elements();
+ e.hasMoreElements();) {
+ Integer aIdx = (Integer)e.nextElement();
+ ansiWidth[aIdx.intValue()]=
+ mtx_tab[glyphIdx].wx;
+ /*
+ System.out.println("Added width "+
+ mtx_tab[glyphIdx].wx +
+ " uni: " + j +
+ " ansi: " + aIdx.intValue());
+ */
+ }
+ }
+ }
+ /*
+ System.out.println("Idx: "+
+ glyphIdx +
+ " Delta: " + cmap_deltas[i]+
+ " Unicode: " + j +
+ " name: " +
+ mtx_tab[glyphIdx].name);
+ */
+
+ } else {
+ int glyphIdx=(j+cmap_deltas[i]) & 0xffff;
+
+ mtx_tab[glyphIdx].unicodeIndex.addElement(new Integer(j));
+
+ unicodeMapping.addElement(
+ new UnicodeMapping(glyphIdx,
+ j));
+
+ // Also add winAnsiWidth
+ if (false) {
+ int d = j;
+ if (j > 127)
+ d = (int)
+ org.apache.fop.render.pdf.CodePointMapping.map[j];
+
+ if (d < ansiWidth.length)
+ ansiWidth[d] = mtx_tab[glyphIdx].wx;
+ } else {
+ Vector v=
+ (Vector)ansiIndex.get(new Integer(j));
+ if (v != null) {
+ for (Enumeration e=v.elements();
+ e.hasMoreElements();) {
+ Integer aIdx = (Integer)e.nextElement();
+ ansiWidth[aIdx.intValue()]=
+ mtx_tab[glyphIdx].wx;
+ }
+ }
+ }
+
+ /*
+ System.out.println("IIdx: "+
+ mtxPtr +
+ " Delta: " + cmap_deltas[i]+
+ " Unicode: " + j +
+ " name: " +
+ mtx_tab[(j+cmap_deltas[i]) & 0xffff].name);
+ */
+ }
+ mtxPtr++;
+ }
}
- }
-
- break;
- case 0x00030000:
- //System.out.println("Postscript format 3 - index");
- break;
- default:
- //System.out.println("Unknown format : " + post_format);
- }
-
- // Check if font is embeddable
- if (dirTabs.get("OS/2") != null) {
- seek_tab(in, "OS/2", 2*4);
- int fsType=in.readTTFUShort();
- if ((fsType & 2) == 0)
- is_embeddable=false;
- else
+ }
+ }
+ return true;
+ }
+
+
+
+ /**
+ * Print first char/last char
+ */
+ private void print_max_min() {
+ int min=255;
+ int max=0;
+ for (int i=0; i < mtx_tab.length; i++) {
+ if (mtx_tab[i].index < min)
+ min = mtx_tab[i].index;
+ if (mtx_tab[i].index > max)
+ max = mtx_tab[i].index;
+ }
+ System.out.println("Min: "+min);
+ System.out.println("Max: "+max);
+ }
+
+ public void readFont(FontFileReader in) throws IOException {
+ readFont(in, (String)null);
+ }
+
+ /** initialize the ansiWidths array (for winAnsiEncoding)
+ * and fill with the missingwidth
+ */
+ private void initAnsiWidths() {
+ ansiWidth=new int[256];
+ for (int i = 0; i < 256; i++)
+ ansiWidth[i] = mtx_tab[0].wx;
+
+ // 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 Hashtable();
+ for (int i=32; i < Glyphs.winAnsiEncoding.length; i++) {
+ Integer ansi = new Integer(i);
+ Integer uni = new Integer((int)Glyphs.winAnsiEncoding[i]);
+
+ Vector v = (Vector)ansiIndex.get(uni);
+ if (v == null) {
+ v = new Vector();
+ ansiIndex.put(uni, v);
+ }
+ v.addElement(ansi);
+ }
+ }
+
+
+ /**
+ * Read the font data
+ * If the fontfile is a TrueType Collection (.ttf file)
+ * The name of the font to read data for must be supplied,
+ * else the name is ignored
+ */
+ public void readFont(FontFileReader in, String name) throws IOException {
+
+ /* Check if TrueType collection, and that the name
+ exists in the collection
+ */
+ if (!checkTTC(in, name))
+ throw new IOException("Failed to read font");
+
+ readDirTabs(in);
+ readFontHeader(in);
+ readHorizontalHeader(in);
+ readHorizontalMetrics(in);
+ initAnsiWidths();
+ readPostscript(in);
+ readOS2(in);
+ readIndexToLocation(in);
+ readGlyf(in);
+ readName(in);
+ readPCLT(in);
+ readCMAP(in); // Read cmap table and fill in ansiwidths
+ createCMaps(); // Create cmaps for bfentries
+ //print_max_min();
+
+ readKerning(in);
+ }
+
+ private void createCMaps() {
+ cmaps = new Vector();
+ TTFCmapEntry tce = new TTFCmapEntry();
+
+ Enumeration e = unicodeMapping.elements();
+ UnicodeMapping um = (UnicodeMapping)e.nextElement();
+ UnicodeMapping lastMapping = um;
+
+ tce.unicodeStart = um.uIdx;
+ tce.glyphStartIndex = um.gIdx;
+
+ while (e.hasMoreElements()) {
+ um = (UnicodeMapping)e.nextElement();
+ if (((lastMapping.uIdx+1) != um.uIdx) ||
+ ((lastMapping.gIdx+1) != um.gIdx)) {
+ tce.unicodeEnd = lastMapping.uIdx;
+ cmaps.addElement(tce);
+
+ tce = new TTFCmapEntry();
+ tce.unicodeStart = um.uIdx;
+ tce.glyphStartIndex = um.gIdx;
+ }
+ lastMapping = um;
+ }
+
+ tce.unicodeEnd = um.uIdx;
+ cmaps.addElement(tce);
+ }
+
+ public void printStuff() {
+ System.out.println("Font name: " + fontName);
+ System.out.println("Full name: " + fullName);
+ System.out.println("Family name: " + familyName);
+ System.out.println("Subfamily name: " + subFamilyName);
+ System.out.println("Notice: " + notice);
+ System.out.println("xHeight: " + (int)get_ttf_funit(xHeight));
+ System.out.println("capheight: " + (int)get_ttf_funit(capHeight));
+
+ int italic=(int)(italicAngle>>16);
+ System.out.println("Italic: " + italic);
+ System.out.print("ItalicAngle: " + (short)(italicAngle/0x10000));
+ if ((italicAngle % 0x10000) > 0 )
+ System.out.print("."+(short)((italicAngle % 0x10000)*1000)/0x10000);
+ System.out.println();
+ System.out.println("Ascender: " + get_ttf_funit(ascender));
+ System.out.println("Descender: " + get_ttf_funit(descender));
+ System.out.println("FontBBox: [" + (int)get_ttf_funit(fontBBox1) +
+ " " + (int)get_ttf_funit(fontBBox2) +
+ " " + (int)get_ttf_funit(fontBBox3) +
+ " " + (int)get_ttf_funit(fontBBox4)+"]");
+ }
+
+ public static void main(String[] args) {
+ try {
+ TTFFile ttfFile=new TTFFile();
+ FontFileReader reader=
+ new FontFileReader(args[0]);
+
+ String name=null;
+ if (args.length >= 2)
+ name=args[1];
+
+ ttfFile.readFont(reader, name);
+ ttfFile.printStuff();
+
+ } catch (IOException ioe) {
+ System.out.println(ioe.toString());
+ }
+ }
+
+ public String getWindowsName() {
+ return new String(familyName+","+subFamilyName);
+ }
+
+ public String getPostscriptName() {
+ if ("Regular".equals(subFamilyName) ||
+ "Roman".equals(subFamilyName))
+ return familyName;
+ else
+ return familyName+","+subFamilyName;
+ }
+ public String getFamilyName() {
+ return familyName;
+ }
+ public String getCharSetName() {
+ return encoding;
+ }
+ public int getCapHeight() {
+ return (int)get_ttf_funit(capHeight);
+ }
+ public int getXHeight() {
+ return (int)get_ttf_funit(xHeight);
+ }
+
+ public int getFlags() {
+ int flags=32; // Use Adobe Standard charset
+ if (italicAngle != 0)
+ flags = flags | 64;
+ if (isFixedPitch != 0)
+ flags = flags | 2;
+ if (hasSerifs)
+ flags = flags | 1;
+ return flags;
+ }
+
+
+ public String getStemV() {
+ return "0";
+ }
+
+ public String getItalicAngle() {
+ String ia=Short.toString((short)(italicAngle/0x10000));
+ if ((italicAngle % 0x10000) > 0 )
+ ia=ia+("."+Short.toString((short)((short)((italicAngle % 0x10000)*1000)/0x10000)));
+
+ return ia;
+ }
+
+ public int[] getFontBBox() {
+ int[] fbb=new int[4];
+ fbb[0]=(int)get_ttf_funit(fontBBox1);
+ fbb[1]=(int)get_ttf_funit(fontBBox2);
+ fbb[2]=(int)get_ttf_funit(fontBBox3);
+ fbb[3]=(int)get_ttf_funit(fontBBox4);
+
+ return fbb;
+ }
+
+ public int getLowerCaseAscent() {
+ return (int)get_ttf_funit(ascender);
+ }
+
+ public int getLowerCaseDescent() {
+ return (int)get_ttf_funit(descender);
+ }
+
+ // This is only for WinAnsiEncoding, so the last char is
+ // the last char < 256
+ public short getLastChar() {
+ return lastChar;
+ }
+
+ public short getFirstChar() {
+ return firstChar;
+ }
+
+ public int[] getWidths() {
+ int[] wx = new int[mtx_tab.length];
+ for (int i = 0; i < wx.length; i++)
+ wx[i] = (int)get_ttf_funit(mtx_tab[i].wx);
+
+ return wx;
+ }
+
+ public int getCharWidth(int idx) {
+ return (int)get_ttf_funit(ansiWidth[idx]);
+ }
+
+ public Hashtable getKerning() {
+ return kerningTab;
+ }
+
+ public Hashtable getAnsiKerning() {
+ return ansiKerningTab;
+ }
+
+ public boolean isEmbeddable() {
+ return is_embeddable;
+ }
+
+
+ /**
+ * Read Table Directory from the current position in the
+ * FontFileReader and fill the global Hashtable dirTabs
+ * with the table name (String) as key and a TTFDirTabEntry
+ * as value.
+ */
+ private void readDirTabs(FontFileReader in) throws IOException {
+ in.skip(4); // TTF_FIXED_SIZE
+ int ntabs=in.readTTFUShort();
+ in.skip(6); // 3xTTF_USHORT_SIZE
+
+ dirTabs=new Hashtable();
+ TTFDirTabEntry[] pd=new TTFDirTabEntry[ntabs];
+ //System.out.println("Reading " + ntabs + " dir tables");
+ for (int i=0; i < ntabs; i++) {
+ pd[i]=new TTFDirTabEntry();
+ dirTabs.put(pd[i].read(in),
+ pd[i]);
+ }
+ }
+
+ /**
+ * Read the "head" table, this reads the bounding box and
+ * sets the upem (unitsPerEM) variable
+ */
+ private void readFontHeader(FontFileReader in) throws IOException {
+ seek_tab(in, "head", 2*4 + 2*4 + 2);
+ upem=in.readTTFUShort();
+
+ in.skip(16);
+
+ fontBBox1=in.readTTFShort();
+ fontBBox2=in.readTTFShort();
+ fontBBox3=in.readTTFShort();
+ fontBBox4=in.readTTFShort();
+
+ in.skip(2+2+2);
+
+ loca_format=in.readTTFShort();
+ }
+
+ /**
+ * Read the number of glyphs from the "maxp" table
+ */
+ private void getNumGlyphs(FontFileReader in) throws IOException {
+ seek_tab(in, "maxp", 4);
+ nglyphs=in.readTTFUShort();
+ System.out.println("Number of glyphs in font: " + nglyphs);
+ }
+
+
+ /** Read the "hhea" table to find the ascender and descender and
+ * size of "hmtx" table, i.e. a fixed size font might have only
+ * one width
+ */
+ private void readHorizontalHeader(FontFileReader in) throws IOException {
+ seek_tab(in, "hhea", 4);
+ ascender=in.readTTFShort(); // Use sTypoAscender in "OS/2" table?
+ descender=in.readTTFShort(); // Use sTypoDescender in "OS/2" table?
+
+ in.skip(2+2+3*2+8*2);
+ nhmtx=in.readTTFUShort();
+ //System.out.println("Number of horizontal metrics: " + nhmtx);
+ }
+
+ /**
+ * Read "hmtx" table and put the horizontal metrics
+ * in the mtx_tab array. If the number of metrics is less
+ * than the number of glyphs (eg fixed size fonts), extend
+ * the mtx_tab array and fill in the missing widths
+ */
+ private void readHorizontalMetrics(FontFileReader in) throws IOException {
+ seek_tab(in, "hmtx", 0);
+
+ int mtx_size=(nglyphs > nhmtx) ? nglyphs : nhmtx;
+ mtx_tab=new TTFMtxEntry[mtx_size];
+
+ //System.out.println("*** Widths array: \n");
+ for (int i=0; i < mtx_size; i++)
+ mtx_tab[i]=new TTFMtxEntry();
+ for (int i=0; i < nhmtx; i++) {
+ mtx_tab[i].wx=in.readTTFUShort();
+ /*
+ System.out.println(" width["+i+"] = "+
+ get_ttf_funit(mtx_tab[i].wx)+";");
+ */
+ in.skip(2); // Skip left side bearing
+ }
+
+ if (nhmtx < mtx_size) {
+ // Fill in the missing widths
+ int lastWidth=mtx_tab[nhmtx-1].wx;
+ for (int i=nhmtx; i < mtx_size; i++) {
+ mtx_tab[i].wx=lastWidth;
+ }
+ }
+ }
+
+
+ /**
+ * Read the "post" table
+ * containing the postscript names of the glyphs.
+ */
+ private final void readPostscript(FontFileReader in) throws IOException {
+ String[] ps_glyphs_buf;
+ int i, k, l;
+
+ seek_tab(in, "post", 0);
+ post_format=in.readTTFLong();
+ italicAngle=in.readTTFULong();
+ underlinePosition=in.readTTFShort();
+ underlineThickness=in.readTTFShort();
+ isFixedPitch=in.readTTFULong();
+
+ in.skip(4*4);
+
+ //System.out.println("Post format: "+post_format);
+ switch (post_format) {
+ case 0x00010000:
+ //System.out.println("Postscript format 1");
+ for (i=0; i < Glyphs.mac_glyph_names.length; i++) {
+ mtx_tab[i].name=Glyphs.mac_glyph_names[i];
+ }
+ break;
+ case 0x00020000:
+ //System.out.println("Postscript format 2");
+ int numGlyphStrings=0;
+ l = in.readTTFUShort(); // Num Glyphs
+ //short minIndex=256;
+ for (i=0; i < l ; i++) { // Read indexes
+ mtx_tab[i].index=in.readTTFUShort();
+ //if (minIndex > mtx_tab[i].index)
+ //minIndex=(short)mtx_tab[i].index;
+
+ if (mtx_tab[i].index > 257)
+ numGlyphStrings++;
+
+ //System.out.println("Post index: "+mtx_tab[i].index);
+ }
+ //firstChar=minIndex;
+ ps_glyphs_buf=new String[numGlyphStrings];
+ //System.out.println("Reading " + numGlyphStrings +
+ // " glyphnames"+
+ // ", was n num glyphs="+l);
+ for (i=0; i < ps_glyphs_buf.length; i++) {
+ ps_glyphs_buf[i]=in.readTTFString(in.readTTFUByte());
+ }
+
+ for (i=0; i < l; i++) {
+ if (mtx_tab[i].index < NMACGLYPHS) {
+ mtx_tab[i].name = Glyphs.mac_glyph_names[mtx_tab[i].index];
+ } else {
+ k = mtx_tab[i].index - NMACGLYPHS ;
+ /*
+ System.out.println(k+" i="+i+" mtx="+mtx_tab.length+
+ " ps="+ps_glyphs_buf.length);
+ */
+ mtx_tab[i].name=ps_glyphs_buf[k];
+ }
+ }
+
+ break;
+ case 0x00030000:
+ // Postscript format 3 contains no glyph names
+ System.out.println("Postscript format 3");
+ break;
+ default:
+ System.out.println("Unknown Postscript format : " +
+ post_format);
+ }
+ }
+
+
+ /**
+ * Read the "OS/2" table
+ */
+ private final void readOS2(FontFileReader in) throws IOException {
+ // Check if font is embeddable
+ if (dirTabs.get("OS/2") != null) {
+ seek_tab(in, "OS/2", 2*4);
+ int fsType=in.readTTFUShort();
+ if ((fsType & 2) == fsType)
+ is_embeddable=false;
+ else
+ is_embeddable=true;
+ } else
is_embeddable=true;
- } else
- is_embeddable=true;
-
-
-
- seek_tab(in, "loca", 0);
- for (i=0; i < nglyphs ; i++) {
- mtx_tab[i].offset = (loca_format == 1 ? in.readTTFULong() :
- (in.readTTFUShort() << 1));
- }
-
- TTFDirTabEntry dirTab =
- (TTFDirTabEntry)dirTabs.get("glyf");
- for (i=0; i < (nglyphs-1); i++) {
- if (mtx_tab[i].offset != mtx_tab[i+1].offset) {
- in.seek_set(dirTab.offset + mtx_tab[i].offset);
- in.skip(2);
- mtx_tab[i].bbox[0]=in.readTTFShort();
- mtx_tab[i].bbox[1]=in.readTTFShort();
- mtx_tab[i].bbox[2]=in.readTTFShort();
- mtx_tab[i].bbox[3]=in.readTTFShort();
- } else {
- mtx_tab[i].bbox[0]=mtx_tab[0].bbox[0];
- mtx_tab[i].bbox[1]=mtx_tab[0].bbox[1];
- mtx_tab[i].bbox[2]=mtx_tab[0].bbox[2];
- mtx_tab[i].bbox[3]=mtx_tab[0].bbox[3];
- }
- }
-
- //System.out.println("nglyf="+nglyphs+" mtx="+mtx_tab.length);
+ }
+
+ /**
+ * Read the "loca" table
+ */
+ private final void readIndexToLocation(FontFileReader in)
+ throws IOException {
+ seek_tab(in, "loca", 0);
+ for (int i=0; i < nglyphs ; i++) {
+ mtx_tab[i].offset = (loca_format == 1 ? in.readTTFULong() :
+ (in.readTTFUShort() << 1));
+ }
+ }
+
+ /**
+ * Read the "glyf" table to find the bounding boxes
+ */
+ private final void readGlyf(FontFileReader in) throws IOException {
+ TTFDirTabEntry dirTab =
+ (TTFDirTabEntry)dirTabs.get("glyf");
+ for (int i=0; i < (nglyphs-1); i++) {
+ if (mtx_tab[i].offset != mtx_tab[i+1].offset) {
+ in.seek_set(dirTab.offset + mtx_tab[i].offset);
+ in.skip(2);
+ mtx_tab[i].bbox[0]=in.readTTFShort();
+ mtx_tab[i].bbox[1]=in.readTTFShort();
+ mtx_tab[i].bbox[2]=in.readTTFShort();
+ mtx_tab[i].bbox[3]=in.readTTFShort();
+ } else {
+ mtx_tab[i].bbox[0]=mtx_tab[0].bbox[0];
+ mtx_tab[i].bbox[1]=mtx_tab[0].bbox[1];
+ mtx_tab[i].bbox[2]=mtx_tab[0].bbox[2];
+ mtx_tab[i].bbox[3]=mtx_tab[0].bbox[3];
+ }
+ }
-
- n=((TTFDirTabEntry)dirTabs.get("glyf")).offset;
- for (i=0; i < nglyphs; i++) {
- if ((i+1) >= mtx_tab.length ||
- mtx_tab[i].offset != mtx_tab[i+1].offset) {
- in.seek_set(n+mtx_tab[i].offset);
- in.skip(2);
- mtx_tab[i].bbox[0]=in.readTTFShort();
- mtx_tab[i].bbox[1]=in.readTTFShort();
- mtx_tab[i].bbox[2]=in.readTTFShort();
- mtx_tab[i].bbox[3]=in.readTTFShort();
- } else {
- mtx_tab[i].bbox[0]=mtx_tab[0].bbox[0];
- mtx_tab[i].bbox[1]=mtx_tab[0].bbox[0];
- mtx_tab[i].bbox[2]=mtx_tab[0].bbox[0];
- mtx_tab[i].bbox[3]=mtx_tab[0].bbox[0];
- }
- //System.out.println(mtx_tab[i].toString(this));
- }
-
- seek_tab(in, "name", 2);
- i = in.getCurrentPos();
- n = in.readTTFUShort();
- j = in.readTTFUShort() + i - 2;
- i += 2*2;
-
- while (n-- > 0) {
- in.seek_set(i);
- platform_id=in.readTTFUShort();
- encoding_id=in.readTTFUShort();
- language_id=in.readTTFUShort();
- //System.out.println("Platform id: " + language_id);
- //System.out.println("Encoding id: " + language_id);
- //System.out.println("Language id: " + language_id);
- k=in.readTTFUShort();
- l=in.readTTFUShort();
-
- if ((platform_id==1 && encoding_id==0) &&
- (k==1 || k==2 || k==0 || k==4 || k==6)) {
- in.seek_set(j+in.readTTFUShort());
- String txt = in.readTTFString(l);
+
+ long n=((TTFDirTabEntry)dirTabs.get("glyf")).offset;
+ for (int i=0; i < nglyphs; i++) {
+ if ((i+1) >= mtx_tab.length ||
+ mtx_tab[i].offset != mtx_tab[i+1].offset) {
+ in.seek_set(n+mtx_tab[i].offset);
+ in.skip(2);
+ mtx_tab[i].bbox[0]=in.readTTFShort();
+ mtx_tab[i].bbox[1]=in.readTTFShort();
+ mtx_tab[i].bbox[2]=in.readTTFShort();
+ mtx_tab[i].bbox[3]=in.readTTFShort();
+ } else {
+ mtx_tab[i].bbox[0]=mtx_tab[0].bbox[0];
+ mtx_tab[i].bbox[1]=mtx_tab[0].bbox[0];
+ mtx_tab[i].bbox[2]=mtx_tab[0].bbox[0];
+ mtx_tab[i].bbox[3]=mtx_tab[0].bbox[0];
+ }
+ //System.out.println(mtx_tab[i].toString(this));
+ }
+ }
+
+ /**
+ * Read the "name" table
+ */
+ private final void readName(FontFileReader in) throws IOException {
+ int platform_id, encoding_id, language_id;
+
+ seek_tab(in, "name", 2);
+ int i = in.getCurrentPos();
+ int n = in.readTTFUShort();
+ int j = in.readTTFUShort() + i - 2;
+ i += 2*2;
+
+ while (n-- > 0) {
+ //System.out.println("Iteration: "+n);
+ in.seek_set(i);
+ platform_id=in.readTTFUShort();
+ encoding_id=in.readTTFUShort();
+ language_id=in.readTTFUShort();
+
+ int k=in.readTTFUShort();
+ int l=in.readTTFUShort();
+
+ if (((platform_id==1 || platform_id==3) &&
+ (encoding_id==0 || encoding_id==1)) &&
+ (k==1 || k==2 || k==0 || k==4 || k==6)) {
+// if (k==1 || k==2 || k==0 || k==4 || k==6) {
+ in.seek_set(j+in.readTTFUShort());
+ String txt = in.readTTFString(l);
+ //System.out.println(platform_id+" "+encoding_id+
+ //" "+k+" "+txt);
switch (k) {
case 0: notice=txt; break;
case 1: familyName=txt; break;
@@ -327,202 +876,215 @@ public class TTFFile {
}
if (!notice.equals("") && !fullName.equals("") &&
!fontName.equals("") && !familyName.equals("") &&
- !subFamilyName.equals(""))
- break;
- }
- i+=6*2;
- }
-
- dirTab=
- (TTFDirTabEntry)dirTabs.get("PCLT");
- if (dirTab!=null) {
- in.seek_set(dirTab.offset + 4 + 4 + 2);
- xHeight=in.readTTFUShort();
- in.skip(2*2);
- capHeight=in.readTTFUShort();
- in.skip(2+16+8+6+1+1);
-
- int serifStyle=in.readTTFUByte();
- serifStyle=serifStyle >> 6;
- serifStyle=serifStyle & 3;
- if (serifStyle == 1)
- hasSerifs=false;
- else
- hasSerifs=true;
-
- } else {
- // Approximate capHeight from height of "H"
- for (i=0; i < mtx_tab.length; i++) {
- if ("H".equals(mtx_tab[i].name))
- capHeight=mtx_tab[i].bbox[3]-
- mtx_tab[i].bbox[1];
- }
- }
-
- // Read kerning
- kerningTab=new Hashtable();
- dirTab=
- (TTFDirTabEntry)dirTabs.get("kern");
- if (dirTab!=null) {
- seek_tab(in, "kern", 2);
- for (n=in.readTTFUShort(); n>0 ; n--) {
+ !subFamilyName.equals("")) {
+ break;
+ }
+ }
+ i+=6*2;
+ }
+ }
+
+ /**
+ * Read the "PCLT" table to find xHeight and capHeight
+ */
+ private final void readPCLT(FontFileReader in) throws IOException {
+ TTFDirTabEntry dirTab=
+ (TTFDirTabEntry)dirTabs.get("PCLT");
+ if (dirTab!=null) {
+ in.seek_set(dirTab.offset + 4 + 4 + 2);
+ xHeight=in.readTTFUShort();
in.skip(2*2);
- k=in.readTTFUShort();
- if (!((k & 1)!=0) || (k & 2)!=0 || (k & 4)!=0)
- return;
- if ((k >> 8) !=0)
- continue;
-
- k=in.readTTFUShort();
- in.skip(3 * 2);
- while (k-- > 0) {
- i=in.readTTFUShort();
- j=in.readTTFUShort();
- int kpx=in.readTTFShort();
- if (kpx != 0) {
- Hashtable adjTab=(Hashtable)kerningTab.get(mtx_tab[i].name);
- if (adjTab==null)
- adjTab=new java.util.Hashtable();
- adjTab.put(mtx_tab[j].name, new Integer((int)get_ttf_funit(kpx)));
- kerningTab.put(mtx_tab[i].name, adjTab);
- }
+ capHeight=in.readTTFUShort();
+ in.skip(2+16+8+6+1+1);
+
+ int serifStyle=in.readTTFUByte();
+ serifStyle=serifStyle >> 6;
+ serifStyle=serifStyle & 3;
+ if (serifStyle == 1)
+ hasSerifs=false;
+ else
+ hasSerifs=true;
+
+ } else {
+ // Approximate capHeight from height of "H"
+ // It's most unlikly that a font misses the PCLT table
+ // This also assumes that psocriptnames exists ("H")
+ // Should look it up int the cmap (that wouldn't help
+ // for charsets without H anyway...)
+ for (int i=0; i < mtx_tab.length; i++) {
+ if ("H".equals(mtx_tab[i].name))
+ capHeight=mtx_tab[i].bbox[3]-
+ mtx_tab[i].bbox[1];
}
- }
- //System.out.println(kerningTab.toString());
- }
- }
-
-
- public void printStuff() {
- System.out.println("Font name: " + fontName);
- System.out.println("Full name: " + fullName);
- System.out.println("Family name: " + familyName);
- System.out.println("Subfamily name: " + subFamilyName);
- System.out.println("Notice: " + notice);
- System.out.println("xHeight: " + (int)get_ttf_funit(xHeight));
- System.out.println("capheight: " + (int)get_ttf_funit(capHeight));
-
- int italic=(int)(italicAngle>>16);
- System.out.println("Italic: " + italic);
- System.out.print("ItalicAngle: " + (short)(italicAngle/0x10000));
- if ((italicAngle % 0x10000) > 0 )
- System.out.print("."+(short)((italicAngle % 0x10000)*1000)/0x10000);
- System.out.println();
- System.out.println("Ascender: " + get_ttf_funit(ascender));
- System.out.println("Descender: " + get_ttf_funit(descender));
- System.out.println("FontBBox: [" + (int)get_ttf_funit(fontBBox1) +
- " " + (int)get_ttf_funit(fontBBox2) +
- " " + (int)get_ttf_funit(fontBBox3) +
- " " + (int)get_ttf_funit(fontBBox4)+"]");
- }
-
- public static void main(String[] args) {
- try {
- TTFFile ttfFile=new TTFFile();
- FontFileReader reader=
- new FontFileReader(args[0]);
-
- ttfFile.readFont(reader);
- ttfFile.printStuff();
-
- } catch (IOException ioe) {
- System.out.println(ioe.toString());
- }
- }
-
- public String getWindowsName() {
- return new String(familyName+","+subFamilyName);
- }
- public String getPostscriptName() {
- return fontName;
- }
- public String getCharSetName() {
- return "WinAnsi";
- }
- public int getCapHeight() {
- return (int)get_ttf_funit(capHeight);
- }
- public int getXHeight() {
- return (int)get_ttf_funit(xHeight);
- }
- public int getFlags() {
- int flags=32; // Use Adobe Standard charset
- if (italicAngle != 0)
- flags = flags | 64;
- if (isFixedPitch != 0)
- flags = flags | 2;
- if (hasSerifs)
- flags = flags | 1;
- return flags;
- }
- public String getStemV() {
- return "0";
- }
- public String getItalicAngle() {
- String ia=Short.toString((short)(italicAngle/0x10000));
- if ((italicAngle % 0x10000) > 0 )
- ia=ia+("."+Short.toString((short)((short)((italicAngle % 0x10000)*1000)/0x10000)));
-
- return ia;
- }
- public int[] getFontBBox() {
- int[] fbb=new int[4];
- fbb[0]=(int)get_ttf_funit(fontBBox1);
- fbb[1]=(int)get_ttf_funit(fontBBox2);
- fbb[2]=(int)get_ttf_funit(fontBBox3);
- fbb[3]=(int)get_ttf_funit(fontBBox4);
-
- return fbb;
- }
- public int getLowerCaseAscent() {
- return (int)get_ttf_funit(ascender);
- }
- public int getLowerCaseDescent() {
- return (int)get_ttf_funit(descender);
- }
- public short getLastChar() {
- fixWidth();
- return (short)(nmglyphs-1);
- }
- public short getFirstChar() {
- return 0;
- }
-
- public int getCharWidth(int idx) {
- fixWidth();
-
- return (int)get_ttf_funit(mtx_encoded[idx]);
- }
-
- public Hashtable getKerning() {
- return kerningTab;
- }
-
- public boolean isEmbeddable() {
- return is_embeddable;
- }
- private void fixWidth() {
- if (reencoded)
- return;
- reencoded=true;
- //System.out.println("Reencoding widths");
- nmglyphs=0;
- mtx_encoded=new int[Glyphs.tex8r.length];
-
- Hashtable existingGlyphs=new java.util.Hashtable();
-
- for (int i=0; i < mtx_tab.length; i++)
- existingGlyphs.put(mtx_tab[i].name, new Integer(mtx_tab[i].wx));
+ }
+ }
-
- for (int i=0; i < Glyphs.tex8r.length; i++) {
- nmglyphs++;
- Integer wx=(Integer)existingGlyphs.get(Glyphs.tex8r[i]);
- if (wx==null)
- mtx_encoded[i]=0;
- else
- mtx_encoded[i]=wx.intValue();
- }
- }
+ /**
+ * Read the kerning table, create a table for both CIDs and
+ * winAnsiEncoding
+ */
+ private final void readKerning(FontFileReader in) throws IOException {
+ // Read kerning
+ kerningTab=new Hashtable();
+ TTFDirTabEntry dirTab=
+ (TTFDirTabEntry)dirTabs.get("kern");
+ if (dirTab!=null) {
+ seek_tab(in, "kern", 2);
+ for (int n=in.readTTFUShort(); n > 0 ; n--) {
+ in.skip(2*2);
+ int k=in.readTTFUShort();
+ if (!((k & 1)!=0) || (k & 2)!=0 || (k & 4)!=0)
+ return;
+ if ((k >> 8) !=0)
+ continue;
+
+ k=in.readTTFUShort();
+ in.skip(3 * 2);
+ while (k-- > 0) {
+ int i=in.readTTFUShort();
+ int j=in.readTTFUShort();
+ int kpx=in.readTTFShort();
+ if (kpx != 0) {
+ // CID table
+ Integer iObj=new Integer(i);
+ Hashtable adjTab=
+ (Hashtable)kerningTab.get(iObj);
+ if (adjTab==null)
+ adjTab=new java.util.Hashtable();
+ adjTab.put(new Integer(j),
+ new Integer((int)get_ttf_funit(kpx)));
+ kerningTab.put(iObj, adjTab);
+ }
+ }
+ }
+ //System.out.println(kerningTab.toString());
+
+ // Create winAnsiEncoded kerning table
+
+ ansiKerningTab = new Hashtable();
+ for (Enumeration ae = kerningTab.keys();
+ ae.hasMoreElements();) {
+ Integer cidKey = (Integer)ae.nextElement();
+ Hashtable akpx = new Hashtable();
+ Hashtable ckpx = (Hashtable)kerningTab.get(cidKey);
+
+ for (Enumeration aee = ckpx.keys();
+ aee.hasMoreElements();) {
+ Integer cidKey2 = (Integer)aee.nextElement();
+ Integer kern = (Integer)ckpx.get(cidKey2);
+
+ for (Enumeration uniMap = mtx_tab[cidKey2.intValue()].unicodeIndex.elements();
+ uniMap.hasMoreElements();) {
+ Integer unicodeKey = (Integer)uniMap.nextElement();
+ Integer[] ansiKeys = unicodeToWinAnsi(unicodeKey.intValue());
+ for (int u = 0; u < ansiKeys.length; u++) {
+ akpx.put(ansiKeys[u], kern);
+ }
+ }
+ }
+
+ if (akpx.size() > 0)
+ for (Enumeration uniMap = mtx_tab[cidKey.intValue()].unicodeIndex.elements();
+ uniMap.hasMoreElements();) {
+ Integer unicodeKey = (Integer)uniMap.nextElement();
+ Integer[] ansiKeys = unicodeToWinAnsi(unicodeKey.intValue());
+ for (int u = 0; u < ansiKeys.length; u++) {
+ ansiKerningTab.put(ansiKeys[u], akpx);
+ }
+ }
+ }
+ }
+ }
+
+ /** Return a vector with TTFCmapEntry
+ */
+ public Vector getCMaps() {
+ return cmaps;
+ }
+
+ /**
+ * Check if this is a TrueType collection and that the given
+ * name exists in the collection.
+ * If it does, set offset in fontfile to the beginning of
+ * the Table Directory for that font
+ @ return true if not collection or font name present, false
+ otherwise
+ */
+ private final boolean checkTTC(FontFileReader in, String name)
+ throws IOException {
+ String tag=in.readTTFString(4);
+
+ if ("ttcf".equals(tag)) {
+ // This is a TrueType Collection
+ in.skip(4);
+
+ // Read directory offsets
+ int numDirectories=(int)in.readTTFULong();
+ //int numDirectories=in.readTTFUShort();
+ long[] dirOffsets=new long[numDirectories];
+ for (int i=0; i < numDirectories; i++) {
+ dirOffsets[i]=in.readTTFULong();
+ }
+
+ System.out.println("This is a TrueType collection file with"+
+ numDirectories + " fonts");
+ System.out.println("Containing the following fonts: ");
+ // Read all the directories and name tables to check
+ // If the font exists - this is a bit ugly, but...
+ boolean found=false;
+
+ // Iterate through all name tables even if font
+ // Is found, just to show all the names
+ for (int i=0; (i < numDirectories); i++) {
+ in.seek_set(dirOffsets[i]);
+ readDirTabs(in);
+ readName(in);
+
+ if (fullName.equals(name)) {
+ found=true;
+ in.seek_set(dirOffsets[i]);
+ System.out.println("* " + fullName);
+ } else {
+ System.out.println(fullName);
+ }
+
+ // Reset names
+ notice="";
+ fullName="";
+ familyName="";
+ fontName="";
+ subFamilyName="";
+ }
+
+ return found;
+ } else {
+ in.seek_set(0);
+ return true;
+ }
+ }
+
+ /* Helper classes, they are not very efficient, but that really
+ doesn't matter... */
+ private Integer[] unicodeToWinAnsi(int unicode) {
+ Vector ret=new Vector();
+ for (int i=32; i < Glyphs.winAnsiEncoding.length; i++)
+ if (unicode == Glyphs.winAnsiEncoding[i])
+ ret.addElement(new Integer(i));
+ Integer[] itg = new Integer[ret.size()];
+ ret.copyInto(itg);
+ return itg;
+ }
}
+
+/**
+ * Key-value helper class
+ */
+class UnicodeMapping {
+ int uIdx;
+ int gIdx;
+ UnicodeMapping(int gIdx, int uIdx) {
+ this.uIdx = uIdx;
+ this.gIdx = gIdx;
+ }
+}
diff --git a/src/org/apache/fop/fonts/TTFMtxEntry.java b/src/org/apache/fop/fonts/TTFMtxEntry.java
index c44c2c965..e1333bd24 100644
--- a/src/org/apache/fop/fonts/TTFMtxEntry.java
+++ b/src/org/apache/fop/fonts/TTFMtxEntry.java
@@ -51,27 +51,30 @@
package org.apache.fop.fonts;
import java.io.*;
+import java.util.Vector;
class TTFMtxEntry {
- int wx;
- String name;
- int index;
- int[] bbox;
- long offset;
- byte found;
-
- TTFMtxEntry() {
- name="";
- found=0;
- bbox=new int[4];
- }
-
- public String toString(TTFFile t) {
- return new String("Glyph "+name+ " index: " + index +
- " bbox [ "+t.get_ttf_funit(bbox[0])+
- " " + t.get_ttf_funit(bbox[1]) +
- " " + t.get_ttf_funit(bbox[2]) +
- " " + t.get_ttf_funit(bbox[3]) + "]" +
- "wx: "+t.get_ttf_funit(wx));
- }
+ int wx;
+ String name;
+ int index;
+ Vector unicodeIndex;
+ int[] bbox;
+ long offset;
+ byte found;
+
+ TTFMtxEntry() {
+ name="";
+ found=0;
+ unicodeIndex = new Vector();
+ bbox=new int[4];
+ }
+
+ public String toString(TTFFile t) {
+ return new String("Glyph "+name+ " index: " + index +
+ " bbox [ "+t.get_ttf_funit(bbox[0])+
+ " " + t.get_ttf_funit(bbox[1]) +
+ " " + t.get_ttf_funit(bbox[2]) +
+ " " + t.get_ttf_funit(bbox[3]) + "]" +
+ "wx: "+t.get_ttf_funit(wx));
+ }
}
diff --git a/src/org/apache/fop/fonts/apps/PFMReader.java b/src/org/apache/fop/fonts/apps/PFMReader.java
index c7c1410f2..581ba20db 100644
--- a/src/org/apache/fop/fonts/apps/PFMReader.java
+++ b/src/org/apache/fop/fonts/apps/PFMReader.java
@@ -67,10 +67,6 @@ import java.util.Enumeration;
* @author jeremias.maerki@outline.ch
*/
public class PFMReader {
-
- static private final String XSL_POSTPROCESS = "FontPostProcess.xsl";
- static private final String XSL_SORT = "FontPostProcessSort.xsl";
-
private boolean invokedStandalone = false;
public PFMReader() {
@@ -88,13 +84,14 @@ public class PFMReader {
Vector arguments=new Vector();
for (int i=0; i < args.length; i++) {
if (args[i].startsWith("-")) {
- i++;
- if (i < args.length)
- options.put(args[i-1], args[i]);
- else
- options.put(args[i-1], "");
+ if ((i+1) < args.length && !args[i+1].startsWith("-")) {
+ options.put(args[i], args[i+1]);
+ i++;
+ } else {
+ options.put(args[i], "");
+ }
} else {
- arguments.addElement(args[i]);
+ arguments.addElement(args[i]);
}
}
@@ -107,18 +104,10 @@ public class PFMReader {
System.out.println(" java org.apache.fop.fonts.apps.PFMReader [options] metricfile.pfm xmlfile.xml\n");
System.out.println(" where options can be:\n");
System.out.println(" -fn <fontname>\n");
- System.out.println(" default is to use the fontname in the .pfm file, but you can override\n");
- System.out.println(" that name to make sure that the embedded font is used instead of installed\n");
- System.out.println(" fonts when viewing documents with Acrobat Reader.\n");
- System.out.println(" -cn <classname>\n");
- System.out.println(" default is to use the fontname\n");
- System.out.println(" -ef <path to the Type1 .pfb fontfile>\n");
- System.out.println(" will add the possibility to embed the font. When running fop, fop will look\n");
- System.out.println(" for this file to embed it\n");
- System.out.println(" -er <path to Type1 fontfile relative to org/apache/fop/render/pdf/fonts>\n");
- System.out.println(" you can also include the fontfile in the fop.jar file when building fop.\n");
- System.out.println(" You can use both -ef and -er. The file specified in -ef will be searched first,\n");
- System.out.println(" then the -er file.\n");
+ System.out.println(" default is to use the fontname in the .ttf file, but\n"+
+ " you can override that name to make sure that the\n");
+ System.out.println(" embedded font is used (if you're embedding fonts)\n");
+ System.out.println(" instead of installed fonts when viewing documents with Acrobat Reader.\n");
}
@@ -142,56 +131,54 @@ public class PFMReader {
* then the -er file.
*/
public static void main(String[] args) {
- String embFile=null;
- String embResource=null;
- String className=null;
- String fontName=null;
-
- Hashtable options=new Hashtable();
- String[] arguments=parseArguments(options, args);
-
- PFMReader app = new PFMReader();
- app.invokedStandalone = true;
-
- System.out.println("PFM Reader v1.1");
- System.out.println();
-
- if (options.get("-ef") != null)
- embFile=(String)options.get("-ef");
-
- if (options.get("-er") != null)
- embResource=(String)options.get("-er");
-
- if (options.get("-fn") != null)
- fontName=(String)options.get("-fn");
-
- if (options.get("-cn") != null)
- className=(String)options.get("-cn");
-
- if (arguments.length != 2 ||
- options.get("-h") != null ||
- options.get("-help") != null ||
- options.get("--help") != null)
- displayUsage();
- else {
- PFMFile pfm = app.loadPFM(arguments[0]);
- if (pfm != null) {
- app.preview(pfm);
-
- org.w3c.dom.Document doc = app.constructFontXML(pfm,
- fontName,
- className,
- embResource,
- embFile);
-
- doc = app.postProcessXML(doc);
- if (doc != null) {
+ String embFile=null;
+ String embResource=null;
+ String className=null;
+ String fontName=null;
+
+ Hashtable options=new Hashtable();
+ String[] arguments=parseArguments(options, args);
+
+ PFMReader app = new PFMReader();
+ app.invokedStandalone = true;
+
+ System.out.println("PFM Reader v1.1");
+ System.out.println();
+
+ if (options.get("-ef") != null)
+ embFile=(String)options.get("-ef");
+
+ if (options.get("-er") != null)
+ embResource=(String)options.get("-er");
+
+ if (options.get("-fn") != null)
+ fontName=(String)options.get("-fn");
+
+ if (options.get("-cn") != null)
+ className=(String)options.get("-cn");
+
+ if (arguments.length != 2 ||
+ options.get("-h") != null ||
+ options.get("-help") != null ||
+ options.get("--help") != null)
+ displayUsage();
+ else {
+ PFMFile pfm = app.loadPFM(arguments[0]);
+ if (pfm != null) {
+ app.preview(pfm);
+
+ org.w3c.dom.Document doc = app.constructFontXML(pfm,
+ fontName,
+ className,
+ embResource,
+ embFile);
+
app.writeFontXML(doc, arguments[1]);
- }
- }
- }
+ }
+ }
}
+
/**
* Read a PFM file and returns it as an object.
*
@@ -286,7 +273,8 @@ public class PFMReader {
Document doc = new DocumentImpl();
Element root = doc.createElement("font-metrics");
doc.appendChild(root);
-
+ root.setAttribute("type", "TYPE1");
+
Element el = doc.createElement("font-name");
root.appendChild(el);
el.appendChild(doc.createTextNode(pfm.getPostscriptName()));
@@ -300,30 +288,12 @@ public class PFMReader {
s = new String(sb);
}
- el = doc.createElement("class-name");
+ el = doc.createElement("embed");
root.appendChild(el);
- if (className != null)
- el.appendChild(doc.createTextNode(className));
- else
- el.appendChild(doc.createTextNode(s));
-
- el = doc.createElement("embedFile");
- root.appendChild(el);
- if (file==null)
- el.appendChild(doc.createTextNode("null"));
- else
- el.appendChild(doc.createTextNode("\""+escapeString(file)+"\""));
-
- el = doc.createElement("embedResource");
- root.appendChild(el);
- if (resource==null)
- el.appendChild(doc.createTextNode("null"));
- else
- el.appendChild(doc.createTextNode("\""+escapeString(resource)+"\""));
-
- el = doc.createElement("subtype");
- root.appendChild(el);
- el.appendChild(doc.createTextNode("Type1"));
+ if (file!=null)
+ el.setAttribute("file", file);
+ if (resource!=null)
+ el.setAttribute("class", resource);
el = doc.createElement("encoding");
root.appendChild(el);
@@ -391,8 +361,8 @@ public class PFMReader {
for (short i = pfm.getFirstChar(); i < pfm.getLastChar(); i++) {
el = doc.createElement("char");
widths.appendChild(el);
- el.setAttribute("ansichar", "0x00" + Integer.toHexString(i).toUpperCase());
- el.setAttribute("width", new Integer(pfm.getCharWidth(i)).toString());
+ el.setAttribute("idx", Integer.toString(i));
+ el.setAttribute("wdt", new Integer(pfm.getCharWidth(i)).toString());
}
@@ -403,72 +373,20 @@ public class PFMReader {
el.setAttribute("kpx1", kpx1);
root.appendChild(el);
Element el2=null;
-
+
Hashtable h2=(Hashtable)pfm.getKerning().get(kpx1);
for (Enumeration enum2=h2.keys(); enum2.hasMoreElements(); ) {
- String kpx2=(String)enum2.nextElement();
- el2=doc.createElement("pair");
- el2.setAttribute("kpx2", kpx2);
- Integer val=(Integer)h2.get(kpx2);
- el2.setAttribute("kern", val.toString());
- el.appendChild(el2);
+ Integer kpx2=(Integer)enum2.nextElement();
+ el2=doc.createElement("pair");
+ el2.setAttribute("kpx2", kpx2.toString());
+ Integer val=(Integer)h2.get(kpx2);
+ el2.setAttribute("kern", val.toString());
+ el.appendChild(el2);
}
}
return doc;
}
- /**
- * Modifies the generated font metrics file. First, it processes the
- * character mmappings, then it sorts them.
- *
- * @param doc The DOM document representing the font metrics file.
- * @return A DOM document representing the processed font metrics file.
- */
- public org.w3c.dom.Document postProcessXML(org.w3c.dom.Document doc) {
- try {
- OutputFormat format = new OutputFormat(doc); //Serialize DOM
- XMLSerializer serial = new XMLSerializer(System.out, format);
- serial.asDOMSerializer(); // As a DOM Serializer
- serial.serialize(doc.getDocumentElement());
-
- System.out.println("Postprocessing...");
- System.out.println();
-
-
-
- InputStream xsl = this.getClass().getResourceAsStream(XSL_POSTPROCESS);
- if (xsl == null) {
- throw new Exception("Resource " + XSL_POSTPROCESS + " not found");
- }
-
- Document targetDoc = new DocumentImpl();
- org.apache.fop.tools.xslt.XSLTransform.transform(doc, xsl, targetDoc);
-
-
- System.out.println("Sorting...");
- System.out.println();
-
- // Sort the whole thing
-
-
- xsl = this.getClass().getResourceAsStream(XSL_SORT);
- if (xsl == null) {
- throw new Exception("Resource " + XSL_SORT + " not found");
- }
-
-
- org.w3c.dom.Document targetDocSorted = new DocumentImpl();
-
- org.apache.fop.tools.xslt.XSLTransform.transform(targetDoc, xsl, targetDocSorted);
-
- return targetDocSorted;
-
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
-
private String escapeString(String str) {
StringBuffer esc=new StringBuffer();
@@ -483,3 +401,7 @@ public class PFMReader {
return esc.toString();
}
}
+
+
+
+
diff --git a/src/org/apache/fop/fonts/apps/TTFReader.java b/src/org/apache/fop/fonts/apps/TTFReader.java
index f7dbe0bfd..e4ff7774b 100644
--- a/src/org/apache/fop/fonts/apps/TTFReader.java
+++ b/src/org/apache/fop/fonts/apps/TTFReader.java
@@ -66,9 +66,6 @@ import java.util.Enumeration;
*/
public class TTFReader {
- static private final String XSL_POSTPROCESS = "TTFPostProcess.xsl";
- static private final String XSL_SORT = "TTFPostProcessSort.xsl";
-
private boolean invokedStandalone = false;
public TTFReader() {
@@ -86,13 +83,14 @@ public class TTFReader {
Vector arguments=new Vector();
for (int i=0; i < args.length; i++) {
if (args[i].startsWith("-")) {
- i++;
- if (i < args.length)
- options.put(args[i-1], args[i]);
- else
- options.put(args[i-1], "");
+ if ((i+1) < args.length && !args[i+1].startsWith("-")) {
+ options.put(args[i], args[i+1]);
+ i++;
+ } else {
+ options.put(args[i], "");
+ }
} else {
- arguments.addElement(args[i]);
+ arguments.addElement(args[i]);
}
}
@@ -105,19 +103,22 @@ public class TTFReader {
private final static void displayUsage() {
System.out.println(" java org.apache.fop.fonts.apps.TTFReader [options] fontfile.ttf xmlfile.xml\n");
System.out.println(" where options can be:\n");
+ System.out.println("-enc cid");
+ System.out.println(" With this option you create a CID keyed font.");
+ System.out.println(" If you're going to use characters outside the");
+ System.out.println(" pdfencoding range (almost the same as iso-8889-1)");
+ System.out.println(" you must add this option.");
+ System.out.println("-ttcname <fontname>");
+ System.out.println(" If you're reading data from a TrueType Collection");
+ System.out.println(" (.ttc file) you must specify which font from the");
+ System.out.println(" collection you will read metrics from. If you read");
+ System.out.println(" from a .ttc file without this option, the fontnames");
+ System.out.println(" will be listed for you.");
System.out.println(" -fn <fontname>\n");
- System.out.println(" default is to use the fontname in the .ttf file, but you can override\n");
- System.out.println(" that name to make sure that the embedded font is used instead of installed\n");
- System.out.println(" fonts when viewing documents with Acrobat Reader.\n");
- System.out.println(" -cn <classname>\n");
- System.out.println(" default is to use the fontname\n");
- System.out.println(" -ef <path to the truetype fontfile>\n");
- System.out.println(" will add the possibility to embed the font. When running fop, fop will look\n");
- System.out.println(" for this file to embed it\n");
- System.out.println(" -er <path to truetype fontfile relative to org/apache/fop/render/pdf/fonts>\n");
- System.out.println(" you can also include the fontfile in the fop.jar file when building fop.\n");
- System.out.println(" You can use both -ef and -er. The file specified in -ef will be searched first,\n");
- System.out.println(" then the -er file.\n");
+ System.out.println(" default is to use the fontname in the .ttf file, but\n"+
+ " you can override that name to make sure that the\n");
+ System.out.println(" embedded font is used (if you're embedding fonts)\n");
+ System.out.println(" instead of installed fonts when viewing documents with Acrobat Reader.\n");
}
@@ -145,6 +146,8 @@ public class TTFReader {
String embResource=null;
String className=null;
String fontName=null;
+ String ttcName=null;
+ boolean isCid=false;
Hashtable options=new Hashtable();
String[] arguments=parseArguments(options, args);
@@ -152,9 +155,18 @@ public class TTFReader {
TTFReader app = new TTFReader();
app.invokedStandalone = true;
- System.out.println("TTF Reader v1.0");
+ System.out.println("TTF Reader v1.1");
System.out.println();
+ if (options.get("-enc") != null) {
+ String enc = (String)options.get("-enc");
+ if ("cid".equals(enc))
+ isCid=true;
+ }
+
+ if (options.get("-ttcname") != null)
+ ttcName=(String)options.get("-ttcname");
+
if (options.get("-ef") != null)
embFile=(String)options.get("-ef");
@@ -173,20 +185,26 @@ public class TTFReader {
options.get("--help") != null)
displayUsage();
else {
- TTFFile ttf = app.loadTTF(arguments[0]);
+ TTFFile ttf = app.loadTTF(arguments[0], ttcName);
if (ttf != null) {
- app.preview(ttf);
-
org.w3c.dom.Document doc = app.constructFontXML(ttf,
fontName,
className,
embResource,
- embFile);
+ embFile,
+ isCid,
+ ttcName);
- doc = app.postProcessXML(doc);
if (doc != null) {
app.writeFontXML(doc, arguments[1]);
}
+
+ if (ttf.isEmbeddable())
+ System.out.println("This font contains no embedding license restrictions");
+ else
+ System.out.println("** Note: This font contains license retrictions for\n"+
+ " embedding. This font can't be embedded.");
+
}
}
}
@@ -195,16 +213,16 @@ public class TTFReader {
* Read a TTF file and returns it as an object.
*
* @param filename The filename of the PFM file.
- * @return The PFM as an object.
+ * @return The TTF as an object.
*/
- public TTFFile loadTTF(String filename) {
+ public TTFFile loadTTF(String fileName, String fontName) {
TTFFile ttfFile=new TTFFile();
try {
- System.out.println("Reading " + filename + "...");
+ System.out.println("Reading " + fileName + "...");
System.out.println();
- FontFileReader reader = new FontFileReader(filename);
- ttfFile.readFont(reader);
+ FontFileReader reader = new FontFileReader(fileName);
+ ttfFile.readFont(reader, fontName);
} catch (Exception e) {
e.printStackTrace();
return null;
@@ -212,45 +230,6 @@ public class TTFReader {
return ttfFile;
}
- /**
- * Displays a preview of the TTF file on the console.
- *
- * @param ttf The TTF file to preview.
- */
- public void preview(TTFFile ttf) {
- PrintStream out = System.out;
-
- out.print("Font: ");
- out.println(ttf.getWindowsName());
- out.print("Name: ");
- out.println(ttf.getPostscriptName());
- out.print("CharSet: ");
- out.println(ttf.getCharSetName());
- out.print("CapHeight: ");
- out.println(ttf.getCapHeight());
- out.print("XHeight: ");
- out.println(ttf.getXHeight());
- out.print("LowerCaseAscent: ");
- out.println(ttf.getLowerCaseAscent());
- out.print("LowerCaseDescent: ");
- out.println(ttf.getLowerCaseDescent());
- out.print("Having widths for ");
- out.print(ttf.getLastChar()-ttf.getFirstChar());
- out.print(" characters (");
- out.print(ttf.getFirstChar());
- out.print("-");
- out.print(ttf.getLastChar());
- out.println(").");
- out.print("for example: Char ");
- out.print(ttf.getFirstChar());
- out.print(" has a width of ");
- out.println(ttf.getCharWidth(ttf.getFirstChar()));
- out.println();
- if (ttf.isEmbeddable())
- out.println("This font might be embedded");
- else
- out.println("This font might not be embedded");
- }
/**
* Writes the generated DOM Document to a file.
@@ -276,21 +255,26 @@ public class TTFReader {
}
/**
- * Generates the font metrics file from the PFM file.
+ * Generates the font metrics file from the TTF/TTC file.
*
- * @param pfm The PFM file to generate the font metrics from.
+ * @param ttf The PFM file to generate the font metrics from.
* @return The DOM document representing the font metrics file.
*/
public org.w3c.dom.Document constructFontXML(TTFFile ttf, String fontName,
String className, String resource,
- String file) {
+ String file, boolean isCid,
+ String ttcName) {
System.out.println("Creating xml font file...");
System.out.println();
Document doc = new DocumentImpl();
Element root = doc.createElement("font-metrics");
doc.appendChild(root);
-
+ if (isCid)
+ root.setAttribute("type", "TYPE0");
+ else
+ root.setAttribute("type", "TRUETYPE");
+
Element el = doc.createElement("font-name");
root.appendChild(el);
@@ -298,51 +282,19 @@ public class TTFReader {
// "Perpetua-Bold", but the TrueType spec says that in the ttf file
// it should be "Perpetua,Bold".
- String s = ttf.getPostscriptName();
+ String s = stripWhiteSpace(ttf.getPostscriptName());
if (fontName != null)
- el.appendChild(doc.createTextNode(fontName));
- else
- el.appendChild(doc.createTextNode(s.replace('-', ',')));
-
- int pos = s.indexOf("-");
- if (pos >= 0) {
- char sb[] = new char[s.length() - 1];
- s.getChars(0, pos, sb, 0);
- s.getChars(pos + 1, s.length(), sb, pos);
- s = new String(sb);
- }
-
- el = doc.createElement("class-name");
- root.appendChild(el);
- if (className != null)
- el.appendChild(doc.createTextNode(className));
+ el.appendChild(doc.createTextNode(stripWhiteSpace(fontName)));
else
- el.appendChild(doc.createTextNode(s));
+ el.appendChild(doc.createTextNode(s));
- el = doc.createElement("embedFile");
- root.appendChild(el);
- //if (file==null || !ttf.isEmbeddable())
- if (file==null)
- el.appendChild(doc.createTextNode("null"));
- else
- el.appendChild(doc.createTextNode("\""+escapeString(file)+"\""));
-
- el = doc.createElement("embedResource");
+ el = doc.createElement("embed");
root.appendChild(el);
- //if (resource==null || !ttf.isEmbeddable())
- if (resource==null)
- el.appendChild(doc.createTextNode("null"));
- else
- el.appendChild(doc.createTextNode("\""+escapeString(resource)+"\""));
-
- el = doc.createElement("subtype");
- root.appendChild(el);
- el.appendChild(doc.createTextNode("TRUETYPE"));
-
- el = doc.createElement("encoding");
- root.appendChild(el);
- el.appendChild(doc.createTextNode(ttf.getCharSetName()+"Encoding"));
+ if (file != null && ttf.isEmbeddable())
+ el.setAttribute("file", file);
+ if (resource != null && ttf.isEmbeddable())
+ el.setAttribute("class", resource);
el = doc.createElement("cap-height");
root.appendChild(el);
@@ -353,12 +305,12 @@ public class TTFReader {
root.appendChild(el);
value = new Integer(ttf.getXHeight());
el.appendChild(doc.createTextNode(value.toString()));
-
+
el = doc.createElement("ascender");
root.appendChild(el);
value = new Integer(ttf.getLowerCaseAscent());
el.appendChild(doc.createTextNode(value.toString()));
-
+
el = doc.createElement("descender");
root.appendChild(el);
value = new Integer(ttf.getLowerCaseDescent());
@@ -379,115 +331,143 @@ public class TTFReader {
root.appendChild(el);
value = new Integer(ttf.getFlags());
el.appendChild(doc.createTextNode(value.toString()));
-
+
el = doc.createElement("stemv");
root.appendChild(el);
value = new Integer(ttf.getStemV());
el.appendChild(doc.createTextNode(value.toString()));
-
+
el = doc.createElement("italicangle");
root.appendChild(el);
value = new Integer(ttf.getItalicAngle());
el.appendChild(doc.createTextNode(value.toString()));
- el = doc.createElement("first-char");
- root.appendChild(el);
- value = new Integer(ttf.getFirstChar());
- el.appendChild(doc.createTextNode(value.toString()));
-
- el = doc.createElement("last-char");
- root.appendChild(el);
- value = new Integer(ttf.getLastChar());
- el.appendChild(doc.createTextNode(value.toString()));
-
- Element widths = doc.createElement("widths");
- root.appendChild(widths);
-
- for (short i = ttf.getFirstChar(); i < ttf.getLastChar(); i++) {
- el = doc.createElement("char");
- widths.appendChild(el);
- //el.setAttribute("ansichar", "0x00" + Integer.toHexString(i).toUpperCase());
- el.setAttribute("name", "0x00" +
- Integer.toHexString(i).toUpperCase());
- el.setAttribute("width",
- new Integer(ttf.getCharWidth(i)).toString());
- }
-
- // Get kerning
- for (Enumeration enum=ttf.getKerning().keys(); enum.hasMoreElements();) {
- String kpx1=(String)enum.nextElement();
- el=doc.createElement("kerning");
- el.setAttribute("kpx1", kpx1);
- root.appendChild(el);
- Element el2=null;
-
- Hashtable h2=(Hashtable)ttf.getKerning().get(kpx1);
- for (Enumeration enum2=h2.keys(); enum2.hasMoreElements(); ) {
- String kpx2=(String)enum2.nextElement();
- el2=doc.createElement("pair");
- el2.setAttribute("kpx2", kpx2);
- Integer val=(Integer)h2.get(kpx2);
- el2.setAttribute("kern", val.toString());
- el.appendChild(el2);
- }
+ if (ttcName != null) {
+ el = doc.createElement("ttc-name");
+ root.appendChild(el);
+ el.appendChild(doc.createTextNode(ttcName));
}
- return doc;
- }
+
+ el = doc.createElement("subtype");
+ root.appendChild(el);
+
+ // Fill in extras for CID keyed fonts
+ if (isCid) {
+ el.appendChild(doc.createTextNode("TYPE0"));
- /**
- * Modifies the generated font metrics file. First, it processes the
- * character mmappings, then it sorts them.
- *
- * @param doc The DOM document representing the font metrics file.
- * @return A DOM document representing the processed font metrics file.
- */
- public org.w3c.dom.Document postProcessXML(org.w3c.dom.Document doc) {
- if (true)
- return doc;
- try {
- OutputFormat format = new OutputFormat(doc); //Serialize DOM
- XMLSerializer serial = new XMLSerializer(System.out, format);
- serial.asDOMSerializer(); // As a DOM Serializer
- serial.serialize(doc.getDocumentElement());
+ Element mel = doc.createElement("multibyte-extras");
+ root.appendChild(mel);
- System.out.println("Postprocessing...");
- System.out.println();
-
-
-
- InputStream xsl = this.getClass().getResourceAsStream(XSL_POSTPROCESS);
- if (xsl == null) {
- throw new Exception("Resource " + XSL_POSTPROCESS + " not found");
+ el = doc.createElement("cid-type");
+ mel.appendChild(el);
+ el.appendChild(doc.createTextNode("CIDFontType2"));
+
+ el = doc.createElement("default-width");
+ mel.appendChild(el);
+ el.appendChild(doc.createTextNode("0"));
+
+ el = doc.createElement("bfranges");
+ mel.appendChild(el);
+ for (Enumeration e=ttf.getCMaps().elements(); e.hasMoreElements();) {
+ TTFCmapEntry ce = (TTFCmapEntry)e.nextElement();
+ Element el2=doc.createElement("bf");
+ el.appendChild(el2);
+ el2.setAttribute("us", Integer.toString(ce.unicodeStart));
+ el2.setAttribute("ue", Integer.toString(ce.unicodeEnd));
+ el2.setAttribute("gi", Integer.toString(ce.glyphStartIndex));
}
-
- Document targetDoc = new DocumentImpl();
- org.apache.fop.tools.xslt.XSLTransform.transform(doc, xsl, targetDoc);
-
-
- System.out.println("Sorting...");
- System.out.println();
-
- // Sort the whole thing
-
- xsl = this.getClass().getResourceAsStream(XSL_SORT);
- if (xsl == null) {
- throw new Exception("Resource " + XSL_SORT + " not found");
+ el = doc.createElement("cid-widths");
+ el.setAttribute("start-index", "0");
+ mel.appendChild(el);
+
+ int[] wx = ttf.getWidths();
+ for (int i = 0; i < wx.length; i++) {
+ Element wxel=doc.createElement("wx");
+ wxel.setAttribute("w", Integer.toString(wx[i]));
+ el.appendChild(wxel);
}
-
-
- org.w3c.dom.Document targetDocSorted = new DocumentImpl();
+ } else {
+ // Fill in extras for singlebyte fonts
+ el.appendChild(doc.createTextNode("TRUETYPE"));
- org.apache.fop.tools.xslt.XSLTransform.transform(targetDoc, xsl, targetDocSorted);
+ Element sel=doc.createElement("singlebyte-extras");
+ root.appendChild(sel);
+
+ el = doc.createElement("encoding");
+ sel.appendChild(el);
+ el.appendChild(doc.createTextNode(ttf.getCharSetName()));
- return targetDocSorted;
+ el = doc.createElement("first-char");
+ sel.appendChild(el);
+ value = new Integer(ttf.getFirstChar());
+ el.appendChild(doc.createTextNode(value.toString()));
+
+ el = doc.createElement("last-char");
+ sel.appendChild(el);
+ value = new Integer(ttf.getLastChar());
+ el.appendChild(doc.createTextNode(value.toString()));
+
+ Element widths = doc.createElement("widths");
+ sel.appendChild(widths);
+
+ for (short i = ttf.getFirstChar(); i < ttf.getLastChar(); i++) {
+ el = doc.createElement("char");
+ widths.appendChild(el);
+ el.setAttribute("idx", Integer.toString(i));
+ el.setAttribute("wdt", Integer.toString(ttf.getCharWidth(i)));
+ }
+ }
+
+ // Get kerning
+ Enumeration enum;
+ if (isCid)
+ enum=ttf.getKerning().keys();
+ else
+ enum=ttf.getAnsiKerning().keys();
+
+ while (enum.hasMoreElements()) {
+ Integer kpx1=(Integer)enum.nextElement();
- } catch (Exception e) {
- e.printStackTrace();
- return null;
+ el=doc.createElement("kerning");
+ el.setAttribute("kpx1", kpx1.toString());
+ root.appendChild(el);
+ Element el2=null;
+
+ Hashtable h2;
+ if (isCid)
+ h2 = (Hashtable)ttf.getKerning().get(kpx1);
+ else
+ h2 = (Hashtable)ttf.getAnsiKerning().get(kpx1);
+
+ for (Enumeration enum2=h2.keys(); enum2.hasMoreElements(); ) {
+ Integer kpx2=(Integer)enum2.nextElement();
+ if (isCid || kpx2.intValue() < 256) {
+ el2=doc.createElement("pair");
+ el2.setAttribute("kpx2", kpx2.toString());
+ Integer val=(Integer)h2.get(kpx2);
+ el2.setAttribute("kern", val.toString());
+ el.appendChild(el2);
+ }
+ }
}
+
+ return doc;
}
-
+
+
+ private String stripWhiteSpace(String s) {
+ char[] ch = new char[s.length()];
+ s.getChars(0, s.length(), ch, 0);
+ StringBuffer stb = new StringBuffer();
+ for (int i = 0; i < ch.length; i++)
+ if (ch[i] != ' ' && ch[i] != '\r' &&
+ ch[i] != '\n' && ch[i] != '\t')
+ stb.append(ch[i]);
+
+ return stb.toString();
+ }
+
private String escapeString(String str) {
StringBuffer esc=new StringBuffer();
diff --git a/src/org/apache/fop/layout/FontInfo.java b/src/org/apache/fop/layout/FontInfo.java
index 869a54e98..84a2a4979 100644
--- a/src/org/apache/fop/layout/FontInfo.java
+++ b/src/org/apache/fop/layout/FontInfo.java
@@ -57,13 +57,14 @@ import java.util.Enumeration;
import org.apache.fop.apps.FOPException;
public class FontInfo {
-
+ Hashtable usedFonts;
Hashtable triplets; // look up a font-triplet to find a font-name
Hashtable fonts; // look up a font-name to get a font (that implements FontMetric at least)
public FontInfo() {
this.triplets = new Hashtable();
- this.fonts = new Hashtable();
+ this.fonts = new Hashtable();
+ this.usedFonts = new Hashtable();
}
public void addFontProperties(String name, String family, String style, String weight) {
@@ -109,6 +110,8 @@ public class FontInfo {
}
MessageHandler.errorln("WARNING: unknown font "+family+" so defaulted font to any");
}
+
+ usedFonts.put(f, fonts.get(f));
return f;
}
@@ -116,13 +119,17 @@ public class FontInfo {
return this.fonts;
}
+ public Hashtable getUsedFonts() {
+ return this.usedFonts;
+ }
+
public FontMetric getMetricsFor(String fontName) throws FOPException {
- return (FontMetric)fonts.get(fontName);
+ usedFonts.put(fontName, fonts.get(fontName));
+ return (FontMetric)fonts.get(fontName);
}
public FontMetric getMetricsFor(String family, String style, String weight) throws FOPException {
// given a family, style and weight, return the metric
-
- return (FontMetric)fonts.get(fontLookup(family,style,weight));
+ return (FontMetric)fonts.get(fontLookup(family,style,weight));
}
}
diff --git a/src/org/apache/fop/layout/FontState.java b/src/org/apache/fop/layout/FontState.java
index f022ab54a..e000b5e77 100644
--- a/src/org/apache/fop/layout/FontState.java
+++ b/src/org/apache/fop/layout/FontState.java
@@ -54,17 +54,17 @@ import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.properties.FontVariant;
public class FontState {
-
- protected FontInfo fontInfo;
- private String fontName;
- private int fontSize;
- private String fontFamily;
- private String fontStyle;
- private String fontWeight;
- private FontMetric metric;
- private int fontVariant;
-
- public FontState(FontInfo fontInfo, String fontFamily, String fontStyle, String fontWeight, int fontSize, int fontVariant) throws FOPException {
+
+ protected FontInfo fontInfo;
+ private String fontName;
+ private int fontSize;
+ private String fontFamily;
+ private String fontStyle;
+ private String fontWeight;
+ private FontMetric metric;
+ private int fontVariant;
+
+ public FontState(FontInfo fontInfo, String fontFamily, String fontStyle, String fontWeight, int fontSize, int fontVariant) throws FOPException {
this.fontInfo = fontInfo;
this.fontFamily = fontFamily;
this.fontStyle = fontStyle;
@@ -73,65 +73,99 @@ public class FontState {
this.fontName = fontInfo.fontLookup(fontFamily,fontStyle,fontWeight);
this.metric = fontInfo.getMetricsFor(fontName);
this.fontVariant = fontVariant;
- }
-
- public int getAscender() {
+ }
+
+ public int getAscender() {
return metric.getAscender(fontSize) / 1000;
- }
-
- public int getCapHeight() {
+ }
+
+ public int getCapHeight() {
return metric.getCapHeight(fontSize) / 1000;
- }
-
- public int getDescender() {
+ }
+
+ public int getDescender() {
return metric.getDescender(fontSize) / 1000;
- }
-
- public String getFontName() {
+ }
+
+ public String getFontName() {
return this.fontName;
- }
-
- public int getFontSize() {
+ }
+
+ public int getFontSize() {
return this.fontSize;
- }
-
- public String getFontWeight() {
+ }
+
+ public String getFontWeight() {
return this.fontWeight;
- }
-
- public String getFontFamily() {
+ }
+
+ public String getFontFamily() {
return this.fontFamily;
- }
-
- public String getFontStyle() {
+ }
+
+ public String getFontStyle() {
return this.fontStyle;
- }
-
- public int getFontVariant() {
+ }
+
+ public int getFontVariant() {
return this.fontVariant;
- }
-
- public FontInfo getFontInfo() {
+ }
+
+ public FontInfo getFontInfo() {
return this.fontInfo;
- }
-
- public int getXHeight() {
+ }
+
+ public int getXHeight() {
return metric.getXHeight(fontSize) / 1000;
- }
- public java.util.Hashtable getKerning() {
- java.util.Hashtable ret=new java.util.Hashtable();
- try {
- FontMetric fm=fontInfo.getMetricsFor(fontFamily, fontStyle, fontWeight);
- if (fm instanceof org.apache.fop.layout.FontDescriptor) {
- org.apache.fop.layout.FontDescriptor fdes=(org.apache.fop.layout.FontDescriptor)fm;
- ret=fdes.getKerningInfo();
- }
- } catch (Exception e) {}
- return ret;
- }
-
- public int width(int charnum) {
- // returns width of given character number in millipoints
+ }
+
+ public java.util.Hashtable getKerning() {
+ java.util.Hashtable ret=new java.util.Hashtable();
+ try {
+ FontMetric fm=fontInfo.getMetricsFor(fontFamily, fontStyle,
+ fontWeight);
+ if (fm instanceof org.apache.fop.layout.FontDescriptor) {
+ org.apache.fop.layout.FontDescriptor fdes=
+ (org.apache.fop.layout.FontDescriptor)fm;
+ ret=fdes.getKerningInfo();
+ }
+ } catch (Exception e) {}
+ return ret;
+ }
+
+ public int width(int charnum) {
+ // returns width of given character number in millipoints
return (metric.width(charnum, fontSize) / 1000);
- }
+ }
+
+ /**
+ * Map a java character (unicode) to a font character
+ * Default uses CodePointMapping
+ */
+ public char mapChar(char c) {
+ try {
+ FontMetric fm=fontInfo.getMetricsFor(fontFamily, fontStyle,
+ fontWeight);
+ if (fm instanceof org.apache.fop.render.pdf.Font) {
+ org.apache.fop.render.pdf.Font f=
+ (org.apache.fop.render.pdf.Font)fm;
+ return f.mapChar(c);
+ }
+ } catch (Exception e) {}
+
+ // Use default CodePointMapping
+ if (c > 127) {
+ char d = org.apache.fop.render.pdf.CodePointMapping.map[c];
+ if (d != 0) {
+ c = d;
+ } else {
+ c = '#';
+ }
+ }
+
+ return c;
+ }
}
+
+
+
diff --git a/src/org/apache/fop/layout/LineArea.java b/src/org/apache/fop/layout/LineArea.java
index 01052ef9d..5f31fed46 100644
--- a/src/org/apache/fop/layout/LineArea.java
+++ b/src/org/apache/fop/layout/LineArea.java
@@ -184,7 +184,9 @@ public class LineArea extends Area {
*/
//Space must be alloted to the page number, so currently we give it 3 spaces
- int width = currentFontState.width(32) * 3;
+
+ int width = currentFontState.width(currentFontState.mapChar(' '));
+
PageNumberInlineArea pia =
new PageNumberInlineArea(currentFontState, this.red,
@@ -214,6 +216,10 @@ public class LineArea extends Area {
int wordStart = start;
int wordLength = 0;
int wordWidth = 0;
+ // With CID fonts, space isn't neccecary currentFontState.width(32)
+ int whitespaceWidth =
+ currentFontState.width(currentFontState.mapChar(' '));
+
char[] data = new char[odata.length];
for (int count = 0; count < odata.length; count++) {
data[count] = odata[count];
@@ -224,18 +230,10 @@ public class LineArea extends Area {
int charWidth;
/* get the character */
char c = data[i];
-
- if (c > 127) {
- /* this class shouldn't be hard coded */
- char d = org.apache.fop.render.pdf.CodePointMapping.map[c];
- if (d != 0) {
- c = data[i] = d;
- } else {
- MessageHandler.error("ch" + (int) c + "?");
- c = data[i] = '#';
- }
- }
-
+ if (!((c == ' ') || (c == '\n') || (c == '\r') ||
+ (c == '\t')))
+ c = data[i] = currentFontState.mapChar(c);
+
charWidth = currentFontState.width(c);
if ((c == ' ') || (c == '\n') || (c == '\r') ||
@@ -248,12 +246,12 @@ public class LineArea extends Area {
if (this.whiteSpaceCollapse ==
WhiteSpaceCollapse.FALSE) {
if (c == ' ') {
- spaceWidth += currentFontState.width(32);
+ spaceWidth += whitespaceWidth;
} else if (c == '\n') {
// force line break
return i;
} else if (c == '\t') {
- spaceWidth += 8 * currentFontState.width(32);
+ spaceWidth += 8 * whitespaceWidth;
}
} // else ignore it
@@ -339,7 +337,7 @@ public class LineArea extends Area {
embeddedLinkStart = 0; //reset embeddedLinkStart since a space was encountered
- spaceWidth = currentFontState.width(32);
+ spaceWidth = whitespaceWidth;
/*
here is the place for space-treatment value 'ignore':
@@ -359,7 +357,7 @@ public class LineArea extends Area {
// force a line break
return i;
} else if (c == '\t') {
- spaceWidth = currentFontState.width(32);
+ spaceWidth = whitespaceWidth;
}
}
@@ -370,7 +368,7 @@ public class LineArea extends Area {
if (this.whiteSpaceCollapse ==
WhiteSpaceCollapse.FALSE) {
prev = WHITESPACE;
- spaceWidth = currentFontState.width(32);
+ spaceWidth = whitespaceWidth;
} else {
// skip over it
start++;
diff --git a/src/org/apache/fop/pdf/PDFCIDFont.java b/src/org/apache/fop/pdf/PDFCIDFont.java
index f13141da0..65588c6a6 100644
--- a/src/org/apache/fop/pdf/PDFCIDFont.java
+++ b/src/org/apache/fop/pdf/PDFCIDFont.java
@@ -69,6 +69,7 @@ public class PDFCIDFont extends PDFObject {
protected PDFWArray w2;
protected PDFCIDSystemInfo systemInfo;
protected PDFCIDFontDescriptor descriptor;
+ protected PDFCMap cmap;
/**
* /CIDToGIDMap (only for CIDFontType2, see p 212)
* can be either "Identity" (default) or a PDFStream
@@ -79,14 +80,15 @@ public class PDFCIDFont extends PDFObject {
/**
* create the /Font object
*/
- public PDFCIDFont(int number, String basefont, String cidtype,
- int dw, int[] w, String registry, String ordering, int supplement,
- PDFCIDFontDescriptor descriptor) {
+ public PDFCIDFont(int number, String basefont, byte cidtype,
+ int dw, int[] w,
+ String registry, String ordering, int supplement,
+ PDFCIDFontDescriptor descriptor) {
super(number);
this.basefont = basefont;
- this.cidtype = cidtype;
+ this.cidtype = TYPE_NAMES[(int)cidtype];
this.dw = new Integer(dw);
this.w = new PDFWArray();
this.w.addEntry(0, w);
@@ -95,19 +97,20 @@ public class PDFCIDFont extends PDFObject {
this.systemInfo = new PDFCIDSystemInfo(registry, ordering, supplement);
this.descriptor = descriptor;
this.cidMap = null;
+ this.cmap = null;
}
/**
* create the /Font object
*/
- public PDFCIDFont(int number, String basefont, String cidtype,
+ public PDFCIDFont(int number, String basefont, byte cidtype,
int dw, PDFWArray w, PDFCIDSystemInfo systemInfo,
PDFCIDFontDescriptor descriptor) {
super(number);
this.basefont = basefont;
- this.cidtype = cidtype;
+ this.cidtype = TYPE_NAMES[(int)cidtype];
this.dw = new Integer(dw);
this.w = w;
this.dw2 = null;
@@ -115,6 +118,7 @@ public class PDFCIDFont extends PDFObject {
this.systemInfo = systemInfo;
this.descriptor = descriptor;
this.cidMap = null;
+ this.cmap = null;
}
/** set the /DW attribute */
@@ -137,6 +141,13 @@ public class PDFCIDFont extends PDFObject {
this.dw2 = new int[] {posY, displacementY};
}
+ /**
+ * Set the CMap used as /ToUnicode cmap
+ */
+ public void setCMAP(PDFCMap cmap) {
+ this.cmap = cmap;
+ }
+
/** set the /W2 array */
public void setW2(PDFWArray w2) {
this.w2 = w2;
@@ -172,16 +183,20 @@ public class PDFCIDFont extends PDFObject {
p.append(cidMap.referencePDF());
}
p.append(" \n/Subtype /"); p.append(this.cidtype);
- p.append("\n"); p.append(systemInfo.toPDF());
+ p.append("\n"); p.append(systemInfo.toPDFString());
p.append("\n/FontDescriptor ");
p.append(this.descriptor.referencePDF());
+
+ if (cmap != null) {
+ p.append("\n/ToUnicode ");
+ p.append(cmap.referencePDF());
+ }
if (dw != null) {
p.append("\n/DW "); p.append(this.dw);
}
if (w != null) {
p.append("\n/W ");
- p.append(w.toPDF());
- p.append(" \n>>\nendobj\n");
+ p.append(w.toPDFString());
}
if (dw2 != null) {
p.append("\n/DW2 ["); // always two values, see p 211
@@ -191,9 +206,11 @@ public class PDFCIDFont extends PDFObject {
}
if (w2 != null) {
p.append("\n/W2 ");
- p.append(w2.toPDF());
+ p.append(w2.toPDFString());
p.append(" \n>>\nendobj\n");
}
+ p.append(" \n>>\nendobj\n");
return p.toString();
}
}
+
diff --git a/src/org/apache/fop/pdf/PDFCIDFontDescriptor.java b/src/org/apache/fop/pdf/PDFCIDFontDescriptor.java
index 9e8cddec5..eabc818e6 100644
--- a/src/org/apache/fop/pdf/PDFCIDFontDescriptor.java
+++ b/src/org/apache/fop/pdf/PDFCIDFontDescriptor.java
@@ -92,6 +92,7 @@ public class PDFCIDFontDescriptor extends PDFFontDescriptor {
}
protected void fillInPDF(StringBuffer p) {
+ p.append("\n/MissingWidth 500\n");
if (lang != null) {
p.append("\n/Lang /"); p.append(lang);
}
diff --git a/src/org/apache/fop/pdf/PDFCMap.java b/src/org/apache/fop/pdf/PDFCMap.java
index 1a086a9af..de0292fb0 100644
--- a/src/org/apache/fop/pdf/PDFCMap.java
+++ b/src/org/apache/fop/pdf/PDFCMap.java
@@ -150,6 +150,12 @@ public class PDFCMap extends PDFStream {
this.wMode = mode;
}
+ public void addContents() {
+ StringBuffer p=new StringBuffer();
+ fillInPDF(p);
+ add(p.toString());
+ }
+
/**
* set the base CMap
*
@@ -169,16 +175,59 @@ public class PDFCMap extends PDFStream {
}
public void fillInPDF(StringBuffer p) {
- p.append(" /Type /CMap\n/CMapName /" + name);
- p.append("\n"); p.append(sysInfo.toPDF());
- p.append("\n/WMode "); p.append(wMode);
- if (base != null) {
- p.append("\n/UseCMap ");
- if (base instanceof String) {
- p.append("/"+base);
- } else { // base instanceof PDFStream
- p.append(((PDFStream)base).referencePDF());
- }
- }
+ //p.append("/Type /CMap\n");
+ //p.append(sysInfo.toPDFString());
+ //p.append("/CMapName /" + name);
+ //p.append("\n");
+ p.append("%!PS-Adobe-3.0 Resource-CMap\n");
+ p.append("%%DocumentNeededResources: ProcSet (CIDInit)\n");
+ p.append("%%IncludeResource: ProcSet (CIDInit)\n");
+ p.append("%%BeginResource: CMap (" + name + ")\n");
+ p.append("%%EndComments\n");
+
+ p.append("/CIDInit /ProcSet findresource begin\n");
+ p.append("12 dict begin\n");
+ p.append("begincmap\n");
+
+ p.append("/CIDSystemInfo 3 dict dup begin\n");
+ p.append(" /Registry (Adobe) def\n");
+ p.append(" /Ordering (Identity) def\n");
+ p.append(" /Supplement 0 def\n");
+ p.append("end def\n");
+
+ p.append("/CMapVersion 1 def\n");
+ p.append("/CMapType 1 def\n");
+ p.append("/CMapName /" + name + " def\n");
+
+ p.append("1 begincodespacerange\n");
+ p.append("<0000> <FFFF>\n");
+ p.append("endcodespacerange\n");
+ p.append("1 begincidrange\n");
+ p.append("<0000> <FFFF> 0\n");
+ p.append("endcidrange\n");
+
+ //p.append("1 beginbfrange\n");
+ //p.append("<0020> <0100> <0000>\n");
+ //p.append("endbfrange\n");
+
+ p.append("endcmap\n");
+ p.append("CMapName currentdict /CMap defineresource pop\n");
+ p.append("end\n");
+ p.append("end\n");
+ p.append("%%EndResource\n");
+ p.append("%%EOF\n");
+ /*
+ p.append(" /Type /CMap\n/CMapName /" + name);
+ p.append("\n");
+ p.append("\n/WMode "); p.append(wMode);
+ if (base != null) {
+ p.append("\n/UseCMap ");
+ if (base instanceof String) {
+ p.append("/"+base);
+ } else { // base instanceof PDFStream
+ p.append(((PDFStream)base).referencePDF());
+ }
+ }
+ */
}
}
diff --git a/src/org/apache/fop/pdf/PDFDocument.java b/src/org/apache/fop/pdf/PDFDocument.java
index 7f55fda80..7d2c7ec2e 100644
--- a/src/org/apache/fop/pdf/PDFDocument.java
+++ b/src/org/apache/fop/pdf/PDFDocument.java
@@ -61,6 +61,8 @@ import org.apache.fop.image.FopImage;
import org.apache.fop.layout.LinkSet;
import org.apache.fop.datatypes.ColorSpace;
+import org.apache.fop.render.pdf.CIDFont;
+
import org.apache.fop.datatypes.IDReferences;
import org.apache.fop.layout.Page;
import org.apache.fop.layout.FontMetric;
@@ -751,59 +753,119 @@ public class PDFDocument {
/* create a PDFFont with the next object number and add to the
list of objects */
if (descriptor == null) {
- PDFFont font = new PDFFont(++this.objectcount, fontname, PDFFont.TYPE1,
- basefont, encoding);
+ PDFFont font = new PDFFont(++this.objectcount, fontname,
+ PDFFont.TYPE1,
+ basefont, encoding);
this.objects.addElement(font);
return font;
} else {
- byte subtype=PDFFont.TYPE1;
- if (metrics instanceof org.apache.fop.render.pdf.Font)
- subtype=((org.apache.fop.render.pdf.Font)metrics).getSubType();
-
- PDFFontNonBase14 font = (PDFFontNonBase14)PDFFont.createFont(
+ byte subtype=PDFFont.TYPE1;
+ if (metrics instanceof org.apache.fop.render.pdf.Font)
+ subtype=((org.apache.fop.render.pdf.Font)metrics).getSubType();
+
+ PDFFontDescriptor pdfdesc = makeFontDescriptor(descriptor,
+ subtype);
+
+ PDFFontNonBase14 font = null;
+ if (subtype == PDFFont.TYPE0) {
+ PDFCMap cmap = new PDFCMap(++this.objectcount,
+ "fop-ucs-H",
+ new PDFCIDSystemInfo("Adobe",
+ "Identity",
+ 0));
+ cmap.addContents();
+ this.objects.addElement(cmap);
+
+ font = (PDFFontNonBase14)PDFFont.createFont(
+ ++this.objectcount, fontname,
+ subtype, basefont, cmap);
+ } else {
+
+ font = (PDFFontNonBase14)PDFFont.createFont(
++this.objectcount, fontname,
subtype, basefont, encoding);
+ }
this.objects.addElement(font);
- PDFFontDescriptor pdfdesc = makeFontDescriptor(descriptor);
+
font.setDescriptor(pdfdesc);
- font.setWidthMetrics(metrics.getFirstChar(), metrics.getLastChar(),
- makeArray(metrics.getWidths(1)));
+
+ if (subtype == PDFFont.TYPE0) {
+ CIDFont cidMetrics = (CIDFont)metrics;
+ PDFCIDSystemInfo sysInfo =
+ new PDFCIDSystemInfo(cidMetrics.getRegistry(),
+ cidMetrics.getOrdering(),
+ cidMetrics.getSupplement());
+ PDFCIDFont cidFont =
+ new PDFCIDFont(++this.objectcount, basefont,
+ cidMetrics.getCidType(),
+ cidMetrics.getDefaultWidth(),
+ cidMetrics.getWidths(),
+ sysInfo, (PDFCIDFontDescriptor)pdfdesc);
+ this.objects.addElement(cidFont);
+
+ //((PDFFontType0)font).setCMAP(cmap);
+
+ ((PDFFontType0)font).setDescendantFonts(cidFont);
+ } else {
+ font.setWidthMetrics(metrics.getFirstChar(),
+ metrics.getLastChar(),
+ makeArray(metrics.getWidths(1)));
+ }
+
return font;
}
}
/**
- * make a /FontDescriptor object for a CID font
+ * make a /FontDescriptor object
*/
- public PDFFontDescriptor makeFontDescriptor(FontDescriptor desc) {
-
- /* create a PDFFontDescriptor with the next object number and add to
- the list of objects */
- PDFFontDescriptor font =
- new PDFFontDescriptor(++this.objectcount,
- desc.fontName(), desc.getAscender(), desc.getDescender(),
- desc.getCapHeight(), desc.getFlags(),
- new PDFRectangle(desc.getFontBBox()), desc.getStemV(),
- desc.getItalicAngle());
-
- // Check if embedding of this font is enabled in the configurationfile
- // and that the font is embeddable
- java.util.Vector cfgv=
- org.apache.fop.configuration.Configuration.getListValue("embed-fonts", 0);
- if (cfgv!=null && cfgv.contains(desc.fontName()) && desc.isEmbeddable()) {
- PDFStream stream=desc.getFontFile(this.objectcount+1);
- if (stream!=null) {
- this.objectcount++;
- font.setFontFile(desc.getSubType(), stream);
- this.objects.addElement(font);
- this.objects.addElement(stream);
- }
- } else {
- this.objects.addElement(font);
- }
+ public PDFFontDescriptor makeFontDescriptor(FontDescriptor desc,
+ byte subtype) {
+ PDFFontDescriptor font = null;
+
+ if (subtype == PDFFont.TYPE0) {
+ // CID Font
+ font =
+ new PDFCIDFontDescriptor(++this.objectcount,
+ desc.fontName(),
+ desc.getFontBBox(),
+ //desc.getAscender(),
+ //desc.getDescender(),
+ desc.getCapHeight(),
+ desc.getFlags(),
+ //new PDFRectangle(desc.getFontBBox()),
+ desc.getItalicAngle(),
+ desc.getStemV(),
+ null); //desc.getLang(),
+ //null);//desc.getPanose());
+ } else {
+ // Create normal FontDescriptor
+ font =
+ new PDFFontDescriptor(++this.objectcount,
+ desc.fontName(),
+ desc.getAscender(),
+ desc.getDescender(),
+ desc.getCapHeight(),
+ desc.getFlags(),
+ new PDFRectangle(desc.getFontBBox()),
+ desc.getStemV(),
+ desc.getItalicAngle());
+ }
+ // Check if the font is embeddable
+ if (desc.isEmbeddable()) {
+ PDFStream stream=desc.getFontFile(this.objectcount+1);
+ if (stream!=null) {
+ this.objectcount++;
+ font.setFontFile(desc.getSubType(), stream);
+ this.objects.addElement(font);
+ this.objects.addElement(stream);
+ }
+ } else {
+ this.objects.addElement(font);
+ }
return font;
- }
+ }
/**
diff --git a/src/org/apache/fop/pdf/PDFFont.java b/src/org/apache/fop/pdf/PDFFont.java
index fefc42547..ed43a8017 100644
--- a/src/org/apache/fop/pdf/PDFFont.java
+++ b/src/org/apache/fop/pdf/PDFFont.java
@@ -136,10 +136,9 @@ public class PDFFont extends PDFObject {
public static PDFFont createFont(int number, String fontname,
byte subtype, String basefont, Object encoding) {
switch (subtype) {
- /*
case TYPE0 :
- return new PDFFontType0(number, fontname, subtype, basefont, encoding);
- */
+ return new PDFFontType0(number, fontname, subtype,
+ basefont, encoding);
case TYPE1 :
case MMTYPE1 :
return new PDFFontType1(number, fontname, subtype, basefont, encoding);
@@ -175,7 +174,10 @@ public class PDFFont extends PDFObject {
PDFFontNonBase14 font;
switch (subtype) {
case TYPE0 :
- return null; // should not happend
+ font = new PDFFontType0(number, fontname, subtype,
+ basefont, encoding);
+ font.setDescriptor(descriptor);
+ return font;
case TYPE1 :
case MMTYPE1 :
font = new PDFFontType1(number, fontname, subtype, basefont, encoding);
diff --git a/src/org/apache/fop/pdf/PDFFontDescriptor.java b/src/org/apache/fop/pdf/PDFFontDescriptor.java
index 97fd60e72..b13030d24 100644
--- a/src/org/apache/fop/pdf/PDFFontDescriptor.java
+++ b/src/org/apache/fop/pdf/PDFFontDescriptor.java
@@ -180,10 +180,13 @@ public class PDFFontDescriptor extends PDFObject {
p.append("\n/FontFile ");
break;
case PDFFont.TRUETYPE:
+ p.append("\n/FontFile2 ");
+ break;
+ case PDFFont.TYPE0:
p.append("\n/FontFile2 ");
break;
default:
- p.append("\n/FontFile3 ");
+ p.append("\n/FontFile2 ");
}
p.append(fontfile.referencePDF());
}
diff --git a/src/org/apache/fop/pdf/PDFFontType0.java b/src/org/apache/fop/pdf/PDFFontType0.java
index 7cc0003ca..7ca15647c 100644
--- a/src/org/apache/fop/pdf/PDFFontType0.java
+++ b/src/org/apache/fop/pdf/PDFFontType0.java
@@ -49,17 +49,18 @@
*/
package org.apache.fop.pdf;
-
/**
* class representing a Type0 font.
*
* Type0 fonts are specified on page 208 and onwards of the PDF 1.3 spec.
*/
-public class PDFFontType0 extends PDFFont {
+public class PDFFontType0 extends PDFFontNonBase14 {
/** this should be an array of CIDFont but only the first one is used */
protected PDFCIDFont descendantFonts;
+ protected PDFCMap cmap;
+
/**
* create the /Font object
*
@@ -78,6 +79,7 @@ public class PDFFontType0 extends PDFFont {
/* set fields using paramaters */
this.descendantFonts = null;
+ cmap=null;
}
/**
@@ -111,13 +113,19 @@ public class PDFFontType0 extends PDFFont {
this.descendantFonts = descendantFonts;
}
+ public void setCMAP(PDFCMap cmap) {
+ this.cmap=cmap;
+ }
/**
* fill in the specifics for the font's subtype
*/
- protected void fillInPDF(StringBuffer p) {
- if (descendantFonts != null) {
- p.append("\n/DescendantFonts [ "+ this.descendantFonts.referencePDF() + " ] ");
- }
-
- }
+ protected void fillInPDF(StringBuffer p) {
+ if (descendantFonts != null) {
+ p.append("\n/DescendantFonts [ " +
+ this.descendantFonts.referencePDF() + " ] ");
+ }
+ if (cmap != null) {
+ p.append("\n/ToUnicode "+cmap.referencePDF());
+ }
+ }
}
diff --git a/src/org/apache/fop/pdf/PDFWArray.java b/src/org/apache/fop/pdf/PDFWArray.java
index acbdd07c5..be1ed8b8e 100644
--- a/src/org/apache/fop/pdf/PDFWArray.java
+++ b/src/org/apache/fop/pdf/PDFWArray.java
@@ -132,7 +132,7 @@ public class PDFWArray {
metrics = m;
}
public void fillInPDF(StringBuffer p) {
- p.setLength(0);
+ //p.setLength(0);
p.append(start); p.append(" [");
for (int i = 0; i < metrics.length; i++) {
p.append(this.metrics[i]);
diff --git a/src/org/apache/fop/render/pdf/CIDFont.java b/src/org/apache/fop/render/pdf/CIDFont.java
new file mode 100644
index 000000000..a8eff598b
--- /dev/null
+++ b/src/org/apache/fop/render/pdf/CIDFont.java
@@ -0,0 +1,29 @@
+package org.apache.fop.render.pdf;
+
+import org.apache.fop.pdf.PDFWArray;
+
+public abstract class CIDFont extends Font {
+
+ // Required
+ public abstract String getCidBaseFont();
+ public abstract byte getCidType();
+ public abstract String getCharEncoding();
+ public abstract String getRegistry();
+ public abstract String getOrdering();
+ public abstract int getSupplement();
+ // Optional
+ public int getDefaultWidth() { return 0; }
+ public PDFWArray getWidths() { return null; }
+ // public int getWinCharSet() { return 0; }
+
+ // Need For FOP
+
+ /**
+ *Returns CMap Object .
+ *<p>
+ *If this method does not return null , the mapping from character codes
+ *to a font number is performed in FOP . When the getCidType() method
+ *returns CIDFontType2 , this method must not return null .
+ */
+ public CMap getCMap() { return null; }
+}
diff --git a/src/org/apache/fop/render/pdf/CMap.java b/src/org/apache/fop/render/pdf/CMap.java
new file mode 100644
index 000000000..8b40e3ec3
--- /dev/null
+++ b/src/org/apache/fop/render/pdf/CMap.java
@@ -0,0 +1,55 @@
+/*-- $Id$ --
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Fop" and "Apache Software Foundation" must not be used to
+ endorse or promote products derived from this software without prior
+ written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation and was originally created by
+ James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ Software Foundation, please see <http://www.apache.org/>.
+
+ */
+package org.apache.fop.render.pdf;
+
+public interface CMap {
+ public abstract char mapping(char ch);
+}
diff --git a/src/org/apache/fop/render/pdf/Font.java b/src/org/apache/fop/render/pdf/Font.java
index 2801d558a..3bb151a04 100644
--- a/src/org/apache/fop/render/pdf/Font.java
+++ b/src/org/apache/fop/render/pdf/Font.java
@@ -58,22 +58,38 @@ import org.apache.fop.layout.FontMetric;
*/
public abstract class Font implements FontMetric {
- /**
- * get the encoding of the font
- */
+ /**
+ * get the encoding of the font
+ */
public abstract String encoding();
- /**
- * get the base font name
- */
+ /**
+ * get the base font name
+ */
public abstract String fontName();
+
+ /**
+ * get the subtype of the font, default is TYPE1
+ */
+ public byte getSubType() {
+ return org.apache.fop.pdf.PDFFont.TYPE1;
+ }
- /**
- * get the subtype of the font, default is TYPE1
- */
- public byte getSubType() {
- return org.apache.fop.pdf.PDFFont.TYPE1;
- }
+ /**
+ * Provide a default mapping
+ */
+ public char mapChar(char c) {
+ // Use default CodePointMapping
+ if (c > 127) {
+ char d = org.apache.fop.render.pdf.CodePointMapping.map[c];
+ if (d != 0) {
+ c = d;
+ } else {
+ c = '#';
+ }
+ }
+ return c;
+ }
}
diff --git a/src/org/apache/fop/render/pdf/FontReader.java b/src/org/apache/fop/render/pdf/FontReader.java
new file mode 100644
index 000000000..153ab4a36
--- /dev/null
+++ b/src/org/apache/fop/render/pdf/FontReader.java
@@ -0,0 +1,334 @@
+/*-- $Id$ --
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Fop" and "Apache Software Foundation" must not be used to
+ endorse or promote products derived from this software without prior
+ written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation and was originally created by
+ James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ Software Foundation, please see <http://www.apache.org/>.
+
+ */
+
+package org.apache.fop.render.pdf;
+import org.apache.fop.render.pdf.fonts.*;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.XMLReader;
+import org.xml.sax.SAXException;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.Attributes;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+import java.util.Hashtable;
+import org.apache.fop.pdf.PDFWArray;
+import org.apache.fop.pdf.PDFCIDFont;
+import org.apache.fop.configuration.ConfigurationReader;
+
+/**
+ * Class for reading a metric.xml file and creating a font object.
+ * Typical usage:
+ <pre>
+ FontReader reader = new FontReader(<path til metrics.xml>);
+ reader.setFontEmbedPath(<path to a .ttf or .pfb file or null to diable embedding>);
+ reader.useKerning(true);
+ Font f = reader.getFont();
+ </pre>
+*/
+public class FontReader extends DefaultHandler {
+ private Locator locator = null;
+ private boolean isCID = false;
+ private MultiByteFont multiFont = null;
+ private SingleByteFont singleFont = null;
+ private Font returnFont = null;
+ //private SingleByteFont singleFont = null;
+ private String text = null;
+
+ private Vector cidWidths = null;
+ private int cidWidthIndex = 0;
+
+ private Hashtable currentKerning = null;
+
+ private Vector bfranges = null;
+
+ private void createFont(String path) throws IOException {
+ XMLReader parser = ConfigurationReader.createParser();
+ if (parser == null)
+ throw new IOException("Unable to create SAX parser");
+
+ try {
+ parser.setFeature("http://xml.org/sax/features/namespace-prefixes",
+ false);
+ } catch (SAXException e) {
+ throw new IOException ("You need a SAX parser which supports " +
+ "SAX version 2");
+ }
+
+ parser.setContentHandler(this);
+
+ try {
+ parser.parse(path);
+ } catch (SAXException e) {
+ throw new IOException(e.getMessage());
+ }
+ }
+
+ /**
+ * Sets the path to embed a font. a null value disables font embedding
+ */
+ public void setFontEmbedPath(String path) {
+ if (isCID)
+ multiFont.embedFileName=path;
+ else
+ singleFont.embedFileName=path;
+ }
+
+ /**
+ * Enable/disable use of kerning for the font
+ */
+ public void useKerning(boolean kern) {
+ if (isCID)
+ multiFont.useKerning = true;
+ else
+ singleFont.useKerning = true;
+ }
+
+
+ /**
+ * Get the generated font object
+ */
+ public Font getFont() {
+ return returnFont;
+ }
+
+ /**
+ * Construct a FontReader object from a path to a metric.xml file
+ * and read metric data
+ */
+ public FontReader(String path) throws IOException {
+ createFont(path);
+ }
+
+ public void startDocument() {
+ }
+
+ public void setDocumentLocator(Locator locator) {
+ this.locator = locator;
+ }
+
+ public void startElement(String uri, String localName,
+ String qName, Attributes attributes) {
+ if (localName.equals("font-metrics")) {
+ if ("TYPE0".equals(attributes.getValue("type"))) {
+ multiFont = new MultiByteFont();
+ returnFont = multiFont;
+ isCID = true;
+ } else if ("TRUETYPE".equals(attributes.getValue("type"))) {
+ singleFont = new SingleByteFont();
+ singleFont.subType = org.apache.fop.pdf.PDFFont.TRUETYPE;
+ returnFont = singleFont;
+ isCID = false;
+ } else {
+ singleFont = new SingleByteFont();
+ singleFont.subType = org.apache.fop.pdf.PDFFont.TYPE1;
+ returnFont = singleFont;
+ isCID = false;
+ }
+ } else if ("embed".equals(localName)) {
+ if (isCID) {
+ // This *is* annoying... should create a common
+ // interface for sing/multibytefonts...
+ multiFont.embedFileName = attributes.getValue("file");
+ multiFont.embedResourceName = attributes.getValue("class");
+ } else {
+ singleFont.embedFileName = attributes.getValue("file");
+ singleFont.embedResourceName = attributes.getValue("class");
+ }
+ } else if ("cid-widths".equals(localName)) {
+ cidWidthIndex = getInt(attributes.getValue("start-index"));
+ cidWidths = new Vector();
+ } else if ("kerning".equals(localName)) {
+ currentKerning = new Hashtable();
+ if (isCID)
+ multiFont.kerning.put(new Integer(attributes.getValue("kpx1")),
+ currentKerning);
+ else
+ singleFont.kerning.put(new Integer(attributes.getValue("kpx1")),
+ currentKerning);
+ } else if ("bfranges".equals(localName)) {
+ bfranges = new Vector();
+ } else if ("bf".equals(localName)) {
+ BFEntry entry = new BFEntry();
+ entry.unicodeStart = getInt(attributes.getValue("us"));
+ entry.unicodeEnd = getInt(attributes.getValue("ue"));
+ entry.glyphStartIndex = getInt(attributes.getValue("gi"));
+ bfranges.addElement(entry);
+ } else if ("wx".equals(localName)) {
+ cidWidths.addElement(new Integer(attributes.getValue("w")));
+ } else if ("widths".equals(localName)) {
+ singleFont.width = new int[256];
+ } else if ("char".equals(localName)) {
+ try {
+ singleFont.width[Integer.parseInt(attributes.getValue("idx"))] =
+ Integer.parseInt(attributes.getValue("wdt"));
+ } catch (NumberFormatException ne) {
+ System.out.println("Malformed width in metric file: " +
+ ne.getMessage());
+ }
+ } else if ("pair".equals(localName)) {
+ currentKerning.put(new Integer(attributes.getValue("kpx2")),
+ new Integer(attributes.getValue("kern")));
+ }
+ }
+
+ private int getInt(String str) {
+ int ret = 0;
+ try {
+ ret = Integer.parseInt(str);
+ } catch (Exception e) {}
+ return ret;
+ }
+
+ public void endElement(String uri, String localName, String qName) {
+ if ("font-name".equals(localName))
+ if (isCID)
+ multiFont.fontName = text;
+ else
+ singleFont.fontName = text;
+ else if ("cap-height".equals(localName))
+ if (isCID)
+ multiFont.capHeight = getInt(text);
+ else
+ singleFont.capHeight = getInt(text);
+ else if ("x-height".equals(localName))
+ if (isCID)
+ multiFont.xHeight = getInt(text);
+ else
+ singleFont.xHeight = getInt(text);
+ else if ("ascender".equals(localName))
+ if (isCID)
+ multiFont.ascender = getInt(text);
+ else
+ singleFont.ascender = getInt(text);
+ else if ("descender".equals(localName))
+ if (isCID)
+ multiFont.descender = getInt(text);
+ else
+ singleFont.descender = getInt(text);
+ else if ("left".equals(localName))
+ if (isCID)
+ multiFont.fontBBox[0] = getInt(text);
+ else
+ singleFont.fontBBox[0] = getInt(text);
+ else if ("bottom".equals(localName))
+ if (isCID)
+ multiFont.fontBBox[1] = getInt(text);
+ else
+ singleFont.fontBBox[1] = getInt(text);
+ else if ("right".equals(localName))
+ if (isCID)
+ multiFont.fontBBox[2] = getInt(text);
+ else
+ singleFont.fontBBox[2] = getInt(text);
+ else if ("first-char".equals(localName))
+ singleFont.firstChar = getInt(text);
+ else if ("last-char".equals(localName))
+ singleFont.lastChar = getInt(text);
+ else if ("top".equals(localName))
+ if (isCID)
+ multiFont.fontBBox[3] = getInt(text);
+ else
+ singleFont.fontBBox[3] = getInt(text);
+ else if ("flags".equals(localName))
+ if (isCID)
+ multiFont.flags = getInt(text);
+ else
+ singleFont.flags = getInt(text);
+ else if ("stemv".equals(localName))
+ if (isCID)
+ multiFont.stemV = getInt(text);
+ else
+ singleFont.stemV = getInt(text);
+ else if ("italic-angle".equals(localName))
+ if (isCID)
+ multiFont.italicAngle = getInt(text);
+ else
+ singleFont.italicAngle = getInt(text);
+ else if ("missing-width".equals(localName))
+ if (isCID)
+ multiFont.missingWidth = getInt(text);
+ else
+ singleFont.missingWidth = getInt(text);
+ else if ("cid-type".equals(localName)) {
+ if ("CIDFontType2".equals(text))
+ multiFont.cidType = PDFCIDFont.CID_TYPE2;
+ } else if ("default-width".equals(localName)) {
+ multiFont.defaultWidth = getInt(text);
+ } else if ("cid-widths".equals(localName)) {
+ int[] wds = new int[cidWidths.size()];
+ int j = 0;
+ for (Enumeration e = cidWidths.elements(); e.hasMoreElements();) {
+ Integer i = (Integer)e.nextElement();
+ wds[j++] = i.intValue();
+ }
+
+ multiFont.warray.addEntry(cidWidthIndex, wds);
+ multiFont.width = wds;
+
+ } else if ("bfranges".equals(localName)) {
+ BFEntry[] entries = new BFEntry[bfranges.size()];
+ bfranges.copyInto(entries);
+ multiFont.bfentries = entries;
+ }
+
+ }
+
+ public void characters(char[] ch, int start, int length) {
+ char c[] = new char[length];
+ System.arraycopy(ch, start, c, 0, length);
+ text = new String(c);
+ }
+
+}
+
+
diff --git a/src/org/apache/fop/render/pdf/FontSetup.java b/src/org/apache/fop/render/pdf/FontSetup.java
index c2209a921..396d9cb46 100644
--- a/src/org/apache/fop/render/pdf/FontSetup.java
+++ b/src/org/apache/fop/render/pdf/FontSetup.java
@@ -57,10 +57,13 @@ import org.apache.fop.layout.FontInfo;
import org.apache.fop.layout.FontDescriptor;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFResources;
+import org.apache.fop.configuration.Configuration;
+import org.apache.fop.configuration.FontTriplet;
// Java
import java.util.Enumeration;
import java.util.Hashtable;
+import java.util.Vector;
/**
* sets up the PDF fonts.
@@ -95,7 +98,7 @@ public class FontSetup {
fontInfo.addMetrics("F12", new CourierBoldOblique());
fontInfo.addMetrics("F13", new Symbol());
fontInfo.addMetrics("F14", new ZapfDingbats());
-
+
//Custom type 1 fonts step 1/2
// fontInfo.addMetrics("F15", new OMEP());
// fontInfo.addMetrics("F16", new GaramondLightCondensed());
@@ -209,8 +212,53 @@ public class FontSetup {
"bold");
fontInfo.addFontProperties("F9", "Computer-Modern-Typewriter",
"normal", "normal");
+
+ /* Add configured fonts */
+ addConfiguredFonts(fontInfo, 15);
}
+ /**
+ * Add fonts from configuration file starting with
+ * internalnames F<num>
+ */
+ public static void addConfiguredFonts(FontInfo fontInfo, int num) {
+
+ String internalName=null;
+ FontReader reader = null;
+
+ Vector fontInfos = Configuration.getFonts();
+ for (Enumeration e = fontInfos.elements(); e.hasMoreElements();) {
+ org.apache.fop.configuration.FontInfo configFontInfo =
+ (org.apache.fop.configuration.FontInfo)e.nextElement();
+
+ try {
+ String metricsFile = configFontInfo.getMetricsFile();
+ if (metricsFile != null) {
+ internalName = "F"+num;
+ num++;
+ reader = new FontReader(metricsFile);
+ reader.useKerning(configFontInfo.getKerning());
+ reader.setFontEmbedPath(configFontInfo.getEmbedFile());
+ fontInfo.addMetrics(internalName, reader.getFont());
+
+ Vector triplets = configFontInfo.getFontTriplets();
+ for (Enumeration t = triplets.elements(); t.hasMoreElements();) {
+ FontTriplet triplet = (FontTriplet)t.nextElement();
+
+ fontInfo.addFontProperties(internalName,
+ triplet.getName(),
+ triplet.getStyle(),
+ triplet.getWeight());
+ }
+ }
+ } catch (Exception ex) {
+ MessageHandler.error("Failed to read font metrics file " +
+ configFontInfo.getMetricsFile() +
+ " : " + ex.getMessage());
+ }
+ }
+ }
+
/**
* add the fonts in the font info to the PDF document
*
@@ -218,7 +266,7 @@ public class FontSetup {
* @param fontInfo font info object to get font information from
*/
public static void addToResources(PDFDocument doc, FontInfo fontInfo) {
- Hashtable fonts = fontInfo.getFonts();
+ Hashtable fonts = fontInfo.getUsedFonts();
Enumeration e = fonts.keys();
PDFResources resources = doc.getResources();
while (e.hasMoreElements()) {
diff --git a/src/org/apache/fop/render/pdf/PDFRenderer.java b/src/org/apache/fop/render/pdf/PDFRenderer.java
index 0954856d5..ae7c0d1c6 100644
--- a/src/org/apache/fop/render/pdf/PDFRenderer.java
+++ b/src/org/apache/fop/render/pdf/PDFRenderer.java
@@ -147,6 +147,8 @@ public class PDFRenderer implements Renderer {
/** the current colour for use in svg */
private PDFColor currentColour = new PDFColor(0, 0, 0);
+ private FontInfo fontInfo;
+
// previous values used for text-decoration drawing
int prevUnderlineXEndPos;
int prevUnderlineYEndPos;
@@ -175,8 +177,6 @@ public class PDFRenderer implements Renderer {
/** The width of the previous word. Used to calculate space between */
int prevWordWidth = 0;
- boolean useKerning;
-
private PDFOutline rootOutline;
/**
@@ -184,10 +184,6 @@ public class PDFRenderer implements Renderer {
*/
public PDFRenderer() {
this.pdfDoc = new PDFDocument();
-
- String cfgKern = Configuration.getStringValue("use-kerning");
- useKerning = ("yes".equals(cfgKern) || "true".equals(cfgKern));
-
}
/**
@@ -224,6 +220,8 @@ public class PDFRenderer implements Renderer {
}
renderRootExtensions(areaTree);
+ FontSetup.addToResources(this.pdfDoc, fontInfo);
+
MessageHandler.logln("writing out PDF");
this.pdfDoc.output(stream);
}
@@ -654,16 +652,23 @@ public class PDFRenderer implements Renderer {
Hashtable kerning = null;
boolean kerningAvailable = false;
- if (useKerning) {
- kerning = area.getFontState().getKerning();
- if (kerning != null && !kerning.isEmpty()) {
- kerningAvailable = true;
- }
- }
-
+ kerning = area.getFontState().getKerning();
+ if (kerning != null && !kerning.isEmpty()) {
+ kerningAvailable = true;
+ }
+
String name = area.getFontState().getFontName();
int size = area.getFontState().getFontSize();
+ // This assumes that *all* CIDFonts use a /ToUnicode mapping
+ boolean useMultiByte = false;
+ Font f = (Font)area.getFontState().getFontInfo().getFonts().get(name);
+ if (f instanceof CIDFont)
+ useMultiByte=true;
+ //String startText = useMultiByte ? "<FEFF" : "(";
+ String startText = useMultiByte ? "<" : "(";
+ String endText = useMultiByte ? ">" : ")";
+
PDFColor theAreaColor = new PDFColor((double) area.getRed(),
(double) area.getGreen(),
(double) area.getBlue());
@@ -726,7 +731,7 @@ public class PDFRenderer implements Renderer {
closeText();
pdf.append("1 0 0 1 " +(rx / 1000f) + " " +
- (bl / 1000f) + " Tm [(");
+ (bl / 1000f) + " Tm [" + startText);
prevWordY = bl;
textOpen = true;
}
@@ -734,7 +739,7 @@ public class PDFRenderer implements Renderer {
// express the space between words in thousandths of an em
int space = prevWordX - rx + prevWordWidth;
float emDiff = (float)space / (float)currentFontSize * 1000f;
- pdf.append(emDiff + " (");
+ pdf.append(emDiff + " " + startText);
}
prevWordWidth = area.getContentWidth();
prevWordX = rx;
@@ -745,10 +750,10 @@ public class PDFRenderer implements Renderer {
// for every word.
pdf.append("1 0 0 1 " +(rx / 1000f) + " " + (bl / 1000f) + " Tm ");
if (kerningAvailable) {
- pdf.append(" [(");
+ pdf.append(" [" + startText);
}
else {
- pdf.append(" (");
+ pdf.append(" " + startText);
}
}
@@ -768,27 +773,33 @@ public class PDFRenderer implements Renderer {
char ch = s.charAt(i);
String prepend = "";
- if (ch > 127) {
- pdf.append("\\");
- pdf.append(Integer.toOctalString((int) ch));
- } else {
- switch (ch) {
- case '(':
- case ')':
- case '\\':
- prepend = "\\";
- break;
+ if (!useMultiByte) {
+ if(ch > 127) {
+ pdf.append("\\");
+ pdf.append(Integer.toOctalString((int) ch));
+ } else {
+ switch (ch) {
+ case '(':
+ case ')':
+ case '\\':
+ prepend = "\\";
+ break;
+ }
+ pdf.append(getUnicodeString(prepend+ch, useMultiByte));
}
- pdf.append(prepend+ch);
- }
+ } else {
+ pdf.append(getUnicodeString(prepend+ch, useMultiByte));
+ }
+
if (kerningAvailable && (i+1) < l) {
- pdf.append(addKerning((new Character(ch)).toString(),
- (new Character(s.charAt(i+1))).toString(),
- kerning));
- }
-
+ pdf.append(addKerning((new Integer((int)ch)),
+ (new Integer((int)s.charAt(i+1))),
+ kerning,
+ startText, endText));
+ }
+
}
- pdf.append(") ");
+ pdf.append(endText + " ");
if (!OPTIMIZE_TEXT) {
if (kerningAvailable) {
pdf.append("] TJ\n");
@@ -807,6 +818,45 @@ public class PDFRenderer implements Renderer {
}
+
+ /**
+ * Convert a string to a unicode hex representation
+ */
+ private String getUnicodeString(StringBuffer str, boolean useMultiByte) {
+ return getUnicodeString(str.toString(), useMultiByte);
+ }
+
+ /**
+ * Convert a string to a multibyte hex representation
+ */
+ private String getUnicodeString(String str, boolean useMultiByte) {
+ if (!useMultiByte) {
+ return str;
+ } else {
+ StringBuffer buf = new StringBuffer(str.length()*4);
+ byte[] uniBytes = null;
+ try {
+ uniBytes = str.getBytes("UnicodeBigUnmarked");
+ } catch (Exception e) {
+ // This should never fail
+ }
+
+ for (int i = 0; i < uniBytes.length; i++) {
+ int b = (uniBytes[i] < 0) ? (int)(256+uniBytes[i])
+ : (int)uniBytes[i];
+
+ String hexString=Integer.toHexString(b);
+ if (hexString.length()==1)
+ buf=buf.append("0"+hexString);
+ else
+ buf=buf.append(hexString);
+ }
+
+ return buf.toString();
+ }
+ }
+
+
/** Checks to see if we have some text rendering commands open
* still and writes out the TJ command to the stream if we do
*/
@@ -886,7 +936,9 @@ public class PDFRenderer implements Renderer {
}
- private StringBuffer addKerning(String ch1, String ch2, Hashtable kerning) {
+ private StringBuffer addKerning(Integer ch1, Integer ch2,
+ Hashtable kerning, String startText,
+ String endText) {
Hashtable h2=(Hashtable)kerning.get(ch1);
int pwdt=0;
StringBuffer buf=new StringBuffer("");
@@ -895,7 +947,7 @@ public class PDFRenderer implements Renderer {
Integer wdt=(Integer)h2.get(ch2);
if (wdt!=null) {
pwdt=-wdt.intValue();
- buf=buf.append(") " + pwdt + " (");
+ buf=buf.append(endText + " " + pwdt + " " + startText);
}
}
return buf;
@@ -1021,8 +1073,8 @@ public class PDFRenderer implements Renderer {
* @param fontInfo font info to set up
*/
public void setupFontInfo(FontInfo fontInfo) {
+ this.fontInfo = fontInfo;
FontSetup.setup(fontInfo);
- FontSetup.addToResources(this.pdfDoc, fontInfo);
}
/**
diff --git a/src/org/apache/fop/render/pdf/fonts/BFEntry.java b/src/org/apache/fop/render/pdf/fonts/BFEntry.java
new file mode 100644
index 000000000..a0f8f198c
--- /dev/null
+++ b/src/org/apache/fop/render/pdf/fonts/BFEntry.java
@@ -0,0 +1,73 @@
+/*-- $Id$ --
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Fop" and "Apache Software Foundation" must not be used to
+ endorse or promote products derived from this software without prior
+ written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation and was originally created by
+ James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ Software Foundation, please see <http://www.apache.org/>.
+
+ */
+
+package org.apache.fop.render.pdf.fonts;
+
+/**
+ * This is just a holder class for bfentries - not get/put methods provided
+ */
+public class BFEntry {
+ public int unicodeStart;
+ public int unicodeEnd;
+ public int glyphStartIndex;
+
+ public BFEntry() {
+ }
+
+ public BFEntry (int unicodeStart,
+ int unicodeEnd,
+ int glyphStartIndex) {
+ this.unicodeStart = unicodeStart;
+ this.unicodeEnd = unicodeEnd;
+ this.glyphStartIndex = glyphStartIndex;
+ }
+
+}
diff --git a/src/org/apache/fop/render/pdf/fonts/MultiByteFont.java b/src/org/apache/fop/render/pdf/fonts/MultiByteFont.java
new file mode 100644
index 000000000..7b55e843d
--- /dev/null
+++ b/src/org/apache/fop/render/pdf/fonts/MultiByteFont.java
@@ -0,0 +1,236 @@
+
+
+package org.apache.fop.render.pdf.fonts;
+
+import org.apache.fop.render.pdf.Font;
+import org.apache.fop.layout.FontDescriptor;
+import org.apache.fop.fonts.Glyphs;
+import org.apache.fop.pdf.PDFStream;
+import org.apache.fop.pdf.PDFWArray;
+import org.apache.fop.pdf.PDFCIDFont;
+import org.apache.fop.render.pdf.CIDFont;
+import org.apache.fop.render.pdf.CMap;
+import org.apache.fop.pdf.PDFTTFStream;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.File;
+import java.io.BufferedInputStream;
+import java.util.Hashtable;
+
+/**
+ * Generic MultiByte (CID) font
+ */
+public class MultiByteFont extends CIDFont implements FontDescriptor {
+ public String fontName = null;
+ public String encoding = "Identity-H";
+
+ public int capHeight = 0;
+ public int xHeight = 0;
+ public int ascender = 0;
+ public int descender = 0;
+ public int[] fontBBox = {0, 0, 0, 0};
+
+ public String embedFileName = null;
+ public String embedResourceName = null;
+ public PDFTTFStream embeddedFont=null;
+
+ public int flags = 4;
+ public int stemV = 0;
+ public int italicAngle = 0;
+ public int missingWidth = 0;
+ public int defaultWidth = 0;
+ public byte cidType = PDFCIDFont.CID_TYPE2;
+
+ public Hashtable kerning=new Hashtable();
+ public boolean useKerning = true;
+
+ public PDFWArray warray=new PDFWArray();
+ public int width[] = null;
+
+ public BFEntry[] bfentries = null;
+
+
+ public MultiByteFont() {}
+
+ public final boolean hasKerningInfo() {
+ return (useKerning & kerning.isEmpty());
+ }
+ public final java.util.Hashtable getKerningInfo() {return kerning;}
+
+ public byte getSubType() {
+ return org.apache.fop.pdf.PDFFont.TYPE0;
+ }
+
+ public String getLang() {return null;}
+ public String getPanose() {return null;}
+ public int getAvgWidth() {return -1;}
+ public int getMinWidth() {return -1;}
+ public int getMaxWidth() {return -1;}
+ public int getleading() {return -1;}
+ public int getStemH() {return 0;}
+ public int getMissingWidth() {return missingWidth;}
+ public int getDefaultWidth() {return defaultWidth;}
+ public String getRegistry() {return "Adobe";}
+ public String getOrdering() {return "UCS";}
+ public int getSupplement() {return 0;}
+ public byte getCidType() {return cidType;}
+ public String getCidBaseFont() {return fontName;}
+ public String getCharEncoding() {return "Identity-H";}
+
+ public PDFWArray getWidths() {
+ return warray;
+ }
+
+ public boolean isEmbeddable() {
+ return (embedFileName==null && embedResourceName==null) ? false : true;
+ }
+
+
+ public PDFStream getFontFile(int i) {
+ InputStream instream=null;
+
+ int iniSize = 256000;
+ int incSize = 128000;
+ // Get file first
+ if (embedFileName!=null)
+ try {
+ File ef = new File(embedFileName);
+ iniSize = (int)ef.length()+1;
+ incSize = (int)ef.length()/10;
+ instream=new FileInputStream(embedFileName);
+ } catch (Exception e) {
+ System.out.println("Failed to embed fontfile: "+embedFileName);
+ }
+
+ // Get resource
+ if (instream==null && embedResourceName!=null)
+ try {
+ instream=new BufferedInputStream(this.getClass().getResourceAsStream(embedResourceName));
+ } catch (Exception e) {
+ System.out.println("Failed to embed fontresource: "+embedResourceName);
+ }
+
+ if (instream==null)
+ return (PDFStream)null;
+
+ // Read fontdata
+ byte[] file = new byte[iniSize];
+ int fsize = 0;
+
+ try {
+ int l = instream.read(file, 0, iniSize);
+ fsize += l;
+
+ if (l==iniSize) {
+ // More to read - needs to extend
+ byte[] tmpbuf;
+
+ while (l > 0) {
+ tmpbuf = new byte[file.length + incSize];
+ System.arraycopy(file, 0, tmpbuf, 0, file.length);
+ l=instream.read(tmpbuf, file.length, incSize);
+ fsize += l;
+ file = tmpbuf;
+
+ if (l < incSize) // whole file read. No need to loop again
+ l=0;
+ }
+ }
+
+ // Only TrueType CID fonts are supported now
+ embeddedFont=new PDFTTFStream(i, fsize);
+ embeddedFont.addFilter("flate");
+ embeddedFont.addFilter("ascii-85");
+ embeddedFont.setData(file, fsize);
+ instream.close();
+ } catch (Exception e) {}
+
+ return (PDFStream) embeddedFont;
+ }
+
+ public String encoding() {
+ return encoding;
+ }
+
+ public String fontName() {
+ return fontName;
+ }
+
+ public int getAscender() {return ascender;}
+ public int getDescender() {return descender;}
+ public int getCapHeight() {return capHeight;}
+
+ public int getAscender(int size) {
+ return size * ascender;
+ }
+
+ public int getCapHeight(int size) {
+ return size * capHeight;
+ }
+
+ public int getDescender(int size) {
+ return size * descender;
+ }
+
+ public int getXHeight(int size) {
+ return size * xHeight;
+ }
+
+ public int getFlags() {
+ return flags;
+ }
+
+ public int[] getFontBBox() {
+ return fontBBox;
+ }
+
+ public int getItalicAngle() {
+ return italicAngle;
+ }
+
+ public int getStemV() {
+ return stemV;
+ }
+
+ public int getFirstChar() {
+ return 0;
+ }
+
+ public int getLastChar() {
+ return 255;
+ }
+
+ public int width(int i, int size) {
+ return size * width[i];
+ }
+
+ public int[] getWidths(int size) {
+ int[] arr = new int[width.length];
+ System.arraycopy(width, 0, arr, 0, width.length-1);
+ for( int i = 0; i < arr.length; i++) arr[i] *= size;
+ return arr;
+ }
+
+ public char mapChar(char c) {
+ int idx = (int)c;
+ int retIdx = 0;
+
+ for (int i = 0; (i < bfentries.length) && retIdx == 0; i++) {
+
+ /*
+ System.out.println("us: "+bfentries[i].unicodeStart +
+ " ue: "+bfentries[i].unicodeEnd+
+ " gi: "+bfentries[i].glyphStartIndex);
+ */
+ if (bfentries[i].unicodeStart <= idx &&
+ bfentries[i].unicodeEnd >= idx) {
+ retIdx=bfentries[i].glyphStartIndex + idx -
+ bfentries[i].unicodeStart;
+ }
+ }
+
+ //System.out.println("Map: "+ c + " (" + idx + ") = " + retIdx);
+ return (char)retIdx;
+ }
+}
+
diff --git a/src/org/apache/fop/render/pdf/fonts/SingleByteFont.java b/src/org/apache/fop/render/pdf/fonts/SingleByteFont.java
new file mode 100644
index 000000000..413d2e7d3
--- /dev/null
+++ b/src/org/apache/fop/render/pdf/fonts/SingleByteFont.java
@@ -0,0 +1,196 @@
+
+
+package org.apache.fop.render.pdf.fonts;
+
+import org.apache.fop.render.pdf.Font;
+import org.apache.fop.layout.FontDescriptor;
+import org.apache.fop.fonts.Glyphs;
+import org.apache.fop.pdf.PDFStream;
+import org.apache.fop.pdf.PDFTTFStream;
+import org.apache.fop.pdf.PDFT1Stream;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.util.Hashtable;
+
+/**
+ * Generic SingleByte font
+ */
+public class SingleByteFont extends Font implements FontDescriptor {
+ public String fontName = null;
+ public String encoding = "WinAnsiEncoding";
+
+ public int capHeight = 0;
+ public int xHeight = 0;
+ public int ascender = 0;
+ public int descender = 0;
+ public int[] fontBBox = {0, 0, 0, 0};
+
+ public String embedFileName = null;
+ public String embedResourceName = null;
+ public PDFStream embeddedFont=null;
+
+ public int firstChar = 0;
+ public int lastChar = 255;
+ public int flags = 4;
+ public int stemV = 0;
+ public int italicAngle = 0;
+ public int missingWidth = 0;
+
+ public Hashtable kerning=new Hashtable();
+ public boolean useKerning = true;
+
+ public int width[] = null;
+ public byte subType = 0;
+
+ public final boolean hasKerningInfo() {
+ return (useKerning & kerning.isEmpty());
+ }
+
+ public final java.util.Hashtable getKerningInfo() {return kerning;}
+
+ public byte getSubType() {
+ return subType;
+ }
+
+ public int getAvgWidth() {return -1;}
+ public int getMinWidth() {return -1;}
+ public int getMaxWidth() {return -1;}
+ public int getleading() {return -1;}
+ public int getStemH() {return 0;}
+ public int getMissingWidth() {return missingWidth;}
+
+ public String getCharEncoding() {return encoding;}
+
+ public boolean isEmbeddable() {
+ return (embedFileName==null && embedResourceName==null) ? false : true;
+ }
+
+
+ public PDFStream getFontFile(int i) {
+ InputStream instream=null;
+
+ // Get file first
+ if (embedFileName!=null)
+ try {
+ instream=new FileInputStream(embedFileName);
+ } catch (Exception e) {
+ System.out.println("Failed to embed fontfile: "+embedFileName);
+ }
+
+ // Get resource
+ if (instream==null && embedResourceName!=null)
+ try {
+ instream=new BufferedInputStream(this.getClass().getResourceAsStream(embedResourceName));
+ } catch (Exception e) {
+ System.out.println("Failed to embed fontresource: "+embedResourceName);
+ }
+
+ if (instream==null)
+ return (PDFStream)null;
+
+ // Read fontdata
+ byte[] file = new byte[128000];
+ int fsize = 0;
+
+ try {
+ int l = instream.read(file, 0, 128000);
+ fsize += l;
+
+ if (l==128000) {
+ // More to read - needs to extend
+ byte[] tmpbuf;
+
+ while (l > 0) {
+ tmpbuf = new byte[file.length + 64000];
+ System.arraycopy(file, 0, tmpbuf, 0, file.length);
+ l=instream.read(tmpbuf, file.length, 64000);
+ fsize += l;
+ file = tmpbuf;
+
+ if (l < 64000) // whole file read. No need to loop again
+ l=0;
+ }
+ }
+
+ if (subType == org.apache.fop.pdf.PDFFont.TYPE1) {
+ embeddedFont=new PDFT1Stream(i, fsize);
+ ((PDFT1Stream)embeddedFont).setData(file, fsize);
+ } else {
+ embeddedFont=new PDFTTFStream(i, fsize);
+ ((PDFTTFStream)embeddedFont).setData(file, fsize);
+ }
+
+ embeddedFont.addFilter("flate");
+ embeddedFont.addFilter("ascii-85");
+ instream.close();
+ } catch (Exception e) {}
+
+ return (PDFStream) embeddedFont;
+ }
+
+ public String encoding() {
+ return encoding;
+ }
+
+ public String fontName() {
+ return fontName;
+ }
+
+ public int getAscender() {return ascender;}
+ public int getDescender() {return descender;}
+ public int getCapHeight() {return capHeight;}
+
+ public int getAscender(int size) {
+ return size * ascender;
+ }
+
+ public int getCapHeight(int size) {
+ return size * capHeight;
+ }
+
+ public int getDescender(int size) {
+ return size * descender;
+ }
+
+ public int getXHeight(int size) {
+ return size * xHeight;
+ }
+
+ public int getFlags() {
+ return flags;
+ }
+
+ public int[] getFontBBox() {
+ return fontBBox;
+ }
+
+ public int getItalicAngle() {
+ return italicAngle;
+ }
+
+ public int getStemV() {
+ return stemV;
+ }
+
+ public int getFirstChar() {
+ return 0;
+ //return firstChar;
+ }
+
+ public int getLastChar() {
+ return lastChar;
+ }
+
+ public int width(int i, int size) {
+ return size * width[i];
+ }
+
+ public int[] getWidths(int size) {
+ int[] arr = new int[width.length];
+ System.arraycopy(width, 0, arr, 0, width.length-1);
+ for( int i = 0; i < arr.length; i++) arr[i] *= size;
+ return arr;
+ }
+}
+