]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
enabling CID keyed truetype fonts; this gives support
authorfotis <fotis@unknown>
Tue, 27 Feb 2001 12:30:36 +0000 (12:30 +0000)
committerfotis <fotis@unknown>
Tue, 27 Feb 2001 12:30:36 +0000 (12:30 +0000)
         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

35 files changed:
conf/config.xml
conf/userconfig.xml
src/org/apache/fop/configuration/Configuration.java
src/org/apache/fop/configuration/ConfigurationParser.java
src/org/apache/fop/configuration/ConfigurationReader.java
src/org/apache/fop/configuration/FontInfo.java [new file with mode: 0644]
src/org/apache/fop/configuration/FontTriplet.java [new file with mode: 0644]
src/org/apache/fop/fonts/Glyphs.java
src/org/apache/fop/fonts/PFMFile.java
src/org/apache/fop/fonts/TTFCmapEntry.java
src/org/apache/fop/fonts/TTFDirTabEntry.java
src/org/apache/fop/fonts/TTFFile.java
src/org/apache/fop/fonts/TTFMtxEntry.java
src/org/apache/fop/fonts/apps/PFMReader.java
src/org/apache/fop/fonts/apps/TTFReader.java
src/org/apache/fop/layout/FontInfo.java
src/org/apache/fop/layout/FontState.java
src/org/apache/fop/layout/LineArea.java
src/org/apache/fop/pdf/PDFCIDFont.java
src/org/apache/fop/pdf/PDFCIDFontDescriptor.java
src/org/apache/fop/pdf/PDFCMap.java
src/org/apache/fop/pdf/PDFDocument.java
src/org/apache/fop/pdf/PDFFont.java
src/org/apache/fop/pdf/PDFFontDescriptor.java
src/org/apache/fop/pdf/PDFFontType0.java
src/org/apache/fop/pdf/PDFWArray.java
src/org/apache/fop/render/pdf/CIDFont.java [new file with mode: 0644]
src/org/apache/fop/render/pdf/CMap.java [new file with mode: 0644]
src/org/apache/fop/render/pdf/Font.java
src/org/apache/fop/render/pdf/FontReader.java [new file with mode: 0644]
src/org/apache/fop/render/pdf/FontSetup.java
src/org/apache/fop/render/pdf/PDFRenderer.java
src/org/apache/fop/render/pdf/fonts/BFEntry.java [new file with mode: 0644]
src/org/apache/fop/render/pdf/fonts/MultiByteFont.java [new file with mode: 0644]
src/org/apache/fop/render/pdf/fonts/SingleByteFont.java [new file with mode: 0644]

index 3d520fec1d8ad6ce6cfd0067b4363fac194228e9..138cb32d53f22a34daa652d084c32b55c1ad66a8 100644 (file)
@@ -50,4 +50,6 @@
       <!-- <value>ascii-hex</value> -->
     </list>
   </entry>
+  <fonts>
+  </fonts>
 </configuration>
index 9c962dec8231bb1182cc26f8fe2f384ea6ab23d6..c5f4b5871e7153ec1b2c24e2eafccfd66735a83c 100644 (file)
@@ -42,30 +42,32 @@ basedir: normally the base directory is the directory where the fo file is
 
 <!--
 ************************************************************************
-  Use kerning, default is to noe use kerning, uncomment to use kerning
+  Add fonts here
 ************************************************************************
 -->
 
-  <entry>
-    <key>use-kerning</key>
-    <value>yes</value>
-  </entry>
-
+<fonts>
+ <!-- example -->
+ <!--
+ <font metrics-file="arial.xml" kerning="yes" embed-file="arial.ttf">
+    <font-triplet name="Arial" style="normal" weight="normal"/>
+    <font-triplet name="ArialMT" style="normal" weight="normal"/>
+ </font>
+ <font metrics-file="arialb.xml" kerning="yes" embed-file="arialb.ttf">
+    <font-triplet name="Arial" style="normal" weight="bold"/>
+    <font-triplet name="ArialMT" style="normal" weight="bold"/>
+ </font>
+ <font metrics-file="ariali.xml" kerning="yes" embed-file="ariali.ttf">
+    <font-triplet name="Arial" style="italics" weight="normal"/>
+    <font-triplet name="ArialMT" style="italics" weight="normal"/>
+ </font>
+ <font metrics-file="arialbi.xml" kerning="yes" embed-file="arialbi.ttf">
+    <font-triplet name="Arial" style="italics" weight="bold"/>
+    <font-triplet name="ArialMT" style="italics" weight="bold"/>
+ </font>
+ -->
+</fonts>
 
-<!--
-************************************************************************
-   Font embedding, only the fonts mentioned here is embedded 
-   The value is the name of the font (the name is what is returned by
-   the font's fontName() method
-************************************************************************
--->
-  <entry>
-    <key>embed-fonts</key>
-    <list>
-       <value>Perpetua</value>
-       <value>Perpetua,Bold</value>
-    </list>
-  </entry>
 
 </configuration>
 
index 844fede9ebe2b7a00365e64c16aa5b58a3369a0c..0889828416d604c106477fe86a61935e685ad5a4 100644 (file)
@@ -219,6 +219,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
index c5c3d620b3af84430d01f912abedc8f2545f42a4..1dab0e2b73cf137d776af2eae273d114bc27dc27 100644 (file)
@@ -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") ) {                 
         }
     }
 
