You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by ac...@apache.org on 2008/04/03 11:40:14 UTC

svn commit: r644243 - in /xmlgraphics/fop/branches/Temp_AFPGOCAResources: ./ src/documentation/content/xdocs/trunk/ src/foschema/ src/java/org/apache/fop/fonts/ src/java/org/apache/fop/fonts/autodetect/ src/java/org/apache/fop/fonts/truetype/ src/java/...

Author: acumiskey
Date: Thu Apr  3 02:40:10 2008
New Revision: 644243

URL: http://svn.apache.org/viewvc?rev=644243&view=rev
Log:
Merged revisions 644208,644213 via svnmerge from 
https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk

........
  r644208 | jeremias | 2008-04-03 09:05:14 +0100 (Thu, 03 Apr 2008) | 11 lines
  
  Bugzilla #44737:
  Added support for auto-configuring TrueType Collections. XML font metrics files for *.ttc fonts are not required anymore.
  Submitted by: Jason Harrop <jason.at.plutext.org>
  
  Changes to patch or in addition to the patch:
  - Tab chars removed and Checkstyle issues fixed
  - Some simplifications in the cache handling (CachedFontInfo is obsolete and less cache-private information is exposed to the outside).
  - TTCs are fully detected and registered with FOP.
  - TTCs can also be registered using a "font" element. The new "sub-font" attribute selected the sub-font in the TTC.
  - Bug fixed in TTFFile: Font names were not decoded correctly (ex. font names in Chinese)
  - Minimal docs.
........
  r644213 | jeremias | 2008-04-03 09:13:50 +0100 (Thu, 03 Apr 2008) | 1 line
  
  Oops. Fixed a last-minute change that broke the build.
........

Removed:
    xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/CachedFontInfo.java
Modified:
    xmlgraphics/fop/branches/Temp_AFPGOCAResources/   (props changed)
    xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/documentation/content/xdocs/trunk/fonts.xml
    xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/foschema/fop-configuration.xsd
    xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/EmbedFontInfo.java
    xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/FontCache.java
    xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/FontLoader.java
    xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/LazyFont.java
    xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java
    xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java
    xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/truetype/FontFileReader.java
    xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/truetype/TTFFile.java
    xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
    xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/render/PrintRendererConfigurator.java
    xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/render/java2d/FontSetup.java
    xmlgraphics/fop/branches/Temp_AFPGOCAResources/status.xml

Propchange: xmlgraphics/fop/branches/Temp_AFPGOCAResources/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Thu Apr  3 02:40:10 2008
@@ -1 +1 @@
-/xmlgraphics/fop/trunk:1-643437
+/xmlgraphics/fop/trunk:1-644238

Modified: xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/documentation/content/xdocs/trunk/fonts.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/documentation/content/xdocs/trunk/fonts.xml?rev=644243&r1=644242&r2=644243&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/documentation/content/xdocs/trunk/fonts.xml (original)
+++ xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/documentation/content/xdocs/trunk/fonts.xml Thu Apr  3 02:40:10 2008
@@ -308,6 +308,11 @@
         <source>java -cp build\fop.jar;lib\avalon-framework.jar;lib\commons-logging.jar;lib\commons-io.jar
           org.apache.fop.fonts.apps.TTFReader -ttcname "MS Mincho"
           msmincho.ttc msminch.xml</source>
+        <p>
+          Alternatively, the individual sub-fonts of a TrueType Collections can be selected
+          using the "sub-font" attribute on the "font" element. That means that generating
+          an XML font metrics file for TrueType collections is not necessary anymore.
+        </p>
       </section>
       <section id="register">
         <title>Register Fonts with FOP</title>

Modified: xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/foschema/fop-configuration.xsd
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/foschema/fop-configuration.xsd?rev=644243&r1=644242&r2=644243&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/foschema/fop-configuration.xsd (original)
+++ xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/foschema/fop-configuration.xsd Thu Apr  3 02:40:10 2008
@@ -210,6 +210,7 @@
     </xsd:sequence>
     <xsd:attribute name="metrics-url" type="xsd:anyURI" use="optional"/>
     <xsd:attribute name="embed-url" type="xsd:anyURI" use="optional"/>
+    <xsd:attribute name="sub-font" type="xsd:string" use="optional"/>
     <xsd:attribute name="kerning" use="optional" default="no">
       <xsd:simpleType>
         <xsd:restriction base="xsd:string">

