Browse Source

Merged revisions 642144-647679 via svnmerge from

https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk

........
  r642923 | jeremias | 2008-03-31 10:39:49 +0200 (Mo, 31 Mrz 2008) | 1 line
  
  Fixed possible NullPointerException in AFM kerning table build code.
........
  r642924 | jeremias | 2008-03-31 10:40:48 +0200 (Mo, 31 Mrz 2008) | 1 line
  
  Added missing code for determining the PDF Flags. The removes the need to have a PFM if you have an AFM file for a Type 1 font.
........
  r642927 | jeremias | 2008-03-31 10:48:34 +0200 (Mo, 31 Mrz 2008) | 1 line
  
  Updated XG Commons for revision: http://svn.apache.org/viewvc?rev=642925&view=rev
........
  r644208 | jeremias | 2008-04-03 10:05:14 +0200 (Do, 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 10:13:50 +0200 (Do, 03 Apr 2008) | 1 line
  
  Oops. Fixed a last-minute change that broke the build.
........
  r644691 | jeremias | 2008-04-04 14:19:50 +0200 (Fr, 04 Apr 2008) | 3 lines
  
  Bugzilla #44743:
  Added a public accessor for reference to the current page to PDFGraphics2D.
  Submitted by: Yegor Kozlov <yegor.at.dinom.ru>
........
  r644697 | jeremias | 2008-04-04 14:40:22 +0200 (Fr, 04 Apr 2008) | 2 lines
  
  Bugzilla #44744:
  Disable drawString(AttributedCharacterIterator, float, float) as it contains bugs and rely on the fallback implementation from AbstractGraphics2D.
........
  r645104 | jeremias | 2008-04-05 16:11:50 +0200 (Sa, 05 Apr 2008) | 1 line
  
  Fixed broken links.
........


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_ProcessingFeedback@647685 13f79535-47bb-0310-9956-ffa450edef68
Temp_ProcessingFeedback
Jeremias Maerki 16 years ago
parent
commit
56d3fbd9f7

BIN
lib/xmlgraphics-commons-1.4svn.jar View File


+ 1
- 1
src/documentation/content/xdocs/0.94/upgrading.xml View File

@@ -77,7 +77,7 @@
</li>
<li>
Extensions and Renderers written for version 0.20.5 will not work with the new code! The new FOP
extension for <a href="http://barcode4j.krysalis.org">Barcode4J</a> is available since
extension for <a href="http://barcode4j.sourceforge.net">Barcode4J</a> is available since
January 2007.
</li>
<li>

+ 1
- 1
src/documentation/content/xdocs/0.95/upgrading.xml View File

@@ -78,7 +78,7 @@
</li>
<li>
Extensions and Renderers written for version 0.20.5 will not work with the new code! The new FOP
extension for <a href="http://barcode4j.krysalis.org">Barcode4J</a> is available since
extension for <a href="http://barcode4j.sourceforge.net">Barcode4J</a> is available since
January 2007.
</li>
<li>

+ 5
- 0
src/documentation/content/xdocs/trunk/fonts.xml View File

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

+ 1
- 1
src/documentation/content/xdocs/trunk/upgrading.xml View File

@@ -79,7 +79,7 @@
</li>
<li>
Extensions and Renderers written for version 0.20.5 will not work with the new code! The new FOP
extension for <a href="http://barcode4j.krysalis.org">Barcode4J</a> is available since
extension for <a href="http://barcode4j.sourceforge.net">Barcode4J</a> is available since
January 2007.
</li>
<li>

+ 1
- 0
src/foschema/fop-configuration.xsd View File

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

+ 0
- 120
src/java/org/apache/fop/fonts/CachedFontInfo.java View File

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

+ 37
- 4
src/java/org/apache/fop/fonts/EmbedFontInfo.java View File

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

+ 156
- 18
src/java/org/apache/fop/fonts/FontCache.java View File

@@ -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,44 +233,99 @@ 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;
}

}
}

+ 10
- 7
src/java/org/apache/fop/fonts/FontLoader.java View File

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

+ 3
- 1
src/java/org/apache/fop/fonts/LazyFont.java View File

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

