aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop/apps
diff options
context:
space:
mode:
authorJeremias Maerki <jeremias@apache.org>2007-05-28 14:31:24 +0000
committerJeremias Maerki <jeremias@apache.org>2007-05-28 14:31:24 +0000
commit8c1aba3f976127d33ec50b67d760f56364c08487 (patch)
treeadfdca730f41c1b9029324bf53535aa25bf16d27 /src/java/org/apache/fop/apps
parent7ada0a06fe2b9ce0e1867d2c9c47f71ea47a43b2 (diff)
downloadxmlgraphics-fop-8c1aba3f976127d33ec50b67d760f56364c08487.tar.gz
xmlgraphics-fop-8c1aba3f976127d33ec50b67d760f56364c08487.zip
Bugzilla #41831:
- Add support font auto-detection (easier font configuration) including a font cache to speed up the auto-detection process. - Refactoring of the configuration code: All Avalon configuration stuff is extracted into separate "Configurator" classes. - Refactoring of the FOURIResolver. Submitted by: Adrian Cumiskey <fop-dev.at.cumiskey.com> Changes to the patch by jeremias during the review: - Font cache simplified (Java object serialization instead of XML), functionality fixed and moved to the fonts.package. - Relocated default cache file location to user directory. - Fixed the font configuration for PDFDocumentGraphics2D/PDFTranscoder that got lost with the patch. - Fixed a problem with having a non-file URL as font base URL. - Simplified RendererContextInfo stuff to make it easier to understand. - Fixed handling of Type 1 fonts in auto-detection. - Reduced verbosity of font-related log output. - Updated Jakarta Commons IO to version 1.3.1 (the patch depends on it) - Various javadocs improvements git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@542237 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop/apps')
-rw-r--r--src/java/org/apache/fop/apps/FOURIResolver.java189
-rw-r--r--src/java/org/apache/fop/apps/FOUserAgent.java43
-rw-r--r--src/java/org/apache/fop/apps/FopFactory.java364
-rw-r--r--src/java/org/apache/fop/apps/FopFactoryConfigurator.java241
4 files changed, 510 insertions, 327 deletions
diff --git a/src/java/org/apache/fop/apps/FOURIResolver.java b/src/java/org/apache/fop/apps/FOURIResolver.java
index e3ffd22cc..13baeaa56 100644
--- a/src/java/org/apache/fop/apps/FOURIResolver.java
+++ b/src/java/org/apache/fop/apps/FOURIResolver.java
@@ -29,6 +29,7 @@ import java.net.URL;
import java.net.URLConnection;
import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamSource;
// commons logging
@@ -47,9 +48,42 @@ import org.apache.xmlgraphics.util.io.Base64EncodeStream;
public class FOURIResolver
implements javax.xml.transform.URIResolver {
+ // log
private Log log = LogFactory.getLog("FOP");
+
+ // true if exceptions are to be thrown if the URIs cannot be resolved.
+ private boolean throwExceptions = false;
+
+ /**
+ * Default constructor
+ */
+ public FOURIResolver() {
+ this(false);
+ }
/**
+ * Additional constructor
+ * @param throwExceptions true if exceptions are to be thrown if the URIs cannot be
+ * resolved.
+ */
+ public FOURIResolver(boolean throwExceptions) {
+ this.throwExceptions = throwExceptions;
+ }
+
+ /**
+ * Handles resolve exceptions appropriately.
+ * @param errorStr error string
+ * @param strict strict user config
+ */
+ private void handleException(Exception e, String errorStr, boolean strict)
+ throws TransformerException {
+ if (strict) {
+ throw new TransformerException(errorStr, e);
+ }
+ log.error(e.getMessage());
+ }
+
+ /**
* Called by the processor through {@link FOUserAgent} when it encounters an
* uri in an external-graphic element.
* (see also {@link javax.xml.transform.URIResolver#resolve(String, String)}
@@ -70,31 +104,25 @@ public class FOURIResolver
* @throws javax.xml.transform.TransformerException Never thrown by this implementation.
* @see javax.xml.transform.URIResolver#resolve(String, String)
*/
- public Source resolve(String href, String base)
- throws javax.xml.transform.TransformerException {
-
- //data URLs can be quite long so don't try to build a File (can lead to problems)
+ public Source resolve(String href, String base) throws TransformerException {
+ // data URLs can be quite long so don't try to build a File (can lead to problems)
if (href.startsWith("data:")) {
return parseDataURI(href);
}
-
+
URL absoluteURL = null;
- File f = new File(href);
- if (f.exists()) {
+ File file = new File(href);
+ if (file.canRead() && file.isFile()) {
try {
- absoluteURL = f.toURL();
+ absoluteURL = file.toURL();
} catch (MalformedURLException mfue) {
- log.error("Could not convert filename to URL: " + mfue.getMessage());
+ handleException(mfue,
+ "Could not convert filename '" + href + "' to URL", throwExceptions);
}
} else {
- URL baseURL = null;
- try {
- baseURL = toBaseURL(base);
- } catch (MalformedURLException mfue) {
- log.error("Error with base URL \"" + base + "\"): " + mfue.getMessage());
- }
- if (baseURL == null) {
- // We don't have a valid baseURL just use the URL as given
+ // no base provided
+ if (base == null) {
+ // We don't have a valid file protocol based URL
try {
absoluteURL = new URL(href);
} catch (MalformedURLException mue) {
@@ -103,64 +131,78 @@ public class FOURIResolver
// the href contains only a path then file: is assumed
absoluteURL = new URL("file:" + href);
} catch (MalformedURLException mfue) {
- log.error("Error with URL '" + href + "': " + mue.getMessage());
- return null;
+ handleException(mfue,
+ "Error with URL '" + href + "'", throwExceptions);
}
}
+
+ // try and resolve from context of base
} else {
+ URL baseURL = null;
try {
- /*
- This piece of code is based on the following statement in
- RFC2396 section 5.2:
-
- 3) If the scheme component is defined, indicating that the reference
- starts with a scheme name, then the reference is interpreted as an
- absolute URI and we are done. Otherwise, the reference URI's
- scheme is inherited from the base URI's scheme component.
-
- Due to a loophole in prior specifications [RFC1630], some parsers
- allow the scheme name to be present in a relative URI if it is the
- same as the base URI scheme. Unfortunately, this can conflict
- with the correct parsing of non-hierarchical URI. For backwards
- compatibility, an implementation may work around such references
- by removing the scheme if it matches that of the base URI and the
- scheme is known to always use the <hier_part> syntax.
-
- The URL class does not implement this work around, so we do.
- */
+ baseURL = new URL(base);
+ } catch (MalformedURLException mfue) {
+ handleException(mfue, "Error with base URL '" + base + "'", throwExceptions);
+ }
- String scheme = baseURL.getProtocol() + ":";
- if (href.startsWith(scheme)) {
- href = href.substring(scheme.length());
- if ("file:".equals(scheme)) {
- int colonPos = href.indexOf(':');
- int slashPos = href.indexOf('/');
- if (slashPos >= 0 && colonPos >= 0 && colonPos < slashPos) {
- href = "/" + href; //Absolute file URL doesn't have a leading slash
- }
+ /*
+ * This piece of code is based on the following statement in
+ * RFC2396 section 5.2:
+ *
+ * 3) If the scheme component is defined, indicating that the
+ * reference starts with a scheme name, then the reference is
+ * interpreted as an absolute URI and we are done. Otherwise,
+ * the reference URI's scheme is inherited from the base URI's
+ * scheme component.
+ *
+ * Due to a loophole in prior specifications [RFC1630], some
+ * parsers allow the scheme name to be present in a relative URI
+ * if it is the same as the base URI scheme. Unfortunately, this
+ * can conflict with the correct parsing of non-hierarchical
+ * URI. For backwards compatibility, an implementation may work
+ * around such references by removing the scheme if it matches
+ * that of the base URI and the scheme is known to always use
+ * the <hier_part> syntax.
+ *
+ * The URL class does not implement this work around, so we do.
+ */
+ String scheme = baseURL.getProtocol() + ":";
+ if (href.startsWith(scheme)) {
+ href = href.substring(scheme.length());
+ if ("file:".equals(scheme)) {
+ int colonPos = href.indexOf(':');
+ int slashPos = href.indexOf('/');
+ if (slashPos >= 0 && colonPos >= 0 && colonPos < slashPos) {
+ href = "/" + href; // Absolute file URL doesn't
+ // have a leading slash
}
}
+ }
+ try {
absoluteURL = new URL(baseURL, href);
} catch (MalformedURLException mfue) {
- log.error("Error with URL '" + href + "': " + mfue.getMessage());
- return null;
+ handleException(mfue,
+ "Error with URL; base '" + base + "' " + "href '" + href + "'",
+ throwExceptions);
}
}
}
- String effURL = absoluteURL.toExternalForm();
- try {
- URLConnection connection = absoluteURL.openConnection();
- connection.setAllowUserInteraction(false);
- connection.setDoInput(true);
- updateURLConnection(connection, href);
- connection.connect();
- return new StreamSource(connection.getInputStream(), effURL);
- } catch (FileNotFoundException fnfe) {
- //Note: This is on "debug" level since the caller is supposed to handle this
- log.debug("File not found: " + effURL);
- } catch (java.io.IOException ioe) {
- log.error("Error with opening URL '" + effURL + "': " + ioe.getMessage());
+ if (absoluteURL != null) {
+ String effURL = absoluteURL.toExternalForm();
+ try {
+ URLConnection connection = absoluteURL.openConnection();
+ connection.setAllowUserInteraction(false);
+ connection.setDoInput(true);
+ updateURLConnection(connection, href);
+ connection.connect();
+ return new StreamSource(connection.getInputStream(), effURL);
+ } catch (FileNotFoundException fnfe) {
+ //Note: This is on "debug" level since the caller is supposed to handle this
+ log.debug("File not found: " + effURL);
+ } catch (java.io.IOException ioe) {
+ log.error("Error with opening URL '" + effURL + "': " + ioe.getMessage());
+ }
}
return null;
}
@@ -201,29 +243,6 @@ public class FOURIResolver
}
/**
- * Returns the base URL as a java.net.URL.
- * If the base URL is not set a default URL pointing to the
- * current directory is returned.
- * @param baseURL the base URL
- * @returns the base URL as java.net.URL
- */
- private URL toBaseURL(String base) throws MalformedURLException {
- if (base == null) {
- return new java.io.File("").toURL();
- }
- if (!base.endsWith("/")) {
- // The behavior described by RFC 3986 regarding resolution of relative
- // references may be misleading for normal users:
- // file://path/to/resources + myResource.res -> file://path/to/myResource.res
- // file://path/to/resources/ + myResource.res -> file://path/to/resources/myResource.res
- // We assume that even when the ending slash is missing, users have the second
- // example in mind
- base += "/";
- }
- return new URL(base);
- }
-
- /**
* Parses inline data URIs as generated by MS Word's XML export and FO stylesheet.
* @see <a href="http://www.ietf.org/rfc/rfc2397">RFC 2397</a>
*/
diff --git a/src/java/org/apache/fop/apps/FOUserAgent.java b/src/java/org/apache/fop/apps/FOUserAgent.java
index f15ddcc31..24df2f75b 100644
--- a/src/java/org/apache/fop/apps/FOUserAgent.java
+++ b/src/java/org/apache/fop/apps/FOUserAgent.java
@@ -63,19 +63,25 @@ import org.apache.fop.render.pdf.PDFRenderer;
public class FOUserAgent {
/** Defines the default target resolution (72dpi) for FOP */
- public static final float DEFAULT_TARGET_RESOLUTION = FopFactory.DEFAULT_TARGET_RESOLUTION;
+ public static final float DEFAULT_TARGET_RESOLUTION = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION;
private static Log log = LogFactory.getLog("FOP");
private FopFactory factory;
- /** The base URL for all URL resolutions, especially for external-graphics */
- private String baseURL;
-
+ /**
+ * The base URL for all URL resolutions, especially for
+ * external-graphics.
+ */
+ private String base = null;
+
+ /** The base URL for all font URL resolutions. */
+ private String fontBase = null;
+
/** A user settable URI Resolver */
private URIResolver uriResolver = null;
- private float targetResolution = DEFAULT_TARGET_RESOLUTION;
+ private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION;
private Map rendererOptions = new java.util.HashMap();
private File outputFile = null;
private Renderer rendererOverride = null;
@@ -105,7 +111,6 @@ public class FOUserAgent {
/**
* Default constructor
- * @throws FOPException
* @see org.apache.fop.apps.FopFactory
* @deprecated Provided for compatibility only. Please use the methods from
* FopFactory to construct FOUserAgent instances!
@@ -126,6 +131,7 @@ public class FOUserAgent {
}
this.factory = factory;
setBaseURL(factory.getBaseURL());
+ setFontBaseURL(factory.getFontBaseURL());
setTargetResolution(factory.getTargetResolution());
}
@@ -277,10 +283,18 @@ public class FOUserAgent {
/**
* Sets the base URL.
- * @param baseURL base URL
+ * @param baseUrl base URL
*/
- public void setBaseURL(String baseURL) {
- this.baseURL = baseURL;
+ public void setBaseURL(String baseUrl) {
+ this.base = baseUrl;
+ }
+
+ /**
+ * sets font base URL
+ * @param fontBaseUrl font base URL
+ */
+ public void setFontBaseURL(String fontBaseUrl) {
+ this.fontBase = fontBaseUrl;
}
/**
@@ -288,7 +302,7 @@ public class FOUserAgent {
* @return the base URL
*/
public String getBaseURL() {
- return this.baseURL;
+ return this.base;
}
/**
@@ -410,8 +424,10 @@ public class FOUserAgent {
*/
public void setTargetResolution(float dpi) {
this.targetResolution = dpi;
- log.info("target-resolution set to: " + targetResolution
- + "dpi (px2mm=" + getTargetPixelUnitToMillimeter() + ")");
+ if (log.isDebugEnabled()) {
+ log.debug("target-resolution set to: " + targetResolution
+ + "dpi (px2mm=" + getTargetPixelUnitToMillimeter() + ")");
+ }
}
/**
@@ -429,8 +445,7 @@ public class FOUserAgent {
/** @return the font base URL */
public String getFontBaseURL() {
- String fontBaseURL = getFactory().getFontBaseURL();
- return fontBaseURL != null ? fontBaseURL : getBaseURL();
+ return fontBase != null ? fontBase : getBaseURL();
}
/**
diff --git a/src/java/org/apache/fop/apps/FopFactory.java b/src/java/org/apache/fop/apps/FopFactory.java
index f7a3bd251..1e7ab2a62 100644
--- a/src/java/org/apache/fop/apps/FopFactory.java
+++ b/src/java/org/apache/fop/apps/FopFactory.java
@@ -26,6 +26,7 @@ import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.MalformedURLException;
+import java.net.URL;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
@@ -39,14 +40,13 @@ import javax.xml.transform.stream.StreamSource;
import org.xml.sax.SAXException;
import org.apache.avalon.framework.configuration.Configuration;
-import org.apache.avalon.framework.configuration.ConfigurationException;
-import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.fo.ElementMapping;
import org.apache.fop.fo.ElementMappingRegistry;
+import org.apache.fop.fonts.FontCache;
import org.apache.fop.hyphenation.HyphenationTreeResolver;
import org.apache.fop.image.ImageFactory;
import org.apache.fop.layoutmgr.LayoutManagerMaker;
@@ -62,27 +62,6 @@ import org.apache.fop.util.ContentHandlerFactoryRegistry;
*/
public class FopFactory {
- /** Defines the default target resolution (72dpi) for FOP */
- public static final float DEFAULT_TARGET_RESOLUTION = 72.0f; //dpi
-
- /** Defines the default source resolution (72dpi) for FOP */
- private static final float DEFAULT_SOURCE_RESOLUTION = 72.0f; //dpi
-
- /** Defines the default page-height */
- private static final String DEFAULT_PAGE_HEIGHT = "11in";
-
- /** Defines the default page-width */
- private static final String DEFAULT_PAGE_WIDTH = "8.26in";
-
- /** Defines if FOP should use strict validation for FO and user config */
- private static final boolean DEFAULT_STRICT_FO_VALIDATION = true;
-
- /** Defines if FOP should validate the user config strictly */
- private static final boolean DEFAULT_STRICT_USERCONFIG_VALIDATION = true;
-
- /** Defines if FOP should use an alternative rule to determine text indents */
- private static final boolean DEFAULT_BREAK_INDENT_INHERITANCE = false;
-
/** logger instance */
private static Log log = LogFactory.getLog(FopFactory.class);
@@ -100,7 +79,7 @@ public class FopFactory {
= new ContentHandlerFactoryRegistry();
/** Our default resolver if none is set */
- private URIResolver foURIResolver = new FOURIResolver();
+ private URIResolver foURIResolver = null;
/** A user settable URI Resolver */
private URIResolver uriResolver = null;
@@ -108,22 +87,23 @@ public class FopFactory {
/** The resolver for user-supplied hyphenation patterns */
private HyphenationTreeResolver hyphResolver;
+ /** Image factory for creating fop image objects */
private ImageFactory imageFactory = new ImageFactory();
- /** user configuration */
- private Configuration userConfig = null;
-
+ /** Configuration layer used to configure fop */
+ private FopFactoryConfigurator config = null;
+
/**
* The base URL for all URL resolutions, especially for
* external-graphics.
*/
- private String baseURL;
+ private String base = null;
/** The base URL for all font URL resolutions. */
- private String fontBaseURL;
+ private String fontBase = null;
/** The base URL for all hyphen URL resolutions. */
- private String hyphenBaseURL;
+ private String hyphenBase = null;
/**
* FOP has the ability, for some FO's, to continue processing even if the
@@ -131,32 +111,36 @@ public class FopFactory {
* behavior for FOP. However, this flag, if set, provides the user the
* ability for FOP to halt on all content model violations if desired.
*/
- private boolean strictFOValidation = DEFAULT_STRICT_FO_VALIDATION;
+ private boolean strictFOValidation = FopFactoryConfigurator.DEFAULT_STRICT_FO_VALIDATION;
/**
* FOP will validate the contents of the user configuration strictly
* (e.g. base-urls and font urls/paths).
*/
- private boolean strictUserConfigValidation = DEFAULT_STRICT_USERCONFIG_VALIDATION;
-
+ private boolean strictUserConfigValidation
+ = FopFactoryConfigurator.DEFAULT_STRICT_USERCONFIG_VALIDATION;
+
+ /** Font cache to speed up auto-font configuration (null if disabled) */
+ private FontCache fontCache = null;
+
/** Allows enabling kerning on the base 14 fonts, default is false */
private boolean enableBase14Kerning = false;
/** Source resolution in dpi */
- private float sourceResolution = DEFAULT_SOURCE_RESOLUTION;
+ private float sourceResolution = FopFactoryConfigurator.DEFAULT_SOURCE_RESOLUTION;
/** Target resolution in dpi */
- private float targetResolution = DEFAULT_TARGET_RESOLUTION;
+ private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION;
/** Page height */
- private String pageHeight = DEFAULT_PAGE_HEIGHT;
+ private String pageHeight = FopFactoryConfigurator.DEFAULT_PAGE_HEIGHT;
/** Page width */
- private String pageWidth = DEFAULT_PAGE_WIDTH;
+ private String pageWidth = FopFactoryConfigurator.DEFAULT_PAGE_WIDTH;
/** @see #setBreakIndentInheritanceOnReferenceAreaBoundary(boolean) */
private boolean breakIndentInheritanceOnReferenceAreaBoundary
- = DEFAULT_BREAK_INDENT_INHERITANCE;
+ = FopFactoryConfigurator.DEFAULT_BREAK_INDENT_INHERITANCE;
/** Optional overriding LayoutManagerMaker */
private LayoutManagerMaker lmMakerOverride = null;
@@ -165,14 +149,17 @@ public class FopFactory {
/** Map with cached ICC based ColorSpace objects. */
private Map colorSpaceMap = null;
-
+
/**
* Main constructor.
*/
protected FopFactory() {
+ this.config = new FopFactoryConfigurator(this);
this.elementMappingRegistry = new ElementMappingRegistry(this);
+ this.foURIResolver = new FOURIResolver(validateUserConfigStrictly());
// Use a synchronized Map - I am not really sure this is needed, but better safe than sorry.
this.colorSpaceMap = Collections.synchronizedMap(new java.util.HashMap());
+ setUseCache(FopFactoryConfigurator.DEFAULT_USE_CACHE);
}
/**
@@ -336,11 +323,42 @@ public class FopFactory {
}
/**
+ * cleans the base url
+ * @param base
+ * @return
+ * @throws MalformedURLException
+ * @throws URISyntaxException
+ */
+ private String checkBaseURL(String base) throws MalformedURLException {
+ if (!base.endsWith("/")) {
+ // The behavior described by RFC 3986 regarding resolution of relative
+ // references may be misleading for normal users:
+ // file://path/to/resources + myResource.res -> file://path/to/myResource.res
+ // file://path/to/resources/ + myResource.res -> file://path/to/resources/myResource.res
+ // We assume that even when the ending slash is missing, users have the second
+ // example in mind
+ base += "/";
+ }
+ File dir = new File(base);
+ try {
+ base = (dir.isDirectory() ? dir.toURL() : new URL(base)).toExternalForm();
+ } catch (MalformedURLException mfue) {
+ if (strictUserConfigValidation) {
+ throw mfue;
+ }
+ log.error(mfue.getMessage());
+ }
+ return base;
+ }
+
+ /**
* Sets the base URL.
- * @param baseURL base URL
+ * @param base base URL
+ * @throws MalformedURLException
+ * @throws URISyntaxException
*/
- void setBaseURL(String baseURL) {
- this.baseURL = baseURL;
+ public void setBaseURL(String base) throws MalformedURLException {
+ this.base = checkBaseURL(base);
}
/**
@@ -348,42 +366,46 @@ public class FopFactory {
* @return the base URL
*/
public String getBaseURL() {
- return this.baseURL;
+ return this.base;
}
-
+
/**
* Sets the font base URL.
- * @param fontBaseURL font base URL
+ * @param fontBase font base URL
+ * @throws MalformedURLException
+ * @throws URISyntaxException
*/
- public void setFontBaseURL(String fontBaseURL) {
- this.fontBaseURL = fontBaseURL;
+ public void setFontBaseURL(String fontBase) throws MalformedURLException {
+ this.fontBase = checkBaseURL(fontBase);
}
/** @return the font base URL */
public String getFontBaseURL() {
- return this.fontBaseURL;
+ return this.fontBase;
}
/** @return the hyphen base URL */
public String getHyphenBaseURL() {
- return hyphenBaseURL;
+ return this.hyphenBase;
}
/**
* Sets the hyphen base URL.
- * @param hyphenBaseURL hythen base URL
- */
- public void setHyphenBaseURL(final String hyphenBaseURL) {
- if (hyphenBaseURL != null) {
+ * @param hyphenBase hythen base URL
+ * @throws MalformedURLException
+ * @throws URISyntaxException
+ * */
+ public void setHyphenBaseURL(final String hyphenBase) throws MalformedURLException {
+ if (hyphenBase != null) {
this.hyphResolver = new HyphenationTreeResolver() {
public Source resolve(String href) {
- return resolveURI(href, hyphenBaseURL);
+ return resolveURI(href, hyphenBase);
}
};
}
- this.hyphenBaseURL = hyphenBaseURL;
+ this.hyphenBase = checkBaseURL(hyphenBase);
}
-
+
/**
* Sets the URI Resolver. It is used for resolving factory-level URIs like hyphenation
* patterns and as backup for URI resolution performed during a rendering run.
@@ -483,8 +505,10 @@ public class FopFactory {
*/
public void setSourceResolution(float dpi) {
this.sourceResolution = dpi;
- log.info("source-resolution set to: " + sourceResolution
- + "dpi (px2mm=" + getSourcePixelUnitToMillimeter() + ")");
+ if (log.isDebugEnabled()) {
+ log.debug("source-resolution set to: " + sourceResolution
+ + "dpi (px2mm=" + getSourcePixelUnitToMillimeter() + ")");
+ }
}
/** @return the resolution for resolution-dependant output */
@@ -538,7 +562,9 @@ public class FopFactory {
*/
public void setPageHeight(String pageHeight) {
this.pageHeight = pageHeight;
- log.info("Default page-height set to: " + pageHeight);
+ if (log.isDebugEnabled()) {
+ log.debug("Default page-height set to: " + pageHeight);
+ }
}
/**
@@ -559,7 +585,9 @@ public class FopFactory {
*/
public void setPageWidth(String pageWidth) {
this.pageWidth = pageWidth;
- log.info("Default page-width set to: " + pageWidth);
+ if (log.isDebugEnabled()) {
+ log.debug("Default page-width set to: " + pageWidth);
+ }
}
/**
@@ -595,7 +623,7 @@ public class FopFactory {
public Set getIgnoredNamespace() {
return Collections.unmodifiableSet(this.ignoredNamespaces);
}
-
+
//------------------------------------------- Configuration stuff
/**
@@ -605,14 +633,9 @@ public class FopFactory {
* @throws SAXException if a parsing error occurs
*/
public void setUserConfig(File userConfigFile) throws SAXException, IOException {
- try {
- DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
- setUserConfig(cfgBuilder.buildFromFile(userConfigFile));
- } catch (ConfigurationException e) {
- throw new FOPException(e);
- }
+ config.setUserConfig(userConfigFile);
}
-
+
/**
* Set the user configuration from an URI.
* @param uri the URI to the configuration file
@@ -620,12 +643,7 @@ public class FopFactory {
* @throws SAXException if a parsing error occurs
*/
public void setUserConfig(String uri) throws SAXException, IOException {
- try {
- DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
- setUserConfig(cfgBuilder.build(uri));
- } catch (ConfigurationException e) {
- throw new FOPException(e);
- }
+ config.setUserConfig(uri);
}
/**
@@ -634,12 +652,7 @@ public class FopFactory {
* @throws FOPException if a configuration problem occurs
*/
public void setUserConfig(Configuration userConfig) throws FOPException {
- this.userConfig = userConfig;
- try {
- configure(userConfig);
- } catch (ConfigurationException e) {
- throw new FOPException(e);
- }
+ config.setUserConfig(userConfig);
}
/**
@@ -647,162 +660,54 @@ public class FopFactory {
* @return the user configuration
*/
public Configuration getUserConfig() {
- return userConfig;
+ return config.getUserConfig();
}
/**
- * Returns the configuration subtree for a specific renderer.
- * @param mimeType MIME type of the renderer
- * @return the requested configuration subtree, null if there's no configuration
+ * Is the user configuration to be validated?
+ * @param strictUserConfigValidation strict user config validation
*/
- public Configuration getUserRendererConfig(String mimeType) {
- if (userConfig == null || mimeType == null) {
- return null;
- }
-
- Configuration userRendererConfig = null;
-
- Configuration[] cfgs
- = userConfig.getChild("renderers").getChildren("renderer");
- for (int i = 0; i < cfgs.length; ++i) {
- Configuration child = cfgs[i];
- try {
- if (child.getAttribute("mime").equals(mimeType)) {
- userRendererConfig = child;
- break;
- }
- } catch (ConfigurationException e) {
- // silently pass over configurations without mime type
- }
- }
- log.debug((userRendererConfig == null ? "No u" : "U")
- + "ser configuration found for MIME type " + mimeType);
- return userRendererConfig;
+ public void setStrictUserConfigValidation(boolean strictUserConfigValidation) {
+ this.strictUserConfigValidation = strictUserConfigValidation;
}
/**
- * Initializes user agent settings from the user configuration
- * file, if present: baseURL, resolution, default page size,...
- *
- * @throws ConfigurationException when there is an entry that
- * misses the required attribute
- * Configures the FopFactory.
- * @param cfg Avalon Configuration Object
- * @see org.apache.avalon.framework.configuration.Configurable
- */
- public void configure(Configuration cfg) throws ConfigurationException {
- log.info("Initializing FopFactory Configuration");
-
- if (cfg.getChild("strict-configuration", false) != null) {
- this.strictUserConfigValidation
- = cfg.getChild("strict-configuration").getValueAsBoolean();
- }
- if (cfg.getChild("strict-validation", false) != null) {
- this.strictFOValidation = cfg.getChild("strict-validation").getValueAsBoolean();
- }
- if (cfg.getChild("base", false) != null) {
- try {
- setBaseURL(getBaseURLfromConfig(cfg, "base"));
- } catch (ConfigurationException e) {
- if (strictUserConfigValidation) {
- throw e;
- }
- log.error(e.getMessage());
- }
- }
- if (cfg.getChild("font-base", false) != null) {
- try {
- setFontBaseURL(getBaseURLfromConfig(cfg, "font-base"));
- } catch (ConfigurationException e) {
- if (strictUserConfigValidation) {
- throw e;
- }
- log.error(e.getMessage());
- }
- }
- if (cfg.getChild("hyphenation-base", false) != null) {
- try {
- setHyphenBaseURL(getBaseURLfromConfig(cfg, "hyphenation-base"));
- } catch (ConfigurationException e) {
- if (strictUserConfigValidation) {
- throw e;
- }
- log.error(e.getMessage());
- }
- }
- if (cfg.getChild("source-resolution", false) != null) {
- setSourceResolution(
- cfg.getChild("source-resolution").getValueAsFloat(DEFAULT_SOURCE_RESOLUTION));
- }
- if (cfg.getChild("target-resolution", false) != null) {
- setTargetResolution(
- cfg.getChild("target-resolution").getValueAsFloat(DEFAULT_TARGET_RESOLUTION));
- }
- if (cfg.getChild("break-indent-inheritance", false) != null) {
- setBreakIndentInheritanceOnReferenceAreaBoundary(
- cfg.getChild("break-indent-inheritance").getValueAsBoolean());
- }
- Configuration pageConfig = cfg.getChild("default-page-settings");
- if (pageConfig.getAttribute("height", null) != null) {
- setPageHeight(pageConfig.getAttribute("height", DEFAULT_PAGE_HEIGHT));
- }
- if (pageConfig.getAttribute("width", null) != null) {
- setPageWidth(pageConfig.getAttribute("width", DEFAULT_PAGE_WIDTH));
- }
+ * Is the user configuration to be validated?
+ * @return if the user configuration should be validated
+ */
+ public boolean validateUserConfigStrictly() {
+ return this.strictUserConfigValidation;
}
+ //------------------------------------------- Cache related stuff
+
/**
- * Retrieves and verifies a base URL.
- * @param cfg The Configuration object to retrieve the base URL from
- * @param name the element name for the base URL
- * @return the requested base URL or null if not available
- * @throws ConfigurationException
- */
- public static String getBaseURLfromConfig(Configuration cfg, String name)
- throws ConfigurationException {
- if (cfg.getChild(name, false) != null) {
- try {
- String cfgBasePath = cfg.getChild(name).getValue(null);
- if (cfgBasePath != null) {
- // Is the path a dirname?
- File dir = new File(cfgBasePath);
-// if (!dir.exists()) {
-// throw new ConfigurationException("Base URL '" + name
-// + "' references non-existent resource '"
-// + cfgBasePath + "'");
-// } else if (dir.isDirectory()) {
- if (dir.isDirectory()) {
- // Yes, convert it into a URL
- cfgBasePath = dir.toURL().toExternalForm();
- }
- // Otherwise, this is already a URL
- }
- log.info(name + " set to: " + cfgBasePath);
- return cfgBasePath;
- } catch (MalformedURLException mue) {
- throw new ConfigurationException("Base URL '" + name
- + "' in user config is malformed!");
+ * 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.fontCache = null;
}
- return null;
}
/**
- * Is the user configuration to be validated?
- * @param strictUserConfigValidation strict user config validation
+ * Cache results of font triplet detection/auto-config?
+ * @return whether this factory is uses the cache
*/
- public void setStrictUserConfigValidation(boolean strictUserConfigValidation) {
- this.strictUserConfigValidation = strictUserConfigValidation;
+ public boolean useCache() {
+ return (this.fontCache != null);
}
- /**
- * Is the user configuration to be validated?
- * @return if the user configuration should be validated
- */
- public boolean validateUserConfigStrictly() {
- return this.strictUserConfigValidation;
+ public FontCache getFontCache() {
+ return this.fontCache;
}
-
+
//------------------------------------------- URI resolution
/**
@@ -810,26 +715,29 @@ public class FopFactory {
* Will use the configured resolver and if not successful fall back
* to the default resolver.
* @param uri URI to access
- * @param base the base URI to resolve against
+ * @param baseUri the base URI to resolve against
* @return A {@link javax.xml.transform.Source} object, or null if the URI
* cannot be resolved.
* @see org.apache.fop.apps.FOURIResolver
*/
- public Source resolveURI(String uri, String base) {
+ public Source resolveURI(String uri, String baseUri) {
Source source = null;
//RFC 2397 data URLs don't need to be resolved, just decode them.
boolean bypassURIResolution = uri.startsWith("data:");
if (!bypassURIResolution && uriResolver != null) {
try {
- source = uriResolver.resolve(uri, base);
+ source = uriResolver.resolve(uri, baseUri);
} catch (TransformerException te) {
log.error("Attempt to resolve URI '" + uri + "' failed: ", te);
+ if (validateUserConfigStrictly()) {
+ return null;
+ }
}
}
if (source == null) {
// URI Resolver not configured or returned null, use default resolver
try {
- source = foURIResolver.resolve(uri, base);
+ source = foURIResolver.resolve(uri, baseUri);
} catch (TransformerException te) {
log.error("Attempt to resolve URI '" + uri + "' failed: ", te);
}
@@ -846,18 +754,18 @@ public class FopFactory {
* The FOP URI resolver is used to try and locate the ICC file.
* If that fails null is returned.
*
- * @param base a base URI to resolve relative URIs
+ * @param baseUri a base URI to resolve relative URIs
* @param iccProfileSrc ICC Profile source to return a ColorSpace for
* @return ICC ColorSpace object or null if ColorSpace could not be created
*/
- public ColorSpace getColorSpace(String base, String iccProfileSrc) {
+ public ColorSpace getColorSpace(String baseUri, String iccProfileSrc) {
ColorSpace colorSpace = null;
- if (!this.colorSpaceMap.containsKey(base + iccProfileSrc)) {
+ if (!this.colorSpaceMap.containsKey(baseUri + iccProfileSrc)) {
try {
ICC_Profile iccProfile = null;
// First attempt to use the FOP URI resolver to locate the ICC
// profile
- Source src = this.resolveURI(iccProfileSrc, base);
+ Source src = this.resolveURI(iccProfileSrc, baseUri);
if (src != null && src instanceof StreamSource) {
// FOP URI resolver found ICC profile - create ICC profile
// from the Source
@@ -882,16 +790,16 @@ public class FopFactory {
if (colorSpace != null) {
// Put in cache (not when VM resolved it as we can't control
- this.colorSpaceMap.put(base + iccProfileSrc, colorSpace);
+ this.colorSpaceMap.put(baseUri + iccProfileSrc, colorSpace);
} else {
// TODO To avoid an excessive amount of warnings perhaps
// register a null ColorMap in the colorSpaceMap
log.warn("Color profile '" + iccProfileSrc + "' not found.");
}
} else {
- colorSpace = (ColorSpace) this.colorSpaceMap.get(base
+ colorSpace = (ColorSpace) this.colorSpaceMap.get(baseUri
+ iccProfileSrc);
}
return colorSpace;
- }
+ }
}
diff --git a/src/java/org/apache/fop/apps/FopFactoryConfigurator.java b/src/java/org/apache/fop/apps/FopFactoryConfigurator.java
new file mode 100644
index 000000000..d708cd989
--- /dev/null
+++ b/src/java/org/apache/fop/apps/FopFactoryConfigurator.java
@@ -0,0 +1,241 @@
+/*
+ * 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.apps;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fop.util.LogUtil;
+import org.xml.sax.SAXException;
+
+/**
+ * FopFactory configurator
+ */
+public class FopFactoryConfigurator {
+
+ /** Defines if FOP should use an alternative rule to determine text indents */
+ public static final boolean DEFAULT_BREAK_INDENT_INHERITANCE = false;
+
+ /** Defines if FOP should validate the user config strictly */
+ public static final boolean DEFAULT_STRICT_USERCONFIG_VALIDATION = true;
+
+ /** Defines if FOP should use strict validation for FO and user config */
+ public static final boolean DEFAULT_STRICT_FO_VALIDATION = true;
+
+ /** Defines the default page-width */
+ public static final String DEFAULT_PAGE_WIDTH = "8.26in";
+
+ /** Defines the default page-height */
+ public static final String DEFAULT_PAGE_HEIGHT = "11in";
+
+ /** Defines the default source resolution (72dpi) for FOP */
+ public static final float DEFAULT_SOURCE_RESOLUTION = 72.0f; //dpi
+
+ /** Defines the default target resolution (72dpi) for FOP */
+ public static final float DEFAULT_TARGET_RESOLUTION = 72.0f; //dpi
+
+ /** Use cache (record previously detected font triplet info) */
+ public static final boolean DEFAULT_USE_CACHE = true;
+
+ /** logger instance */
+ private final Log log = LogFactory.getLog(FopFactoryConfigurator.class);
+
+ /** Fop factory */
+ private FopFactory factory = null;
+
+ /** Fop factory configuration */
+ private Configuration cfg = null;
+
+ /**
+ * Default constructor
+ * @param factory fop factory
+ */
+ public FopFactoryConfigurator(FopFactory factory) {
+ super();
+ this.factory = factory;
+ }
+
+ /**
+ * Initializes user agent settings from the user configuration
+ * file, if present: baseURL, resolution, default page size,...
+ * @param factory fop factory
+ * @throws FOPException fop exception
+ */
+ public void configure(FopFactory factory) throws FOPException {
+ if (log.isDebugEnabled()) {
+ log.debug("Initializing FopFactory Configuration");
+ }
+
+ // strict configuration
+ if (cfg.getChild("strict-configuration", false) != null) {
+ try {
+ factory.setStrictUserConfigValidation(
+ cfg.getChild("strict-configuration").getValueAsBoolean());
+ } catch (ConfigurationException e) {
+ LogUtil.handleException(log, e, false);
+ }
+ }
+ boolean strict = factory.validateUserConfigStrictly();
+
+ // strict fo validation
+ if (cfg.getChild("strict-validation", false) != null) {
+ try {
+ factory.setStrictValidation(
+ cfg.getChild("strict-validation").getValueAsBoolean());
+ } catch (ConfigurationException e) {
+ LogUtil.handleException(log, e, strict);
+ }
+ }
+
+ // base definitions for relative path resolution
+ if (cfg.getChild("base", false) != null) {
+ try {
+ factory.setBaseURL(
+ cfg.getChild("base").getValue(null));
+ } catch (MalformedURLException mfue) {
+ LogUtil.handleException(log, mfue, strict);
+ }
+ }
+ if (cfg.getChild("font-base", false) != null) {
+ try {
+ factory.setFontBaseURL(
+ cfg.getChild("font-base").getValue(null));
+ } catch (MalformedURLException mfue) {
+ LogUtil.handleException(log, mfue, strict);
+ }
+ }
+ if (cfg.getChild("hyphenation-base", false) != null) {
+ try {
+ factory.setHyphenBaseURL(
+ cfg.getChild("hyphenation-base").getValue(null));
+ } catch (MalformedURLException mfue) {
+ LogUtil.handleException(log, mfue, strict);
+ }
+ }
+
+ // renderer options
+ if (cfg.getChild("source-resolution", false) != null) {
+ factory.setSourceResolution(
+ cfg.getChild("source-resolution").getValueAsFloat(
+ FopFactoryConfigurator.DEFAULT_SOURCE_RESOLUTION));
+ if (log.isDebugEnabled()) {
+ log.debug("source-resolution set to: " + factory.getSourceResolution()
+ + "dpi (px2mm=" + factory.getSourcePixelUnitToMillimeter() + ")");
+ }
+ }
+ if (cfg.getChild("target-resolution", false) != null) {
+ factory.setTargetResolution(
+ cfg.getChild("target-resolution").getValueAsFloat(
+ FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION));
+ if (log.isDebugEnabled()) {
+ log.debug("target-resolution set to: " + factory.getTargetResolution()
+ + "dpi (px2mm=" + factory.getTargetPixelUnitToMillimeter()
+ + ")");
+ }
+ }
+ if (cfg.getChild("break-indent-inheritance", false) != null) {
+ try {
+ factory.setBreakIndentInheritanceOnReferenceAreaBoundary(
+ cfg.getChild("break-indent-inheritance").getValueAsBoolean());
+ } catch (ConfigurationException e) {
+ LogUtil.handleException(log, e, strict);
+ }
+ }
+ Configuration pageConfig = cfg.getChild("default-page-settings");
+ if (pageConfig.getAttribute("height", null) != null) {
+ factory.setPageHeight(
+ pageConfig.getAttribute("height", FopFactoryConfigurator.DEFAULT_PAGE_HEIGHT));
+ if (log.isInfoEnabled()) {
+ log.info("Default page-height set to: " + factory.getPageHeight());
+ }
+ }
+ if (pageConfig.getAttribute("width", null) != null) {
+ factory.setPageWidth(
+ pageConfig.getAttribute("width", FopFactoryConfigurator.DEFAULT_PAGE_WIDTH));
+ if (log.isInfoEnabled()) {
+ log.info("Default page-width set to: " + factory.getPageWidth());
+ }
+ }
+
+ // caching (fonts)
+ if (cfg.getChild("use-cache", false) != null) {
+ try {
+ factory.setUseCache(
+ cfg.getChild("use-cache").getValueAsBoolean());
+ } catch (ConfigurationException mfue) {
+ LogUtil.handleException(log, mfue, strict);
+ }
+ }
+ }
+
+ /**
+ * Set the user configuration.
+ * @param userConfigFile the configuration file
+ * @throws IOException if an I/O error occurs
+ * @throws SAXException if a parsing error occurs
+ */
+ public void setUserConfig(File userConfigFile) throws SAXException, IOException {
+ try {
+ DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
+ setUserConfig(cfgBuilder.buildFromFile(userConfigFile));
+ } catch (ConfigurationException e) {
+ throw new FOPException(e);
+ }
+ }
+
+ /**
+ * Set the user configuration from an URI.
+ * @param uri the URI to the configuration file
+ * @throws IOException if an I/O error occurs
+ * @throws SAXException if a parsing error occurs
+ */
+ public void setUserConfig(String uri) throws SAXException, IOException {
+ try {
+ DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
+ setUserConfig(cfgBuilder.build(uri));
+ } catch (ConfigurationException e) {
+ throw new FOPException(e);
+ }
+ }
+
+ /**
+ * Set the user configuration.
+ * @param cfg avalon configuration
+ * @throws FOPException if a configuration problem occurs
+ */
+ public void setUserConfig(Configuration cfg) throws FOPException {
+ this.cfg = cfg;
+ configure(this.factory);
+ }
+
+ /**
+ * Get the avalon user configuration.
+ * @return the user configuration
+ */
+ public Configuration getUserConfig() {
+ return this.cfg;
+ }
+}