Modified: xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/EmbedFontInfo.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/EmbedFontInfo.java?rev=644243&r1=644242&r2=644243&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/EmbedFontInfo.java (original)
+++ xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/EmbedFontInfo.java Thu Apr  3 02:40:10 2008
@@ -28,7 +28,7 @@
 public class EmbedFontInfo implements Serializable {
     
     /** Serialization Version UID */
-    private static final long serialVersionUID = -9075848379822693399L;
+    private static final long serialVersionUID = 8755432068669997367L;
     
     /** filename of the metrics file */
     protected String metricsFile;
@@ -38,20 +38,27 @@
     protected boolean kerning;
     /** the list of associated font triplets */
     protected List fontTriplets;
-      
+    
+    /** the PostScript name of the font */
+    protected String postScriptName = null;
+    /** the sub-fontname of the font (used for TrueType Collections, null otherwise) */
+    protected String subFontName = null;
+
     /**
      * Main constructor
      * @param metricsFile Path to the xml file containing font metrics
      * @param kerning True if kerning should be enabled
      * @param fontTriplets List of font triplets to associate with this font
      * @param embedFile Path to the embeddable font file (may be null)
+     * @param subFontName the sub-fontname used for TrueType Collections (null otherwise)
      */
     public EmbedFontInfo(String metricsFile, boolean kerning,
-                    List fontTriplets, String embedFile) {
+                    List fontTriplets, String embedFile, String subFontName) {
         this.metricsFile = metricsFile;
         this.embedFile = embedFile;
         this.kerning = kerning;
         this.fontTriplets = fontTriplets;
+        this.subFontName = subFontName;
     }
         
     /**
@@ -86,9 +93,35 @@
         return fontTriplets;
     }
     
+    /**
+     * Returns the sub-fontname name of the font. This is primarily used for TrueType Collections
+     * to select one of the sub-fonts. For all other fonts, this is always null. 
+     * @return the sub-fontname (or null)
+     */
+    public String getSubFontName() {
+        return this.subFontName;
+    }
+    
+    /**
+     * Returns the PostScript name of the font.
+     * @return the PostScript name
+     */
+    public String getPostScriptName() {
+        return postScriptName;
+    }
+    
+    /**
+     * Sets the PostScript name of the font
+     * @param postScriptName the PostScript name
+     */
+    public void setPostScriptName(String postScriptName) {
+        this.postScriptName = postScriptName;
+    }
+    
     /** {@inheritDoc} */
     public String toString() {
         return "metrics-url=" + metricsFile + ",embed-url=" + embedFile
-            + ", kerning=" + kerning + ", font-triplet=" + fontTriplets; 
+            + ", kerning=" + kerning + ", font-triplet=" + fontTriplets
+            + (getSubFontName() != null ? ", sub-font=" + getSubFontName() : ""); 
     }
 }

Modified: xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/FontCache.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/FontCache.java?rev=644243&r1=644242&r2=644243&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/FontCache.java (original)
+++ xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/FontCache.java Thu Apr  3 02:40:10 2008
@@ -26,8 +26,12 @@
 import java.io.ObjectOutputStream;
 import java.io.OutputStream;
 import java.io.Serializable;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
 import java.util.Map;
 
+import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -61,10 +65,11 @@
     /** change lock */
     private transient Object changeLock = new Object();
     
-    /** master mapping of font url -> font info */
-    private Map fontMap = new java.util.HashMap();
+    /** master mapping of font url -> font info.  This needs to be
+     *  a list, since a TTC file may contain more than 1 font. */
+    private Map fontfileMap = new java.util.HashMap(); //Map<String, CachedFontFile>
 
-    /** mapping of font url -> file modified date */
+    /** mapping of font url -> file modified date (for all fonts that have failed to load) */
     private Map failedFontMap = new java.util.HashMap();
 
     /**
@@ -216,7 +221,7 @@
      */
     public boolean containsFont(String embedUrl) {
         if (embedUrl != null) {
-            return fontMap.containsKey(embedUrl);
+            return fontfileMap.containsKey(embedUrl);
         }
         return false;
     }
