import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
+import org.apache.fop.fonts.FontManager;
import org.apache.fop.pdf.PDFAMode;
import org.apache.fop.pdf.PDFEncryptionManager;
import org.apache.fop.pdf.PDFEncryptionParams;
factory.setStrictValidation(false);
} else if (args[i].equals("-conserve")) {
conserveMemoryPolicy = true;
+ } else if (args[i].equals("-delete-cache")) {
+ parseDeleteCacheOption(args, i);
+ } else if (args[i].equals("-cache")) {
+ parseCacheOption(args, i);
} else if (args[i].equals("-dpi")) {
i = i + parseResolution(args, i);
} else if (args[i].equals("-q") || args[i].equals("--quiet")) {
return true;
} // end parseOptions
+ private int parseCacheOption(String[] args, int i) throws FOPException {
+ if ((i + 1 == args.length)
+ || (isOption(args[i + 1]))) {
+ throw new FOPException("if you use '-cache', you must specify "
+ + "the name of the font cache file");
+ } else {
+ factory.getFontManager().setCacheFile(new File(args[i + 1]));
+ return 1;
+ }
+ }
+
+ private void parseDeleteCacheOption(String[] args, int i) throws FOPException {
+ FontManager fontManager = factory.getFontManager();
+ try {
+ setUserConfig();
+ File cacheFile = fontManager.getCacheFile();
+ if (fontManager.deleteCache()) {
+ System.out.println("Successfully deleted the font cache file '"
+ + cacheFile + "'.");
+ System.exit(0);
+ } else {
+ System.err.println("Failed to delete the font cache file '"
+ + cacheFile + "'.");
+ System.exit(1);
+ }
+ } catch (IOException e) {
+ System.err.println("Failed to delete the font cache file");
+ System.exit(1);
+ }
+ }
+
private int parseConfigurationOption(String[] args, int i) throws FOPException {
if ((i + 1 == args.length)
|| (isOption(args[i + 1]))) {
+ " -a enables accessibility features (Tagged PDF etc., default off)\n"
+ " -pdfprofile prof PDF file will be generated with the specified profile\n"
+ " (Examples for prof: PDF/A-1b or PDF/X-3:2003)\n\n"
- + " -conserve Enable memory-conservation policy (trades memory-consumption"
+ + " -conserve enable memory-conservation policy (trades memory-consumption"
+ " for disk I/O)\n"
+ " (Note: currently only influences whether the area tree is"
+ " serialized.)\n\n"
+
+ + " -delete-cache deletes the current font cache file\n"
+ + " -cache specifies a file/directory path location"
+ + " for the font cache file\n\n"
+
+ " [INPUT] \n"
+ " infile xsl:fo input file (the same as the next) \n"
+ " (use '-' for infile to pipe input from stdin)\n"
package org.apache.fop.fonts;
+import java.io.BufferedInputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
public final class FontCache implements Serializable {
/**
- * Serialization Version UID. Change this value if you want to make sure the user's cache
- * file is purged after an update.
+ * Serialization Version UID. Change this value if you want to make sure the
+ * user's cache file is purged after an update.
*/
private static final long serialVersionUID = 605232520271754719L;
/** font cache file path */
private static final String DEFAULT_CACHE_FILENAME = "fop-fonts.cache";
-
/** has this cache been changed since it was last read? */
private transient boolean changed = false;
/** change lock */
private final boolean[] changeLock = new boolean[1];
- /** 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/*<String, CachedFontFile>*/ fontfileMap = null;
+ /**
+ * 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/* <String, CachedFontFile> */fontfileMap = null;
- /** mapping of font url -> file modified date (for all fonts that have failed to load) */
- private Map failedFontMap/*<String, Long>*/ = null;
+ /**
+ * mapping of font url -> file modified date (for all fonts that have failed
+ * to load)
+ */
+ private Map failedFontMap/* <String, Long> */= null;
/**
* Default constructor
/**
* Returns the default font cache file.
- * @param forWriting true if the user directory should be created
+ *
+ * @param forWriting
+ * true if the user directory should be created
* @return the default font cache file
*/
public static File getDefaultCacheFile(boolean forWriting) {
/**
* Reads the default font cache file and returns its contents.
- * @return the font cache deserialized from the file (or null if no cache file exists or if
- * it could not be read)
+ *
+ * @return the font cache deserialized from the file (or null if no cache
+ * file exists or if it could not be read)
*/
public static FontCache load() {
return loadFrom(getDefaultCacheFile(false));
/**
* Reads a font cache file and returns its contents.
- * @param cacheFile the cache file
- * @return the font cache deserialized from the file (or null if no cache file exists or if
- * it could not be read)
+ *
+ * @param cacheFile
+ * the cache file
+ * @return the font cache deserialized from the file (or null if no cache
+ * file exists or if it could not be read)
*/
public static FontCache loadFrom(File cacheFile) {
if (cacheFile.exists()) {
try {
if (log.isTraceEnabled()) {
- log.trace("Loading font cache from " + cacheFile.getCanonicalPath());
+ log.trace("Loading font cache from "
+ + cacheFile.getCanonicalPath());
}
- InputStream in = new java.io.FileInputStream(cacheFile);
- in = new java.io.BufferedInputStream(in);
+ InputStream in = new BufferedInputStream(new FileInputStream(cacheFile));
ObjectInputStream oin = new ObjectInputStream(in);
try {
- return (FontCache)oin.readObject();
+ return (FontCache) oin.readObject();
} finally {
IOUtils.closeQuietly(oin);
}
} catch (ClassNotFoundException e) {
- //We don't really care about the exception since it's just a cache file
+ // We don't really care about the exception since it's just a
+ // cache file
log.warn("Could not read font cache. Discarding font cache file. Reason: "
+ e.getMessage());
} catch (IOException ioe) {
- //We don't really care about the exception since it's just a cache file
- log.warn("I/O exception while reading font cache (" + ioe.getMessage()
- + "). Discarding font cache file.");
+ // We don't really care about the exception since it's just a
+ // cache file
+ log.warn("I/O exception while reading font cache ("
+ + ioe.getMessage() + "). Discarding font cache file.");
try {
cacheFile.delete();
} catch (SecurityException ex) {
- log.warn("Failed to delete font cache file: " + cacheFile.getAbsolutePath());
+ log.warn("Failed to delete font cache file: "
+ + cacheFile.getAbsolutePath());
}
}
}
/**
* Writes the font cache to disk.
- * @throws FOPException fop exception
+ *
+ * @throws FOPException
+ * fop exception
*/
public void save() throws FOPException {
saveTo(getDefaultCacheFile(true));
/**
* Writes the font cache to disk.
- * @param cacheFile the file to write to
- * @throws FOPException fop exception
+ *
+ * @param cacheFile
+ * the file to write to
+ * @throws FOPException
+ * fop exception
*/
public void saveTo(File cacheFile) throws FOPException {
synchronized (changeLock) {
if (changed) {
try {
- if (log.isTraceEnabled()) {
- log.trace("Writing font cache to " + cacheFile.getCanonicalPath());
- }
+ log.trace("Writing font cache to " + cacheFile.getCanonicalPath());
OutputStream out = new java.io.FileOutputStream(cacheFile);
out = new java.io.BufferedOutputStream(out);
ObjectOutputStream oout = new ObjectOutputStream(out);
/**
* creates a key given a font info for the font mapping
- * @param fontInfo font info
+ *
+ * @param fontInfo
+ * font info
* @return font cache key
*/
protected static String getCacheKey(EmbedFontInfo fontInfo) {
/**
* cache has been updated since it was read
+ *
* @return if this cache has changed
*/
public boolean hasChanged() {
/**
* is this font in the cache?
- * @param embedUrl font info
+ *
+ * @param embedUrl
+ * font info
* @return boolean
*/
public boolean containsFont(String embedUrl) {
- return (embedUrl != null
- && getFontFileMap().containsKey(embedUrl));
+ return (embedUrl != null && getFontFileMap().containsKey(embedUrl));
}
/**
* is this font info in the cache?
- * @param fontInfo font info
+ *
+ * @param fontInfo
+ * font info
* @return font
*/
public boolean containsFont(EmbedFontInfo fontInfo) {
- return (fontInfo != null
- && getFontFileMap().containsKey(getCacheKey(fontInfo)));
+ return (fontInfo != null && getFontFileMap().containsKey(
+ getCacheKey(fontInfo)));
}
/**
- * 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
+ * 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) {
return null;
}
- private Map/*<String, CachedFontFile>*/ getFontFileMap() {
+ private Map/* <String, CachedFontFile> */getFontFileMap() {
if (fontfileMap == null) {
- fontfileMap = new java.util.HashMap/*<String, CachedFontFile>*/();
+ fontfileMap = new java.util.HashMap/* <String, CachedFontFile> */();
}
return fontfileMap;
}
/**
* Adds a font info to cache
- * @param fontInfo font info
+ *
+ * @param fontInfo
+ * font info
*/
public void addFont(EmbedFontInfo fontInfo) {
String cacheKey = getCacheKey(fontInfo);
synchronized (changeLock) {
CachedFontFile cachedFontFile;
if (containsFont(cacheKey)) {
- cachedFontFile = (CachedFontFile)getFontFileMap().get(cacheKey);
+ cachedFontFile = (CachedFontFile) getFontFileMap()
+ .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);
+ 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);
/**
* Returns a font from the cache.
- * @param embedUrl font info
+ *
+ * @param embedUrl
+ * font info
* @return CachedFontFile object
*/
public CachedFontFile getFontFile(String embedUrl) {
- return containsFont(embedUrl) ? (CachedFontFile) getFontFileMap().get(embedUrl) : null;
+ return containsFont(embedUrl) ? (CachedFontFile) getFontFileMap().get(
+ embedUrl) : 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
+ * 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);
/**
* removes font from cache
- * @param embedUrl embed url
+ *
+ * @param embedUrl
+ * embed url
*/
public void removeFont(String embedUrl) {
synchronized (changeLock) {
/**
* has this font previously failed to load?
- * @param embedUrl embed url
- * @param lastModified last modified
+ *
+ * @param embedUrl
+ * embed url
+ * @param lastModified
+ * last modified
* @return whether this is a failed font
*/
public boolean isFailedFont(String embedUrl, long lastModified) {
synchronized (changeLock) {
if (getFailedFontMap().containsKey(embedUrl)) {
- long failedLastModified = ((Long)getFailedFontMap().get(embedUrl)).longValue();
+ long failedLastModified = ((Long) getFailedFontMap().get(
+ embedUrl)).longValue();
if (lastModified != failedLastModified) {
// this font has been changed so lets remove it
// from failed font map for now
/**
* Registers a failed font with the cache
- * @param embedUrl embed url
- * @param lastModified time last modified
+ *
+ * @param embedUrl
+ * embed url
+ * @param lastModified
+ * time last modified
*/
public void registerFailedFont(String embedUrl, long lastModified) {
synchronized (changeLock) {
}
}
- private Map/*<String, Long>*/ getFailedFontMap() {
+ private Map/* <String, Long> */getFailedFontMap() {
if (failedFontMap == null) {
- failedFontMap = new java.util.HashMap/*<String, Long>*/();
+ failedFontMap = new java.util.HashMap/* <String, Long> */();
}
return failedFontMap;
}
/**
* Retrieve the last modified date/time of a URL.
- * @param url the URL
+ *
+ * @param url
+ * the URL
* @return the last modified date/time
*/
public static long getLastModified(URL url) {
try {
return conn.getLastModified();
} finally {
- //An InputStream is created even if it's not accessed, but we need to close it.
+ // An InputStream is created even if it's not accessed, but we
+ // need to close it.
IOUtils.closeQuietly(conn.getInputStream());
}
} catch (IOException e) {
/** file modify date (if available) */
private long lastModified = -1;
- private Map/*<String, EmbedFontInfo>*/ filefontsMap = null;
+ private Map/* <String, EmbedFontInfo> */filefontsMap = null;
public CachedFontFile(long lastModified) {
setLastModified(lastModified);
}
- private Map/*<String, EmbedFontInfo>*/ getFileFontsMap() {
+ private Map/* <String, EmbedFontInfo> */getFileFontsMap() {
if (filefontsMap == null) {
- filefontsMap = new java.util.HashMap/*<String, EmbedFontInfo>*/();
+ filefontsMap = new java.util.HashMap/* <String, EmbedFontInfo> */();
}
return filefontsMap;
}
}
public EmbedFontInfo[] getEmbedFontInfos() {
- return (EmbedFontInfo[])getFileFontsMap().values().toArray(
+ return (EmbedFontInfo[]) getFileFontsMap().values().toArray(
new EmbedFontInfo[getFileFontsMap().size()]);
}
/**
* Gets the modified timestamp for font file (not always available)
+ *
* @return modified timestamp
*/
public long lastModified() {
}
/**
- * Gets the modified timestamp for font file
- * (used for the purposes of font info caching)
- * @param lastModified modified font file timestamp
+ * 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}
+ * @return string representation of this object {@inheritDoc}
*/
public String toString() {
return super.toString() + ", lastModified=" + lastModified;
package org.apache.fop.fonts;
+import java.io.File;
import java.net.MalformedURLException;
import java.util.Iterator;
import java.util.List;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
+import org.apache.fop.apps.FOPException;
import org.apache.fop.fonts.FontTriplet.Matcher;
import org.apache.fop.fonts.substitute.FontSubstitutions;
// TODO: Refactor fonts package so major font activities (autodetection etc)
-// are all centrally managed and delegated from this class, also remove dependency on FopFactory
-// and start using POJO config/properties type classes
+// are all centrally managed and delegated from this class
/**
* The manager of fonts. The class holds a reference to the font cache and information about
/** FontTriplet matcher for fonts that shall be referenced rather than embedded. */
private FontTriplet.Matcher referencedFontsMatcher;
+ /** Enables/disables the use of font caching */
+ private boolean useCache = DEFAULT_USE_CACHE;
+
+ /** Provides a font cache file path **/
+ private File cacheFile;
+
/**
* Main constructor
*/
public FontManager() {
- setUseCache(DEFAULT_USE_CACHE);
}
/**
return fontSubstitutions;
}
+ /**
+ * Sets the font cache file
+ * @param cacheFile the font cache file
+ */
+ public void setCacheFile(File cacheFile) {
+ this.cacheFile = cacheFile;
+ }
+
+ /**
+ * Returns the font cache file
+ * @return the font cache file
+ */
+ public File getCacheFile() {
+ if (cacheFile != null) {
+ return this.cacheFile;
+ }
+ return FontCache.getDefaultCacheFile(false);
+ }
+
/**
* Whether or not to cache results of font triplet detection/auto-config
* @param useCache use cache or not
*/
public void setUseCache(boolean useCache) {
- if (useCache) {
- this.fontCache = FontCache.load();
- if (this.fontCache == null) {
- this.fontCache = new FontCache();
- }
- } else {
+ this.useCache = useCache;
+ if (!useCache) {
this.fontCache = null;
}
}
* @return true if this font manager uses the cache
*/
public boolean useCache() {
- return (this.fontCache != null);
+ return useCache;
}
/**
* @return the font cache
*/
public FontCache getFontCache() {
- return this.fontCache;
+ if (fontCache == null) {
+ if (useCache) {
+ if (cacheFile != null) {
+ fontCache = FontCache.loadFrom(cacheFile);
+ } else {
+ fontCache = FontCache.load();
+ }
+ if (fontCache == null) {
+ fontCache = new FontCache();
+ }
+ }
+ }
+ return fontCache;
+ }
+
+ /**
+ * Saves the FontCache as necessary
+ *
+ * @throws FOPException fop exception
+ */
+ public void saveCache() throws FOPException {
+ if (useCache) {
+ if (fontCache != null && fontCache.hasChanged()) {
+ if (cacheFile != null) {
+ fontCache.saveTo(cacheFile);
+ } else {
+ fontCache.save();
+ }
+ }
+ }
+ }
+
+ /**
+ * Deletes the current FontCache file
+ * @return Returns true if the font cache file was successfully deleted.
+ */
+ public boolean deleteCache() {
+ boolean deleted = false;
+ if (useCache) {
+ if (cacheFile != null) {
+ deleted = cacheFile.delete();
+ cacheFile = null;
+ } else {
+ deleted = FontCache.getDefaultCacheFile(true).delete();
+ }
+ }
+ return deleted;
}
/**