index 92d7c338a50e62f797d2d8a1080f6ec3d89b2e66..edde15624538e6d65963ed084acafe19b21d4a45 100644 (file)
@@ -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 (file)
index 0000000..07af6b1
--- /dev/null
@@ -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 (file)
index 0000000..d5e927d
--- /dev/null
@@ -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;
+    }
+
+}
+
+
+
+
index cba61bcdb0370895420e6c9a34f6f563f87f8495..99fc076e352e8f6e97cf56bafcdd1ef57ca1d6f2 100644 (file)
@@ -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",
index 5ebb011cc8b0c95e897b1582f52e86b7eb5572bd..f1cae42d3bb96947b20443db2ad215ba5831a5cd 100644 (file)
@@ -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);
         }
     }
 
index af1eb5c007554156d8bb7ba388123fc8508178e0..3e8dd746a5557fdda498afb5e6ca92725296af3e 100644 (file)
  */
 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;
+    }
+                    
 }
index 42fed9f3ac4999a4b3203f199f596f13eb45fd17..30f0c4cfef50da928d6c81f213b61dd33f85a6ba 100644 (file)
@@ -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");
+    }
 }
index 06987e77ac179ae455065c2ce0230277e5f91eb8..02c49bfe14eddc8a90a8420e8c2b2ffd7eeb2b19 100644 (file)
  */
 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;
+    }
+}
index c44c2c965ae8196640867e7e84960ced83756d1a..e1333bd240aafd3061043e182888815d9af23dcc 100644 (file)
 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));
+    }
 }
index c7c1410f269b009167774de3a63fe7aa0f6625a5..581ba20dbfaae2a19010358e1b38fb4516244e2d 100644 (file)
@@ -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();
    }
 }
+
+
+
+
index f7dbe0bfd68bb09209820449a3e28693920466db..e4ff7774bd7355f3c179f244ee023e54c9293f80 100644 (file)
@@ -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();
       
index 869a54e986362c1e98b8287f36ac00c9e4fb7cf7..84a2a49791fba434b9af0911afc452969a025207 100644 (file)
@@ -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));
   }
 }
index f022ab54a1c6495280daa7c3387c87db46323846..e000b5e779344a7989e6b9b9a609ee39ea29f5d7 100644 (file)
@@ -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;
+    }
 }
+
+
+
index 01052ef9dce5ef860a66afe69a01802de8eb11cd..5f31fed46072afa7652d06cd56abac8556c00014 100644 (file)
@@ -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++;
index f13141da0855a9d22967458ecd385ee45dc921e1..65588c6a65aad5fe512b32a956d9c08b344ccfad 100644 (file)
@@ -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();
        }
 }
+
index 9e8cddec5789fd5ed0668599d95e7aaebb90f87e..eabc818e63ec6a75103c816e235ad25669e4741b 100644 (file)
@@ -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);
        }
index 1a086a9afb54c888d45e3bf1b61561817e99e6c7..de0292fb06e50cecd8805cbd1e50675eb3fd78aa 100644 (file)
@@ -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());
+                }
+            }
+            */
        }
 }
index 7f55fda80e3f796ada379d5fcf88d8db2f817bcd..7d2c7ec2e0bd401f0b0214357a9bfd96c8dba52d 100644 (file)
@@ -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;
-       }
+    }
 
 
        /**
index fefc425475655bcabc940644ec4bf51b7ffcf154..ed43a801772fc0016dc90b527fe3d013fa8af3d3 100644 (file)
@@ -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);
index 97fd60e7215b44c0cd8d7c79a2b1c5d0e2b56a51..b13030d24d14e8409cc64f66072b769624265be1 100644 (file)
@@ -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());
                }
index 7cc0003cac8a21c8f529f839e35c13da9c983af8..7ca15647c2461978a303381148c0ab11f7dc0f80 100644 (file)
 
  */
 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());
+        }
+    }
 }
index acbdd07c5416127d9cda68838985aeac10339b3d..be1ed8b8e998e8b74190392cc089d212fe5ad891 100644 (file)
@@ -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 (file)
index 0000000..a8eff59
--- /dev/null
@@ -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 (file)
index 0000000..8b40e3e
--- /dev/null
@@ -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);
+}
index 2801d558ab30175f2b0a445f2aef30d1f1465787..3bb151a049dbad188938a9fa659d188a0aa340f5 100644 (file)
@@ -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 (file)
index 0000000..153ab4a
--- /dev/null
@@ -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);
+    }
+    
+}
+
+
index c2209a921eedb91b1646c291425f4ed902b08b50..396d9cb46f0248e33d413761489ff7ccd96d60cd 100644 (file)
@@ -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()) {
index 0954856d5e31db18cffe2aa1a9c223a6badb2551..ae7c0d1c65b1ffa66269b9539e1dccbf13d6eb0c 100644 (file)
@@ -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 (file)
index 0000000..a0f8f19
--- /dev/null
@@ -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 (file)
index 0000000..7b55e84
--- /dev/null
@@ -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 (file)
index 0000000..413d2e7
--- /dev/null
@@ -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;
+    }
+}
+