@@ -228,45 +233,100 @@
      */
     public boolean containsFont(EmbedFontInfo fontInfo) {
         if (fontInfo != null) {
-            return fontMap.containsKey(getCacheKey(fontInfo));
+            return fontfileMap.containsKey(getCacheKey(fontInfo));
         }
         return false;
     }
 
     /**
-     * adds a font info to cache
+     * Tries to identify a File instance from an array of URLs. If there's no file URL in the
+     * array, the method returns null.
+     * @param urls array of possible font urls
+     * @return file font file 
+     */
+    public static File getFileFromUrls(String[] urls) {
+        for (int i = 0; i < urls.length; i++) {
+            String urlStr = urls[i]; 
+            if (urlStr != null) {
+                File fontFile = null;
+                if (urlStr.startsWith("file:")) {
+                    try {
+                        URL url = new URL(urlStr);
+                        fontFile = FileUtils.toFile(url);
+                    } catch (MalformedURLException mfue) {
+                        // do nothing
+                    }
+                }
+                if (fontFile == null) {
+                    fontFile = new File(urlStr);
+                }
+                if (fontFile.exists() && fontFile.canRead()) {
+                    return fontFile;
+                }
+            }
+        } 
+        return null;
+    }
+
+    /**
+     * Adds a font info to cache
      * @param fontInfo font info
      */
     public void addFont(EmbedFontInfo fontInfo) {
         String cacheKey = getCacheKey(fontInfo);
         synchronized (changeLock) {
-            if (!containsFont(cacheKey)) {
+            CachedFontFile cachedFontFile;
+            if (containsFont(cacheKey)) {
+                cachedFontFile = (CachedFontFile)fontfileMap.get(cacheKey);
+                if (!cachedFontFile.containsFont(fontInfo)) {
+                    cachedFontFile.put(fontInfo);
+                }
+            } else {
+                // try and determine modified date
+                File fontFile = getFileFromUrls(new String[]
+                                     {fontInfo.getEmbedFile(), fontInfo.getMetricsFile()});
+                long lastModified = (fontFile != null ? fontFile.lastModified() : -1);
+                cachedFontFile = new CachedFontFile(lastModified);
                 if (log.isTraceEnabled()) {
                     log.trace("Font added to cache: " + cacheKey);
                 }
-                if (fontInfo instanceof CachedFontInfo) {
-                    fontMap.put(cacheKey, fontInfo);
-                } else {
-                    fontMap.put(cacheKey, new CachedFontInfo(fontInfo));
-                }
+                cachedFontFile.put(fontInfo);
+                fontfileMap.put(cacheKey, cachedFontFile);
                 changed = true;
             }
         }
     }
 
     /**
-     * returns a font from the cache
+     * Returns a font from the cache.
      * @param embedUrl font info
-     * @return boolean
+     * @return CachedFontFile object 
      */
-    public CachedFontInfo getFont(String embedUrl) {
+    public CachedFontFile getFontFile(String embedUrl) {
         if (containsFont(embedUrl)) {
-            return (CachedFontInfo)fontMap.get(embedUrl);
+            return (CachedFontFile)fontfileMap.get(embedUrl);
         }
         return null;
     }
     
     /**
+     * Returns the EmbedFontInfo instances belonging to a font file. If the font file was
+     * modified since it was cached the entry is removed and null is returned.
+     * @param embedUrl the font URL
+     * @param lastModified the last modified date/time of the font file
+     * @return the EmbedFontInfo instances or null if there's no cached entry or if it is outdated
+     */
+    public EmbedFontInfo[] getFontInfos(String embedUrl, long lastModified) {
+        CachedFontFile cff = getFontFile(embedUrl);
+        if (cff.lastModified() == lastModified) {
+            return cff.getEmbedFontInfos();
+        } else {
+            removeFont(embedUrl);
+            return null;
+        }
+    }
+    
+    /**
      * removes font from cache
      * @param embedUrl embed url
      */
@@ -276,7 +336,7 @@
                 if (log.isTraceEnabled()) {
                     log.trace("Font removed from cache: " + embedUrl);
                 }
-                fontMap.remove(embedUrl);
+                fontfileMap.remove(embedUrl);
                 changed = true;
             }
         }
@@ -326,9 +386,87 @@
             if (log.isTraceEnabled()) {
                 log.trace("Font cache cleared.");
             }
-            fontMap.clear();
+            fontfileMap.clear();
             failedFontMap.clear();
             changed = true;
         }
+    }
+    
+    /**
+     * Retrieve the last modified date/time of a URL.
+     * @param url the URL
+     * @return the last modified date/time
+     */
+    public static long getLastModified(URL url) {
+        try {
+            URLConnection conn = url.openConnection();
+            try {
+                return conn.getLastModified();
+            } finally {
+                //An InputStream is created even if it's not accessed, but we need to close it.
+                IOUtils.closeQuietly(conn.getInputStream());
+            }
+        } catch (IOException e) {
+            // Should never happen, because URL must be local
+            log.debug("IOError: " + e.getMessage());
+            return 0;
+        }
+    }
+    
+    private static class CachedFontFile implements Serializable {
+        /** file modify date (if available) */
+        private long lastModified = -1;
+
+        private Map filefontsMap = new java.util.HashMap(); //Map<String, EmbedFontInfo>
+        
+        public CachedFontFile(long lastModified) {
+            setLastModified(lastModified);
+        }
+
+        void put(EmbedFontInfo efi) {
+            filefontsMap.put(efi.getPostScriptName(), efi);
+        }
+
+        public boolean containsFont(EmbedFontInfo efi) {
+            if (efi.getPostScriptName() != null) {
+                return filefontsMap.containsKey(efi.getPostScriptName());
+            }
+            return false;
+        }
+
+        public Map getFilefontsMap() {
+            return filefontsMap;
+        }
+
+        public EmbedFontInfo[] getEmbedFontInfos() {
+            return (EmbedFontInfo[])this.filefontsMap.values().toArray(
+                    new EmbedFontInfo[this.filefontsMap.size()]);
+        }
+        
+        /**
+         * Gets the modified timestamp for font file (not always available)
+         * @return modified timestamp
+         */
+        public long lastModified() {
+            return this.lastModified;
+        }
+
+        /**
+         * Gets the modified timestamp for font file
+         * (used for the purposes of font info caching) 
+         * @param lastModified modified font file timestamp
+         */
+        public void setLastModified(long lastModified) {
+            this.lastModified = lastModified;
+        }
+        
+        /**
+         * @return string representation of this object 
+         * {@inheritDoc}
+         */
+        public String toString() {
+            return super.toString() + ", lastModified=" + lastModified;
+        }
+
     }
 }

Modified: xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/FontLoader.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/FontLoader.java?rev=644243&r1=644242&r2=644243&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/FontLoader.java (original)
+++ xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/FontLoader.java Thu Apr  3 02:40:10 2008
@@ -71,36 +71,39 @@
     /**
      * Loads a custom font from a File. In the case of Type 1 fonts, the PFB file must be specified.
      * @param fontFile the File representation of the font
+     * @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise)
      * @param resolver the font resolver to use when resolving URIs
      * @return the newly loaded font
      * @throws IOException In case of an I/O error
      */
