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-ffa450edef68Temp_ProcessingFeedback
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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"> |
@@ -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; | |||
} | |||
} |
@@ -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() : ""); | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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) { |
@@ -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; |
@@ -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) | |||
); | |||
} | |||
@@ -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); | |||
} | |||
} |
@@ -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 | |||
* |
@@ -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); |
@@ -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); |
@@ -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) { |
@@ -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) { |
@@ -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)) { |
@@ -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); | |||
} | |||
@@ -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 |
@@ -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. |