+ 4
- 3
src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java View File

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

+ 93
- 37
src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java View File

@@ -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;
@@ -42,6 +40,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
@@ -143,8 +145,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);
}
@@ -157,35 +164,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)) {
@@ -196,22 +189,85 @@ public class FontInfoFinder {
}
}
// try to determine triplet information from font file
CustomFont customFont = null;
try {
customFont = FontLoader.loadFont(fontUrl, resolver);
} catch (Exception e) {
if (this.eventListener != null) {
this.eventListener.fontLoadingErrorAtAutoDetection(this, embedUrl, e);
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) {
if (this.eventListener != null) {
this.eventListener.fontLoadingErrorAtAutoDetection(this, fontFileURI, 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();
if (this.eventListener != null) {
customFont.setEventListener(this.eventListener);
}
} catch (Exception e) {
if (fontCache != null) {
fontCache.registerFailedFont(embedUrl, fileLastModified);
}
if (this.eventListener != null) {
this.eventListener.fontLoadingErrorAtAutoDetection(this, embedUrl, e);
}
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);
if (this.eventListener != null) {
customFont.setEventListener(this.eventListener);
}
} catch (Exception e) {
if (fontCache != null) {
fontCache.registerFailedFont(embedUrl, fileLastModified);
}
if (this.eventListener != null) {
this.eventListener.fontLoadingErrorAtAutoDetection(this, embedUrl, e);
}
return null;
}
EmbedFontInfo fi = fontInfoFromCustomFont(fontUrl, customFont, fontCache);
if (fi != null) {
return new EmbedFontInfo[] {fi};
} else {
return null;
}
return null;
}
if (this.eventListener != null) {
customFont.setEventListener(this.eventListener);
}
return fontInfoFromCustomFont(fontUrl, customFont, fontCache);

}

}

+ 21
- 1
src/java/org/apache/fop/fonts/truetype/FontFileReader.java View File

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

@@ -313,6 +313,26 @@ public class FontFileReader {
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);
}