-    public static CustomFont loadFont(File fontFile, FontResolver resolver)
+    public static CustomFont loadFont(File fontFile, String subFontName, FontResolver resolver)
                 throws IOException {
-        return loadFont(fontFile.getAbsolutePath(), resolver);
+        return loadFont(fontFile.getAbsolutePath(), subFontName, resolver);
     }
 
     /**
      * Loads a custom font from an URL. In the case of Type 1 fonts, the PFB file must be specified.
      * @param fontUrl the URL representation of the font
+     * @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise)
      * @param resolver the font resolver to use when resolving URIs
      * @return the newly loaded font
      * @throws IOException In case of an I/O error
      */
-    public static CustomFont loadFont(URL fontUrl, FontResolver resolver)
+    public static CustomFont loadFont(URL fontUrl, String subFontName, FontResolver resolver)
                 throws IOException {
-        return loadFont(fontUrl.toExternalForm(), resolver);
+        return loadFont(fontUrl.toExternalForm(), subFontName, resolver);
     }
     
     
     /**
      * Loads a custom font from a URI. In the case of Type 1 fonts, the PFB file must be specified.
      * @param fontFileURI the URI to the font
+     * @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise)
      * @param resolver the font resolver to use when resolving URIs
      * @return the newly loaded font
      * @throws IOException In case of an I/O error
      */
-    public static CustomFont loadFont(String fontFileURI, FontResolver resolver)
+    public static CustomFont loadFont(String fontFileURI, String subFontName, FontResolver resolver)
                 throws IOException {
         fontFileURI = fontFileURI.trim();
         boolean type1 = isType1(fontFileURI);
@@ -108,7 +111,7 @@
         if (type1) {
             loader = new Type1FontLoader(fontFileURI, resolver);
         } else {
-            loader = new TTFFontLoader(fontFileURI, resolver);
+            loader = new TTFFontLoader(fontFileURI, subFontName, resolver);
         }
         return loader.getFont();
     }
@@ -121,7 +124,7 @@
      * @throws IOException In case of an I/O error
      * @throws MalformedURLException If an invalid URL is built
      */
-    protected static InputStream openFontUri(FontResolver resolver, String uri) 
+    public static InputStream openFontUri(FontResolver resolver, String uri) 
                     throws IOException, MalformedURLException {
         InputStream in = null;
         if (resolver != null) {

Modified: xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/LazyFont.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/LazyFont.java?rev=644243&r1=644242&r2=644243&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/LazyFont.java (original)
+++ xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/LazyFont.java Thu Apr  3 02:40:10 2008
@@ -44,6 +44,7 @@
     private String metricsFileName = null;
     private String fontEmbedPath = null;
     private boolean useKerning = false;
+    private String subFontName = null;
 
     private boolean isMetricsLoaded = false;
     private Typeface realFont = null;
@@ -61,6 +62,7 @@
         this.metricsFileName = fontInfo.getMetricsFile();
         this.fontEmbedPath = fontInfo.getEmbedFile();
         this.useKerning = fontInfo.getKerning();
+        this.subFontName = fontInfo.getSubFontName();
         this.resolver = resolver;
     }
 
@@ -123,7 +125,7 @@
                     if (fontEmbedPath == null) {
                         throw new RuntimeException("Cannot load font. No font URIs available.");
                     }
-                    realFont = FontLoader.loadFont(fontEmbedPath, resolver);
+                    realFont = FontLoader.loadFont(fontEmbedPath, this.subFontName, resolver);
                 }
                 if (realFont instanceof FontDescriptor) {
                     realFontDescriptor = (FontDescriptor) realFont;

Modified: xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java?rev=644243&r1=644242&r2=644243&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java (original)
+++ xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java Thu Apr  3 02:40:10 2008
@@ -72,14 +72,15 @@
     }
     
     /**
-     * Font file filter.  Currently searches for files with .ttf and .pfb extensions.
+     * Font file filter.  Currently searches for files with .ttf, .ttc, .otf, and .pfb extensions.
      * @return IOFileFilter font file filter
      */
     protected static IOFileFilter getFileFilter() {
         return FileFilterUtils.andFileFilter(
                 FileFilterUtils.fileFileFilter(),
-                new WildcardFileFilter(new String[] {"*.ttf", "*.otf", "*.pfb"}, IOCase.INSENSITIVE)
-                //TODO Add *.ttc when support for it has been added to the auto-detection mech.
+                new WildcardFileFilter(
+                        new String[] {"*.ttf", "*.otf", "*.pfb", "*.ttc"},
+                        IOCase.INSENSITIVE)
         );
     }
     

Modified: xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java?rev=644243&r1=644242&r2=644243&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java (original)
+++ xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java Thu Apr  3 02:40:10 2008
@@ -19,9 +19,8 @@
 
 package org.apache.fop.fonts.autodetect;
 
-import java.io.IOException;
+import java.io.InputStream;
 import java.net.URL;
