aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org
diff options
context:
space:
mode:
authorAdrian Cumiskey <acumiskey@apache.org>2008-04-03 09:40:10 +0000
committerAdrian Cumiskey <acumiskey@apache.org>2008-04-03 09:40:10 +0000
commit918928b5b464c3ce55af20b608f78a5a70da1b95 (patch)
tree69507ffadb30383fd6502292174d9df15d855750 /src/java/org
parentcfa5ebf3a6e05964b07c7adc06f68d80c2c911bc (diff)
downloadxmlgraphics-fop-918928b5b464c3ce55af20b608f78a5a70da1b95.tar.gz
xmlgraphics-fop-918928b5b464c3ce55af20b608f78a5a70da1b95.zip
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. ........ git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AFPGOCAResources@644243 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org')
-rw-r--r--src/java/org/apache/fop/fonts/CachedFontInfo.java120
-rw-r--r--src/java/org/apache/fop/fonts/EmbedFontInfo.java41
-rw-r--r--src/java/org/apache/fop/fonts/FontCache.java174
-rw-r--r--src/java/org/apache/fop/fonts/FontLoader.java17
-rw-r--r--src/java/org/apache/fop/fonts/LazyFont.java4
-rw-r--r--src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java7
-rw-r--r--src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java124
-rw-r--r--src/java/org/apache/fop/fonts/truetype/FontFileReader.java22
-rw-r--r--src/java/org/apache/fop/fonts/truetype/TTFFile.java69
-rw-r--r--src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java38
-rw-r--r--src/java/org/apache/fop/render/PrintRendererConfigurator.java31
-rw-r--r--src/java/org/apache/fop/render/java2d/FontSetup.java2
12 files changed, 439 insertions, 210 deletions
diff --git a/src/java/org/apache/fop/fonts/CachedFontInfo.java b/src/java/org/apache/fop/fonts/CachedFontInfo.java
deleted file mode 100644
index 3de3cfd4e..000000000
--- a/src/java/org/apache/fop/fonts/CachedFontInfo.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.fonts;
-
-import java.io.File;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.List;
-
-import org.apache.commons.io.FileUtils;
-
-/**
- * Font info stored in the cache
- */
-public class CachedFontInfo extends EmbedFontInfo {
-
- /** Serialization Version UID */
- private static final long serialVersionUID = 240028291961081894L;
-
- /** file modify date (if available) */
- private long lastModified = -1;
-
- /**
- * Returns a file given a list of urls
- * @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;
- }
-
- /**
- * Default constructor
- * @param metricsFile metrics file
- * @param kerning kerning
- * @param fontTriplets font triplets
- * @param embedFile embed file
- * @param lastModified timestamp that this font was last modified
- */
- public CachedFontInfo(String metricsFile, boolean kerning, List fontTriplets,
- String embedFile, long lastModified) {
- super(metricsFile, kerning, fontTriplets, embedFile);
- this.lastModified = lastModified;
- }
-
- /**
- * Constructor
- * @param fontInfo an existing embed font info
- */
- public CachedFontInfo(EmbedFontInfo fontInfo) {
- super(fontInfo.metricsFile, fontInfo.kerning, fontInfo.fontTriplets, fontInfo.embedFile);
- // try and determine modified date
- File fontFile = getFileFromUrls(new String[] {embedFile, metricsFile});
- if (fontFile != null ) {
- this.lastModified = fontFile.lastModified();
- }
- }
-
- /**
- * 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;
- }
-}
diff --git a/src/java/org/apache/fop/fonts/EmbedFontInfo.java b/src/java/org/apache/fop/fonts/EmbedFontInfo.java
index 58dcbf142..8bda40532 100644
--- a/src/java/org/apache/fop/fonts/EmbedFontInfo.java
+++ b/src/java/org/apache/fop/fonts/EmbedFontInfo.java
@@ -28,7 +28,7 @@ import java.util.List;
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 @@ public class EmbedFontInfo implements Serializable {
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 @@ public class EmbedFontInfo implements Serializable {
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() : "");
}
}
diff --git a/src/java/org/apache/fop/fonts/FontCache.java b/src/java/org/apache/fop/fonts/FontCache.java
index 13afa5a65..fcf26dafb 100644
--- a/src/java/org/apache/fop/fonts/FontCache.java
+++ b/src/java/org/apache/fop/fonts/FontCache.java
@@ -26,8 +26,12 @@ import java.io.ObjectInputStream;
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 @@ public final class FontCache implements Serializable {
/** 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 final class FontCache implements Serializable {
*/
public boolean containsFont(String embedUrl) {
if (embedUrl != null) {
- return fontMap.containsKey(embedUrl);
+ return fontfileMap.containsKey(embedUrl);
}
return false;
}
@@ -228,45 +233,100 @@ public final class FontCache implements Serializable {
*/
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 @@ public final class FontCache implements Serializable {
if (log.isTraceEnabled()) {
log.trace("Font removed from cache: " + embedUrl);
}
- fontMap.remove(embedUrl);
+ fontfileMap.remove(embedUrl);
changed = true;
}
}
@@ -326,9 +386,87 @@ public final class FontCache implements Serializable {
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;
+ }
+
+ }
}
diff --git a/src/java/org/apache/fop/fonts/FontLoader.java b/src/java/org/apache/fop/fonts/FontLoader.java
index 1fa328a0a..69c55ceae 100644
--- a/src/java/org/apache/fop/fonts/FontLoader.java
+++ b/src/java/org/apache/fop/fonts/FontLoader.java
@@ -71,36 +71,39 @@ public abstract class FontLoader {
/**
* 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 @@ public abstract class FontLoader {
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 @@ public abstract class FontLoader {
* @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) {
diff --git a/src/java/org/apache/fop/fonts/LazyFont.java b/src/java/org/apache/fop/fonts/LazyFont.java
index 8997069d4..07b5be305 100644
--- a/src/java/org/apache/fop/fonts/LazyFont.java
+++ b/src/java/org/apache/fop/fonts/LazyFont.java
@@ -44,6 +44,7 @@ public class LazyFont extends Typeface implements FontDescriptor {
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 @@ public class LazyFont extends Typeface implements FontDescriptor {
this.metricsFileName = fontInfo.getMetricsFile();
this.fontEmbedPath = fontInfo.getEmbedFile();
this.useKerning = fontInfo.getKerning();
+ this.subFontName = fontInfo.getSubFontName();
this.resolver = resolver;
}
@@ -123,7 +125,7 @@ public class LazyFont extends Typeface implements FontDescriptor {
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;
diff --git a/src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java b/src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java
index c35faf65d..d0f7b4f14 100644
--- a/src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java
+++ b/src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java
@@ -72,14 +72,15 @@ public class FontFileFinder extends DirectoryWalker implements FontFinder {
}
/**
- * 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)
);
}
diff --git a/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java b/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java
index 5fc0525c3..8207eb140 100644
--- a/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java
+++ b/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java
@@ -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.io.IOUtils;
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.FontLoader;
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 @@ public class FontInfoFinder {
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 @@ public class FontInfoFinder {
* @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 @@ public class FontInfoFinder {
}
}
+
// 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);
+
+
}
+
}
diff --git a/src/java/org/apache/fop/fonts/truetype/FontFileReader.java b/src/java/org/apache/fop/fonts/truetype/FontFileReader.java
index 18ac7ad0f..0d1af4785 100644
--- a/src/java/org/apache/fop/fonts/truetype/FontFileReader.java
+++ b/src/java/org/apache/fop/fonts/truetype/FontFileReader.java
@@ -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;
@@ -314,6 +314,26 @@ public class FontFileReader {
}
/**
+ * 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);
+ }
+
+ /**
* Return a copy of the internal array
*
* @param offset The absolute offset to start reading from
diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFile.java b/src/java/org/apache/fop/fonts/truetype/TTFFile.java
index e60722331..8c5211e67 100644
--- a/src/java/org/apache/fop/fonts/truetype/TTFFile.java
+++ b/src/java/org/apache/fop/fonts/truetype/TTFFile.java
@@ -988,7 +988,10 @@ public class TTFFile {
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 @@ public class TTFFile {
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 @@ public class TTFFile {
}
break;
case 4:
- if (fullName.length() == 0) {
+ if (fullName.length() == 0 || (platformID == 3 && languageID == 1033)) {
fullName = txt;
}
break;
@@ -1474,6 +1482,59 @@ public class TTFFile {
}
}
+ /**
+ * 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 @@ public class TTFFile {
* @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);
diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
index 60a6948fc..9cd59b5b3 100644
--- a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
+++ b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
@@ -34,11 +34,12 @@ import org.apache.fop.fonts.FontResolver;
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 @@ public class TTFFontLoader extends FontLoader {
* @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 @@ public class TTFFontLoader extends FontLoader {
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 @@ public class TTFFontLoader extends FontLoader {
returnFont.setItalicAngle(Integer.parseInt(ttf.getItalicAngle()));
returnFont.setMissingWidth(0);
returnFont.setWeight(ttf.getWeightClass());
-
+
multiFont.setCIDType(CIDFontType.CIDTYPE2);
int[] wx = ttf.getWidths();
multiFont.setWidthArray(wx);
diff --git a/src/java/org/apache/fop/render/PrintRendererConfigurator.java b/src/java/org/apache/fop/render/PrintRendererConfigurator.java
index 0f0acd60d..ccff3baa1 100644
--- a/src/java/org/apache/fop/render/PrintRendererConfigurator.java
+++ b/src/java/org/apache/fop/render/PrintRendererConfigurator.java
@@ -36,10 +36,11 @@ import org.apache.commons.io.IOUtils;
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.FontUtil;
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 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator
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 class PrintRendererConfigurator extends AbstractRendererConfigurator
*/
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 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator
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 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator
}
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 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator
}
}
- fontInfo = new EmbedFontInfo(metricsUrl, useKerning, tripleList, embedUrl);
+ fontInfo = new EmbedFontInfo(metricsUrl, useKerning, tripleList, embedUrl, subFont);
if (fontCache != null) {
if (!fontCache.containsFont(fontInfo)) {
diff --git a/src/java/org/apache/fop/render/java2d/FontSetup.java b/src/java/org/apache/fop/render/java2d/FontSetup.java
index 752335521..ade457d95 100644
--- a/src/java/org/apache/fop/render/java2d/FontSetup.java
+++ b/src/java/org/apache/fop/render/java2d/FontSetup.java
@@ -304,7 +304,7 @@ public class FontSetup {
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);
}