/**
* Return a copy of the internal array
*

+ 65
- 4
src/java/org/apache/fop/fonts/truetype/TTFFile.java View File

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

+ 31
- 7
src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java View File

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

+ 2
- 2
src/java/org/apache/fop/fonts/type1/AFMFile.java View File

@@ -413,7 +413,7 @@ public class AFMFile {
Map.Entry entryFrom = (Map.Entry)iterFrom.next();
String name1 = (String)entryFrom.getKey();
AFMCharMetrics chm1 = getChar(name1);
if (!chm1.hasCharCode()) {
if (chm1 == null || !chm1.hasCharCode()) {
continue;
}
Map container = null;
@@ -423,7 +423,7 @@ public class AFMFile {
Map.Entry entryTo = (Map.Entry)iterTo.next();
String name2 = (String)entryTo.getKey();
AFMCharMetrics chm2 = getChar(name2);
if (!chm2.hasCharCode()) {
if (chm2 == null || !chm2.hasCharCode()) {
continue;
}
if (container == null) {

+ 20
- 7
src/java/org/apache/fop/fonts/type1/Type1FontLoader.java View File

@@ -108,11 +108,6 @@ public class Type1FontLoader extends FontLoader {
throw new java.io.FileNotFoundException(
"Neither an AFM nor a PFM file was found for " + this.fontFileURI);
}
if (pfm == null) {
//Cannot do without the PFM for now
throw new java.io.FileNotFoundException(
"No PFM file was found for " + this.fontFileURI);
}
buildFont(afm, pfm);
this.loaded = true;
}
@@ -289,7 +284,25 @@ public class Type1FontLoader extends FontLoader {
}
if (afm != null) {
//TODO returnFont.setFlags(flags);
String charSet = afm.getCharacterSet();
int flags = 0;
if ("Special".equals(charSet)) {
flags |= 4; //bit 3: Symbolic
} else {
if (singleFont.getEncoding().mapChar('A') == 'A') {
//High likelyhood that the font is non-symbolic
flags |= 32; //bit 6: Nonsymbolic
} else {
flags |= 4; //bit 3: Symbolic
}
}
if (afm.getWritingDirectionMetrics(0).isFixedPitch()) {
flags |= 1; //bit 1: FixedPitch
}
if (afm.getWritingDirectionMetrics(0).getItalicAngle() != 0.0) {
flags |= 64; //bit 7: Italic
}
returnFont.setFlags(flags);
returnFont.setFirstChar(afm.getFirstChar());
returnFont.setLastChar(afm.getLastChar());
@@ -302,6 +315,7 @@ public class Type1FontLoader extends FontLoader {
}
returnFont.replaceKerningMap(afm.createXKerningMapEncoded());
} else {
returnFont.setFlags(pfm.getFlags());
returnFont.setFirstChar(pfm.getFirstChar());
returnFont.setLastChar(pfm.getLastChar());
for (short i = pfm.getFirstChar(); i <= pfm.getLastChar(); i++) {
@@ -309,7 +323,6 @@ public class Type1FontLoader extends FontLoader {
}
returnFont.replaceKerningMap(pfm.getKerning());
}
returnFont.setFlags(pfm.getFlags());
}

private CodePointMapping buildCustomEncoding(String encodingName, AFMFile afm) {

+ 22
- 9
src/java/org/apache/fop/render/PrintRendererConfigurator.java View File

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

+ 1
- 1
src/java/org/apache/fop/render/java2d/FontSetup.java View File

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


+ 13
- 7
src/java/org/apache/fop/svg/PDFGraphics2D.java View File

@@ -50,8 +50,6 @@ import java.awt.image.renderable.RenderableImage;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.text.AttributedCharacterIterator;
import java.text.CharacterIterator;
import java.util.List;
import java.util.Map;

@@ -304,7 +302,15 @@ public class PDFGraphics2D extends AbstractGraphics2D {
}

/**
* Set the Grpahics context.
* Gets the PDF reference of the current page.
* @return the PDF reference of the current page
*/
public String getPageReference() {
return this.pageRef;
}
/**
* Set the Graphics context.
* @param c the graphics context to use
*/
public void setGraphicContext(GraphicContext c) {
@@ -390,7 +396,7 @@ public class PDFGraphics2D extends AbstractGraphics2D {
if (linkType != PDFLink.EXTERNAL) {
String pdfdest = "/FitR " + dest;
resourceContext.addAnnotation(
pdfDoc.getFactory().makeLink(rect, pageRef, pdfdest));
pdfDoc.getFactory().makeLink(rect, getPageReference(), pdfdest));
} else {
resourceContext.addAnnotation(
pdfDoc.getFactory().makeLink(rect, dest, linkType, 0));
@@ -958,7 +964,7 @@ public class PDFGraphics2D extends AbstractGraphics2D {
PDFResources res = pdfDoc.getFactory().makeResources();
PDFResourceContext context = new PDFResourceContext(res);
PDFGraphics2D pattGraphic = new PDFGraphics2D(textAsShapes, specialFontInfo,
pdfDoc, context, pageRef,
pdfDoc, context, getPageReference(),
"", 0);
pattGraphic.setGraphicContext(new GraphicContext());
pattGraphic.gc.validateTransformStack();
@@ -1512,7 +1518,7 @@ public class PDFGraphics2D extends AbstractGraphics2D {
* @see #setTransform
* @see #setComposite
* @see #setClip
*/
*//* TODO Reimplement for higher efficiency similar to the way it was done in PDFTextPainter
public void drawString(AttributedCharacterIterator iterator, float x,
float y) {
preparePainting();
@@ -1577,7 +1583,7 @@ public class PDFGraphics2D extends AbstractGraphics2D {
}

currentStream.write("ET\n");
}
}*/

/**
* Fills the interior of a <code>Shape</code> using the settings of the

+ 7
- 0
status.xml View File

@@ -58,6 +58,13 @@
Added SVG support for AFP (GOCA).
</action>
-->
<action context="Renderers" dev="JM" type="add" fixes-bug="44743" due-to="Yegor Kozlov">
Added a public accessor for reference to the current page to PDFGraphics2D.
</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.

Loading…
Cancel
Save