-import java.net.URLConnection;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
@@ -32,7 +31,6 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
-import org.apache.fop.fonts.CachedFontInfo;
 import org.apache.fop.fonts.CustomFont;
 import org.apache.fop.fonts.EmbedFontInfo;
 import org.apache.fop.fonts.Font;
@@ -41,6 +39,10 @@
 import org.apache.fop.fonts.FontResolver;
 import org.apache.fop.fonts.FontTriplet;
 import org.apache.fop.fonts.FontUtil;
+import org.apache.fop.fonts.MultiByteFont;
+import org.apache.fop.fonts.truetype.FontFileReader;
+import org.apache.fop.fonts.truetype.TTFFile;
+import org.apache.fop.fonts.truetype.TTFFontLoader;
 
 /**
  * Attempts to determine correct FontInfo
@@ -131,8 +133,13 @@
         generateTripletsFromFont(customFont, fontTripletList);
         String embedUrl;
         embedUrl = fontUrl.toExternalForm();
+        String subFontName = null;
+        if (customFont instanceof MultiByteFont) {
+            subFontName = ((MultiByteFont)customFont).getTTCName();
+        }
         EmbedFontInfo fontInfo = new EmbedFontInfo(null, customFont.isKerningEnabled(),
-                fontTripletList, embedUrl);
+                fontTripletList, embedUrl, subFontName);
+        fontInfo.setPostScriptName(customFont.getFontName());        
         if (fontCache != null) {
             fontCache.addFont(fontInfo);
         }
@@ -145,35 +152,21 @@
      * @param fontUrl font URL. Assumed to be local.
      * @param resolver font resolver used to resolve font
      * @param fontCache font cache (may be null)
-     * @return newly created embed font info
+     * @return an array of newly created embed font info. Generally, this array
+     *         will have only one entry, unless the fontUrl is a TrueType Collection
      */
-    public EmbedFontInfo find(URL fontUrl, FontResolver resolver, FontCache fontCache) {
+    public EmbedFontInfo[] find(URL fontUrl, FontResolver resolver, FontCache fontCache) {
         String embedUrl = null;
         embedUrl = fontUrl.toExternalForm();
         
         long fileLastModified = -1;
         if (fontCache != null) {
-            try {
-                URLConnection conn = fontUrl.openConnection();
-                try {
-                    fileLastModified = conn.getLastModified();
-                } finally {
-                    //An InputStream is created even if it's not accessed, but we need to close it.
-                    IOUtils.closeQuietly(conn.getInputStream());
-                }
-            } catch (IOException e) {
-                // Should never happen, because URL must be local
-                log.debug("IOError: " + e.getMessage());
-                fileLastModified = 0;
-            }
+            fileLastModified = FontCache.getLastModified(fontUrl);
             // firstly try and fetch it from cache before loading/parsing the font file
             if (fontCache.containsFont(embedUrl)) {
-                CachedFontInfo fontInfo = fontCache.getFont(embedUrl);
-                if (fontInfo.lastModified() == fileLastModified) {
-                    return fontInfo;
-                } else {
-                    // out of date cache item
-                    fontCache.removeFont(embedUrl);
+                EmbedFontInfo[] fontInfos = fontCache.getFontInfos(embedUrl, fileLastModified);
+                if (fontInfos != null) {
+                    return fontInfos;
                 }
             // is this a previously failed parsed font?
             } else if (fontCache.isFailedFont(embedUrl, fileLastModified)) {
@@ -184,20 +177,81 @@
             }
         }
         
+        
         // try to determine triplet information from font file
         CustomFont customFont = null;
-        try {
-            customFont = FontLoader.loadFont(fontUrl, resolver);
-        } catch (Exception e) {
-            //TODO Too verbose (it's an error but we don't care if some fonts can't be loaded)
-            if (log.isErrorEnabled()) {
-                log.error("Unable to load font file: " + embedUrl + ". Reason: " + e.getMessage());
+        
+        if (fontUrl.toExternalForm().endsWith(".ttc")) {
+            // Get a list of the TTC Font names
+            List ttcNames = null; //List<String>
+            String fontFileURI = fontUrl.toExternalForm().trim();
+            TTFFontLoader ttfLoader = new TTFFontLoader(fontFileURI, resolver);
+            InputStream in = null;
+            try {
+                in = FontLoader.openFontUri(resolver, fontFileURI);
+                TTFFile ttf = new TTFFile();
+                FontFileReader reader = new FontFileReader(in);
+                ttcNames = ttf.getTTCnames(reader);
+            } catch (Exception e) {
+                log.error(e);
+            } finally {
+                IOUtils.closeQuietly(in);
             }
-            if (fontCache != null) {
-                fontCache.registerFailedFont(embedUrl, fileLastModified);
+
+            List embedFontInfoList = new java.util.ArrayList(); //List<EmbedFontInfo>
+
+            // For each font name ...
+            //for (String fontName : ttcNames) {
+            Iterator ttcNamesIterator = ttcNames.iterator();
+            while (ttcNamesIterator.hasNext()) {
+                String fontName = (String)ttcNamesIterator.next();
+
+                if (log.isDebugEnabled()) {
+                    log.debug("Loading " + fontName);
+                }
+                try {
+                    ttfLoader = new TTFFontLoader(fontFileURI, fontName, resolver);
+                    customFont = ttfLoader.getFont();
+                } catch (Exception e) {
+                    //TODO Too verbose (it's an error but we don't care if some fonts can't be loaded)
+                    //if (log.isErrorEnabled()) {
+                    log.error("Unable to load font file: " + embedUrl + ". Reason: " + e.getMessage());
+                    //}
+                    if (fontCache != null) {
+                        fontCache.registerFailedFont(embedUrl, fileLastModified);
+                    }
+                    continue;
+                }
+                EmbedFontInfo fi = fontInfoFromCustomFont(fontUrl, customFont, fontCache);
+                if (fi != null) {
+                    embedFontInfoList.add(fi);
+                } 
+            }
+            return (EmbedFontInfo[])embedFontInfoList.toArray(
+                    new EmbedFontInfo[embedFontInfoList.size()]);
+        } else {
+            // The normal case
+            try {
+                customFont = FontLoader.loadFont(fontUrl, null, resolver);
+            } catch (Exception e) {
+                //TODO Too verbose (it's an error but we don't care if some fonts can't be loaded)
+                //if (log.isErrorEnabled()) {
+                    log.error("Unable to load font file: " + embedUrl + ". Reason: " + e.getMessage());
+                //}
+                if (fontCache != null) {
+                    fontCache.registerFailedFont(embedUrl, fileLastModified);
+                }
+                return null;
+            }
+            EmbedFontInfo fi = fontInfoFromCustomFont(fontUrl, customFont, fontCache);
+            if (fi != null) {
+                return new EmbedFontInfo[] {fi};
+            } else {
+                return null;
             }
-            return null;
         }
-        return fontInfoFromCustomFont(fontUrl, customFont, fontCache);     
+        
+
     }
+
 }

Modified: xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/truetype/FontFileReader.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/truetype/FontFileReader.java?rev=644243&r1=644242&r2=644243&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/truetype/FontFileReader.java (original)
+++ xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/truetype/FontFileReader.java Thu Apr  3 02:40:10 2008
@@ -19,9 +19,9 @@
  
 package org.apache.fop.fonts.truetype;
 
-import java.io.InputStream;
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 
 import org.apache.commons.io.IOUtils;
 
@@ -310,6 +310,26 @@
         } else {
             encoding = "ISO-8859-1";
         }
+        return new String(tmp, encoding);
+    }
+
+    /**
+     * Read an ISO-8859-1 string of len bytes.
+     *
+     * @param len The length of the string to read
+     * @return A String
+     * @throws IOException If EOF is reached
+     */
+    public final String readTTFString(int len, int encodingID) throws IOException {
+        if ((len + current) > fsize) {
+            throw new java.io.EOFException("Reached EOF, file size=" + fsize);
+        }
+
+        byte[] tmp = new byte[len];
+        System.arraycopy(file, current, tmp, 0, len);
+        current += len;
+        final String encoding;
+        encoding = "UTF-16BE"; //Use this for all known encoding IDs for now
         return new String(tmp, encoding);
     }
 

Modified: xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/truetype/TTFFile.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/truetype/TTFFile.java?rev=644243&r1=644242&r2=644243&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/truetype/TTFFile.java (original)
+++ xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/truetype/TTFFile.java Thu Apr  3 02:40:10 2008
@@ -988,7 +988,10 @@
         if (dirTabs.get("OS/2") != null) {
             seekTab(in, "OS/2", 2 * 2);
             this.usWeightClass = in.readTTFUShort();
+            
+            // usWidthClass
             in.skip(2);
+            
             int fsType = in.readTTFUShort();
             if (fsType == 2) {
                 isEmbeddable = false;
@@ -1123,7 +1126,12 @@
             if (((platformID == 1 || platformID == 3) 
                     && (encodingID == 0 || encodingID == 1))) {
                 in.seekSet(j + in.readTTFUShort());
-                String txt = in.readTTFString(l);
+                String txt;
+                if (platformID == 3) {
+                    txt = in.readTTFString(l, encodingID);
+                } else {
+                    txt = in.readTTFString(l);
+                }
                 
                 if (log.isDebugEnabled()) {
                     log.debug(platformID + " " 
@@ -1147,7 +1155,7 @@
                     }
                     break;
                 case 4:
-                    if (fullName.length() == 0) {
+                    if (fullName.length() == 0 || (platformID == 3 && languageID == 1033)) {
                         fullName = txt;
                     }
                     break;
@@ -1474,6 +1482,59 @@
         }
     }
 
+    /**
+     * Return TTC font names
+     * @param in FontFileReader to read from
+     * @return True if not collection or font name present, false otherwise
+     * @throws IOException In case of an I/O problem
+     */
+    public final List getTTCnames(FontFileReader in) throws IOException {
+        List fontNames = new java.util.ArrayList();
+
+        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();
+            long[] dirOffsets = new long[numDirectories];
+            for (int i = 0; i < numDirectories; i++) {
+                dirOffsets[i] = in.readTTFULong();
+            }
+
+            if (log.isDebugEnabled()) {
+                log.debug("This is a TrueType collection file with "
+                        + numDirectories + " fonts");
+                log.debug("Containing the following fonts: ");
+            }
+
+            for (int i = 0; (i < numDirectories); i++) {
+                in.seekSet(dirOffsets[i]);
+                readDirTabs(in);
+
+                readName(in);
+
+                log.debug(fullName);
+                fontNames.add(fullName);
+
+                // Reset names
+                notice = "";
+                fullName = "";
+                familyNames.clear();
+                postScriptName = "";
+                subFamilyName = "";
+            }
+
+            in.seekSet(0);
+            return fontNames;
+        } else {
+            log.error("Not a TTC!");
+            return null;
+        }
+    }
+    
     /*
      * Helper classes, they are not very efficient, but that really
      * doesn't matter...
@@ -1536,8 +1597,8 @@
      * @throws IOException if unicodeIndex not found
      */
     private Integer unicodeToGlyph(int unicodeIndex) throws IOException {
-        final Integer result = 
-            (Integer) unicodeToGlyphMap.get(new Integer(unicodeIndex));
+        final Integer result
+            = (Integer) unicodeToGlyphMap.get(new Integer(unicodeIndex));
         if (result == null) {
             throw new IOException(
                     "Glyph index not found for unicode value " + unicodeIndex);

Modified: xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java?rev=644243&r1=644242&r2=644243&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java (original)
+++ xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java Thu Apr  3 02:40:10 2008
@@ -34,11 +34,12 @@
 import org.apache.fop.fonts.MultiByteFont;
 
 /**
- * Loads a font into memory directly from the original font file.
+ * Loads a TrueType font into memory directly from the original font file.
  */
 public class TTFFontLoader extends FontLoader {
 
     private MultiByteFont multiFont;
+    private String subFontName;
     
     /**
      * Default constructor
@@ -46,27 +47,50 @@
      * @param resolver the FontResolver for font URI resolution
      */
     public TTFFontLoader(String fontFileURI, FontResolver resolver) {
+        this(fontFileURI, null, resolver);
+    }
+    
+    /**
+     * Additional constructor for TrueType Collections.
+     * @param fontFileURI the URI representing the font file
+     * @param subFontName the sub-fontname of a font in a TrueType Collection (or null for normal
+     *          TrueType fonts)
+     * @param resolver the FontResolver for font URI resolution
+     */
+    public TTFFontLoader(String fontFileURI, String subFontName, FontResolver resolver) {
         super(fontFileURI, resolver);
+        this.subFontName = subFontName;
     }
     
     /** {@inheritDoc} */
     protected void read() throws IOException {
+        read(this.subFontName);
+    }
+
+    /**
+     * Reads a TrueType font. 
+     * @param ttcFontName the TrueType sub-font name of TrueType Collection (may be null for
+     *    normal TrueType fonts)
+     * @throws IOException if an I/O error occurs
+     */
+    private void read(String ttcFontName) throws IOException {
         InputStream in = openFontUri(resolver, this.fontFileURI);
         try {
             TTFFile ttf = new TTFFile();
             FontFileReader reader = new FontFileReader(in);
-            boolean supported = ttf.readFont(reader, null);
+            boolean supported = ttf.readFont(reader, ttcFontName);
             if (!supported) {
                 throw new IOException("TrueType font is not supported: " + fontFileURI);
             }
-            buildFont(ttf);
+            buildFont(ttf, ttcFontName);
             loaded = true;
         } finally {
             IOUtils.closeQuietly(in);
         }
     }
-
-    private void buildFont(TTFFile ttf) {
+    
+    
+    private void buildFont(TTFFile ttf, String ttcFontName) {
         if (ttf.isCFF()) {
             throw new UnsupportedOperationException(
                     "OpenType fonts with CFF data are not supported, yet");
@@ -79,7 +103,7 @@
         returnFont.setFullName(ttf.getFullName());
         returnFont.setFamilyNames(ttf.getFamilyNames());
         returnFont.setFontSubFamilyName(ttf.getSubFamilyName());
-        //multiFont.setTTCName(ttcName)
+        multiFont.setTTCName(ttcFontName);
         returnFont.setCapHeight(ttf.getCapHeight());
         returnFont.setXHeight(ttf.getXHeight());
         returnFont.setAscender(ttf.getLowerCaseAscent());
@@ -91,7 +115,7 @@
         returnFont.setItalicAngle(Integer.parseInt(ttf.getItalicAngle()));
         returnFont.setMissingWidth(0);
         returnFont.setWeight(ttf.getWeightClass());
-        
+                
         multiFont.setCIDType(CIDFontType.CIDTYPE2);
         int[] wx = ttf.getWidths();
         multiFont.setWidthArray(wx);

Modified: xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/render/PrintRendererConfigurator.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/render/PrintRendererConfigurator.java?rev=644243&r1=644242&r2=644243&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/render/PrintRendererConfigurator.java (original)
+++ xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/render/PrintRendererConfigurator.java Thu Apr  3 02:40:10 2008
@@ -36,10 +36,11 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import org.apache.xmlgraphics.util.ClasspathResource;
+
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.apps.FopFactory;
-import org.apache.fop.fonts.CachedFontInfo;
 import org.apache.fop.fonts.EmbedFontInfo;
 import org.apache.fop.fonts.FontCache;
 import org.apache.fop.fonts.FontInfo;
@@ -50,7 +51,6 @@
 import org.apache.fop.fonts.autodetect.FontFileFinder;
 import org.apache.fop.fonts.autodetect.FontInfoFinder;
 import org.apache.fop.util.LogUtil;
-import org.apache.xmlgraphics.util.ClasspathResource;
 
 /**
  * Base Print renderer configurator (mostly handles font configuration)
@@ -230,9 +230,20 @@
             URL fontUrl = (URL)iter.next();
             // parse font to ascertain font info
             FontInfoFinder finder = new FontInfoFinder();
-            EmbedFontInfo fontInfo = finder.find(fontUrl, resolver, fontCache);
-            if (fontInfo != null) {
-                fontInfoList.add(fontInfo);                
+            //EmbedFontInfo fontInfo = finder.find(fontUrl, resolver, fontCache);
+            
+            //List<EmbedFontInfo> embedFontInfoList = finder.find(fontUrl, resolver, fontCache);
+            EmbedFontInfo[] embedFontInfos = finder.find(fontUrl, resolver, fontCache);
+
+            if (embedFontInfos == null) {
+                return;
+            }
+
+            for (int i = 0, c = embedFontInfos.length; i < c; i++) {
+                EmbedFontInfo fontInfo = embedFontInfos[i];
+                if (fontInfo != null) {
+                    fontInfoList.add(fontInfo);
+                }
             }
         }
     }
@@ -257,9 +268,10 @@
      */
     public static EmbedFontInfo getFontInfoFromConfiguration(
             Configuration fontCfg, FontResolver fontResolver, boolean strict, FontCache fontCache)
-    throws FOPException {
+                    throws FOPException {
         String metricsUrl = fontCfg.getAttribute("metrics-url", null);
         String embedUrl = fontCfg.getAttribute("embed-url", null);
+        String subFont = fontCfg.getAttribute("sub-font", null);
 
         if (metricsUrl == null && embedUrl == null) {
             LogUtil.handleError(log, "Font configuration without metric-url or embed-url", strict);
@@ -296,7 +308,7 @@
             LogUtil.handleError(log, "font without font-triplet", strict);
 
             // if not strict try to determine font info from the embed/metrics url
-            File fontFile = CachedFontInfo.getFileFromUrls(new String[] {embedUrl, metricsUrl});
+            File fontFile = FontCache.getFileFromUrls(new String[] {embedUrl, metricsUrl});
             URL fontUrl;
             try {
                 fontUrl = fontFile.toURI().toURL();
@@ -307,7 +319,8 @@
             }
             if (fontFile != null) {
                 FontInfoFinder finder = new FontInfoFinder();
-                return finder.find(fontUrl, fontResolver, fontCache);
+                EmbedFontInfo[] infos = finder.find(fontUrl, fontResolver, fontCache); 
+                return infos[0]; //When subFont is set, only one font is returned
             } else {
                 return null;
             }
@@ -337,7 +350,7 @@
                 }
             }
             
-            fontInfo = new EmbedFontInfo(metricsUrl, useKerning, tripleList, embedUrl);
+            fontInfo = new EmbedFontInfo(metricsUrl, useKerning, tripleList, embedUrl, subFont);
             
             if (fontCache != null) {
                 if (!fontCache.containsFont(fontInfo)) {

Modified: xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/render/java2d/FontSetup.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/render/java2d/FontSetup.java?rev=644243&r1=644242&r2=644243&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/render/java2d/FontSetup.java (original)
+++ xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/render/java2d/FontSetup.java Thu Apr  3 02:40:10 2008
@@ -304,7 +304,7 @@
                     Source fontSource = resolver.resolve(configFontInfo.getEmbedFile());
                     font = new CustomFontMetricsMapper(fontMetrics, fontSource);
                 } else {
-                    CustomFont fontMetrics = FontLoader.loadFont(fontFile, resolver);
+                    CustomFont fontMetrics = FontLoader.loadFont(fontFile, null, resolver);
                     font = new CustomFontMetricsMapper(fontMetrics);
                 }
 

Modified: xmlgraphics/fop/branches/Temp_AFPGOCAResources/status.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_AFPGOCAResources/status.xml?rev=644243&r1=644242&r2=644243&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_AFPGOCAResources/status.xml (original)
+++ xmlgraphics/fop/branches/Temp_AFPGOCAResources/status.xml Thu Apr  3 02:40:10 2008
@@ -59,6 +59,10 @@
       <action context="Renderers" dev="AC" importance="high" type="add">
         Added de-duplication and externalization support for IOCA and GOCA data resource objects.
       </action>
+      <action context="Fonts" dev="JM" type="add" fixes-bug="44737" due-to="Jason Harrop">
+        Added support for auto-configuring TrueType Collections. XML font metrics files for
+        *.ttc fonts are not required anymore.
+      </action>
       <action context="Renderers" dev="JM" type="update">
         When a JPEG image is embedded, an optionally embedded color profile is filtered out
         as it's already embedded separately in the PDF file.



---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org