diff options
Diffstat (limited to 'src/java/org/apache')
74 files changed, 3537 insertions, 1319 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; + } +} diff --git a/src/java/org/apache/fop/area/AreaTreeParser.java b/src/java/org/apache/fop/area/AreaTreeParser.java index 9e293afac..ba819621e 100644 --- a/src/java/org/apache/fop/area/AreaTreeParser.java +++ b/src/java/org/apache/fop/area/AreaTreeParser.java @@ -1060,7 +1060,7 @@ public class AreaTreeParser { if (fontName != null) { String fontStyle = attributes.getValue("font-style"); int fontWeight = getAttributeAsInteger( - attributes, "font-weight", Font.NORMAL); + attributes, "font-weight", Font.WEIGHT_NORMAL); area.addTrait(trait, FontInfo.createFontKey(fontName, fontStyle, fontWeight)); } diff --git a/src/java/org/apache/fop/cli/CommandLineOptions.java b/src/java/org/apache/fop/cli/CommandLineOptions.java index ce6aa64b8..63a817071 100644 --- a/src/java/org/apache/fop/cli/CommandLineOptions.java +++ b/src/java/org/apache/fop/cli/CommandLineOptions.java @@ -143,7 +143,7 @@ public class CommandLineOptions { dumpConfiguration(); } checkSettings(); - createUserConfig(); + setUserConfig(); //Factory config is set up, now we can create the user agent foUserAgent = factory.newFOUserAgent(); @@ -772,11 +772,11 @@ public class CommandLineOptions { } // end checkSettings /** - * Create the user configuration. + * Sets the user configuration. * @throws FOPException if creating the user configuration fails * @throws IOException */ - private void createUserConfig() throws FOPException, IOException { + private void setUserConfig() throws FOPException, IOException { if (userConfigFile == null) { return; } diff --git a/src/java/org/apache/fop/fonts/CachedFontInfo.java b/src/java/org/apache/fop/fonts/CachedFontInfo.java new file mode 100644 index 000000000..281289193 --- /dev/null +++ b/src/java/org/apache/fop/fonts/CachedFontInfo.java @@ -0,0 +1,117 @@ +/* + * 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.util.List; + +import org.apache.xml.utils.URI; +import org.apache.xml.utils.URI.MalformedURIException; + +/** + * 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) { + if (urlStr.startsWith("file:")) { + URI uri; + try { + uri = new URI(urlStr); + urlStr = uri.getPath(); + } catch (MalformedURIException e) { + // do nothing + } + } + File 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 + * @see java.lang.Object#toString() + */ + public String toString() { + return super.toString() + ", lastModified=" + lastModified; + } +} diff --git a/src/java/org/apache/fop/fonts/CustomFont.java b/src/java/org/apache/fop/fonts/CustomFont.java index 5d7221c13..1455319e6 100644 --- a/src/java/org/apache/fop/fonts/CustomFont.java +++ b/src/java/org/apache/fop/fonts/CustomFont.java @@ -30,8 +30,9 @@ public abstract class CustomFont extends Typeface implements FontDescriptor, MutableFont { private String fontName = null; + private String fontSubName = null; private String embedFileName = null; - protected String embedResourceName = null; + private String embedResourceName = null; private FontResolver resolver = null; private int capHeight = 0; @@ -51,7 +52,6 @@ public abstract class CustomFont extends Typeface private boolean useKerning = true; - /** * @see org.apache.fop.fonts.FontMetrics#getFontName() */ @@ -60,6 +60,21 @@ public abstract class CustomFont extends Typeface } /** + * @see org.apache.fop.fonts.FontMetrics#getStrippedFontName() + */ + public String getStrippedFontName() { + return FontUtil.stripWhiteSpace(fontName); + } + + /** + * Returns font's subfamily name. + * @return the font's subfamily name + */ + public String getFontSubName() { + return fontSubName; + } + + /** * Returns an URI representing an embeddable font file. The URI will often * be a filename or an URL. * @return URI to an embeddable font file or null if not available. @@ -239,6 +254,14 @@ public abstract class CustomFont extends Typeface } /** + * Sets the font's subfamily name. + * @param subFamilyName the subfamily name of the font + */ + public void setFontSubFamilyName(String subFamilyName) { + this.fontSubName = subFamilyName; + } + + /** * @see org.apache.fop.fonts.MutableFont#setEmbedFileName(String) */ public void setEmbedFileName(String path) { diff --git a/src/java/org/apache/fop/fonts/EmbedFontInfo.java b/src/java/org/apache/fop/fonts/EmbedFontInfo.java index 45f9bb6e4..ad8915d9d 100644 --- a/src/java/org/apache/fop/fonts/EmbedFontInfo.java +++ b/src/java/org/apache/fop/fonts/EmbedFontInfo.java @@ -19,17 +19,26 @@ package org.apache.fop.fonts; +import java.io.Serializable; import java.util.List; /** * FontInfo contains meta information on fonts (where is the metrics file etc.) */ -public class EmbedFontInfo { +public class EmbedFontInfo implements Serializable { - private String metricsFile, embedFile; - private boolean kerning; - private List fontTriplets; - + /** Serialization Version UID */ + private static final long serialVersionUID = -9075848379822693399L; + + /** filename of the metrics file */ + protected String metricsFile; + /** filename of the main font file */ + protected String embedFile; + /** false, to disable kerning */ + protected boolean kerning; + /** the list of associated font triplets */ + protected List fontTriplets; + /** * Main constructor * @param metricsFile Path to the xml file containing font metrics @@ -44,7 +53,7 @@ public class EmbedFontInfo { this.kerning = kerning; this.fontTriplets = fontTriplets; } - + /** * Returns the path to the metrics file * @return the metrics file path @@ -76,6 +85,10 @@ public class EmbedFontInfo { public List getFontTriplets() { return fontTriplets; } - + + /** @see java.lang.Object#toString() */ + public String toString() { + return "metrics-url=" + metricsFile + ",embed-url=" + embedFile + + ", kerning=" + kerning + ", font-triplet=" + fontTriplets; + } } - diff --git a/src/java/org/apache/fop/fonts/Font.java b/src/java/org/apache/fop/fonts/Font.java index a6b6d52d4..de83072c6 100644 --- a/src/java/org/apache/fop/fonts/Font.java +++ b/src/java/org/apache/fop/fonts/Font.java @@ -27,12 +27,22 @@ import java.util.Map; */ public class Font { - /** Default fallback key */ - public static final FontTriplet DEFAULT_FONT = new FontTriplet("any", "normal", 400); - /** Normal font weight */ - public static final int NORMAL = 400; /** Bold font weight */ - public static final int BOLD = 700; + public static final int WEIGHT_BOLD = 700; + + /** Normal font weight */ + public static final int WEIGHT_NORMAL = 400; + + /** Normal font style */ + public static final String STYLE_NORMAL = "normal"; + + /** Italic font style */ + public static final String STYLE_ITALIC = "italic"; + + /** Default fallback key */ + public static final FontTriplet DEFAULT_FONT = new FontTriplet( + "any", STYLE_NORMAL, WEIGHT_NORMAL); + private String fontName; private FontTriplet triplet; diff --git a/src/java/org/apache/fop/fonts/FontCache.java b/src/java/org/apache/fop/fonts/FontCache.java new file mode 100644 index 000000000..036ec724e --- /dev/null +++ b/src/java/org/apache/fop/fonts/FontCache.java @@ -0,0 +1,330 @@ +/* + * 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.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.Map; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.apps.FOPException; +import org.apache.fop.util.LogUtil; + +/** + * Fop cache (currently only used for font info caching) + */ +public final class FontCache implements Serializable { + + /** Serialization Version UID */ + private static final long serialVersionUID = 605232520271754717L; + + /** logging instance */ + private static Log log = LogFactory.getLog(FontCache.class); + + /** FOP's user directory name */ + private static final String FOP_USER_DIR = ".fop"; + + /** 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 transient Object changeLock = new Object(); + + /** master mapping of font url -> font info */ + private Map fontMap = new java.util.HashMap(); + + /** mapping of font url -> file modified date */ + private Map failedFontMap = new java.util.HashMap(); + + /** + * Default constructor + */ + public FontCache() { + //nop + } + + private void readObject(java.io.ObjectInputStream in) + throws IOException, ClassNotFoundException { + in.defaultReadObject(); + this.changeLock = new Object(); //Initialize transient field + } + + private static File getUserHome() { + String s = System.getProperty("user.home"); + if (s != null) { + File userDir = new File(s); + if (userDir.exists()) { + return userDir; + } + } + return null; + } + + /** + * Returns the default font cache file. + * @param forWriting true if the user directory should be created + * @return the default font cache file + */ + public static File getDefaultCacheFile(boolean forWriting) { + File userHome = getUserHome(); + if (userHome != null) { + File fopUserDir = new File(userHome, FOP_USER_DIR); + if (forWriting) { + fopUserDir.mkdir(); + } + return new File(fopUserDir, DEFAULT_CACHE_FILENAME); + } + return new File(FOP_USER_DIR); + } + + /** + * 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) + */ + 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) + */ + public static FontCache loadFrom(File cacheFile) { + if (cacheFile.exists()) { + try { + if (log.isTraceEnabled()) { + log.trace("Loading font cache from " + cacheFile.getCanonicalPath()); + } + InputStream in = new java.io.FileInputStream(cacheFile); + in = new java.io.BufferedInputStream(in); + ObjectInputStream oin = new ObjectInputStream(in); + try { + 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 + 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."); + } + } + return null; + } + + /** + * Writes the font cache to disk. + * @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 + */ + public void saveTo(File cacheFile) throws FOPException { + synchronized (changeLock) { + if (changed) { + try { + if (log.isTraceEnabled()) { + 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); + try { + oout.writeObject(this); + } finally { + IOUtils.closeQuietly(oout); + } + } catch (IOException ioe) { + LogUtil.handleException(log, ioe, true); + } + changed = false; + log.trace("Cache file written."); + } + } + } + + /** + * creates a key given a font info for the font mapping + * @param fontInfo font info + * @return font cache key + */ + protected static String getCacheKey(EmbedFontInfo fontInfo) { + if (fontInfo != null) { + String embedFile = fontInfo.getEmbedFile(); + String metricsFile = fontInfo.getMetricsFile(); + return (embedFile != null) ? embedFile : metricsFile; + } + return null; + } + + /** + * cache has been updated since it was read + * @return if this cache has changed + */ + public boolean hasChanged() { + return this.changed; + } + + /** + * is this font in the cache? + * @param embedUrl font info + * @return boolean + */ + public boolean containsFont(String embedUrl) { + if (embedUrl != null) { + return fontMap.containsKey(embedUrl); + } + return false; + } + + /** + * is this font info in the cache? + * @param fontInfo font info + * @return font + */ + public boolean containsFont(EmbedFontInfo fontInfo) { + if (fontInfo != null) { + return fontMap.containsKey(getCacheKey(fontInfo)); + } + return false; + } + + /** + * adds a font info to cache + * @param fontInfo font info + */ + public void addFont(EmbedFontInfo fontInfo) { + String cacheKey = getCacheKey(fontInfo); + synchronized (changeLock) { + if (!containsFont(cacheKey)) { + 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)); + } + changed = true; + } + } + } + + /** + * returns a font from the cache + * @param embedUrl font info + * @return boolean + */ + public CachedFontInfo getFont(String embedUrl) { + if (containsFont(embedUrl)) { + return (CachedFontInfo)fontMap.get(embedUrl); + } + return null; + } + + /** + * removes font from cache + * @param embedUrl embed url + */ + public void removeFont(String embedUrl) { + synchronized (changeLock) { + if (containsFont(embedUrl)) { + if (log.isTraceEnabled()) { + log.trace("Font removed from cache: " + embedUrl); + } + fontMap.remove(embedUrl); + changed = true; + } + } + } + + /** + * has this font previously failed to load? + * @param embedUrl embed url + * @param lastModified last modified + * @return whether this is a failed font + */ + public boolean isFailedFont(String embedUrl, long lastModified) { + if (failedFontMap.containsKey(embedUrl)) { + synchronized (changeLock) { + long failedLastModified = ((Long)failedFontMap.get(embedUrl)).longValue(); + if (lastModified != failedLastModified) { + // this font has been changed so lets remove it + // from failed font map for now + failedFontMap.remove(embedUrl); + changed = true; + } + } + return true; + } + return false; + } + + /** + * registers a failed font with the cache + * @param embedUrl embed url + * @param lastModified time last modified + */ + public void registerFailedFont(String embedUrl, long lastModified) { + synchronized (changeLock) { + if (!failedFontMap.containsKey(embedUrl)) { + failedFontMap.put(embedUrl, new Long(lastModified)); + changed = true; + } + } + } + + /** + * Clears font cache + */ + public void clear() { + synchronized (changeLock) { + if (log.isTraceEnabled()) { + log.trace("Font cache cleared."); + } + fontMap.clear(); + failedFontMap.clear(); + changed = true; + } + } +} diff --git a/src/java/org/apache/fop/fonts/FontInfo.java b/src/java/org/apache/fop/fonts/FontInfo.java index 987bb94b7..995d59bf8 100644 --- a/src/java/org/apache/fop/fonts/FontInfo.java +++ b/src/java/org/apache/fop/fonts/FontInfo.java @@ -130,6 +130,9 @@ public class FontInfo { */ private FontTriplet fontLookup(String family, String style, int weight, boolean substFont) { + if (log.isTraceEnabled()) { + log.trace("Font lookup: " + family + " " + style + " " + weight); + } FontTriplet startKey = createFontKey(family, style, weight); FontTriplet key = startKey; // first try given parameters @@ -146,13 +149,13 @@ public class FontInfo { // only if the font may be substituted // fallback 1: try the same font-family and weight with default style if (f == null) { - key = createFontKey(family, "normal", weight); + key = createFontKey(family, Font.STYLE_NORMAL, weight); f = getInternalFontKey(key); } // fallback 2: try the same font-family with default style and weight if (f == null) { - key = createFontKey(family, "normal", 400); + key = createFontKey(family, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); f = getInternalFontKey(key); } @@ -426,8 +429,4 @@ public class FontInfo { return 0; } } - } - - - diff --git a/src/java/org/apache/fop/fonts/FontLoader.java b/src/java/org/apache/fop/fonts/FontLoader.java index 4377f9fab..c48e36453 100644 --- a/src/java/org/apache/fop/fonts/FontLoader.java +++ b/src/java/org/apache/fop/fonts/FontLoader.java @@ -19,6 +19,7 @@ package org.apache.fop.fonts;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
@@ -28,6 +29,8 @@ import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource;
import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.apache.fop.fonts.truetype.TTFFontLoader;
import org.apache.fop.fonts.type1.Type1FontLoader;
@@ -37,6 +40,51 @@ import org.apache.fop.fonts.type1.Type1FontLoader; public abstract class FontLoader {
/**
+ * logging instance
+ */
+ protected static Log log = LogFactory.getLog(FontLoader.class);
+
+ /** URI representing the font file */
+ protected String fontFileURI = null;
+ /** the InputStream to load the font from */
+ protected InputStream in = null;
+ /** the FontResolver to use for font URI resolution */
+ protected FontResolver resolver = null;
+ /** the loaded font */
+ protected CustomFont returnFont = null;
+
+ /** true if the font has been loaded */
+ protected boolean loaded = false;
+
+ /**
+ * Default constructor.
+ * @param fontFileURI the URI to the PFB file of a Type 1 font
+ * @param in the InputStream reading the PFM file of a Type 1 font
+ * @param resolver the font resolver used to resolve URIs
+ */
+ public FontLoader(String fontFileURI, InputStream in, FontResolver resolver) {
+ this.fontFileURI = fontFileURI;
+ this.in = in;
+ this.resolver = resolver;
+ }
+
+ private static boolean isType1(String fontURI) {
+ return fontURI.toLowerCase().endsWith(".pfb");
+ }
+
+ /**
+ * 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 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)
+ throws IOException {
+ return loadFont(fontFile.getAbsolutePath(), 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 resolver the font resolver to use when resolving URIs
@@ -45,21 +93,38 @@ public abstract class FontLoader { */
public static CustomFont loadFont(String fontFileURI, FontResolver resolver)
throws IOException {
- FontLoader loader;
fontFileURI = fontFileURI.trim();
String name = fontFileURI.toLowerCase();
String effURI;
- boolean type1 = false;
- if (name.endsWith(".pfb")) {
- type1 = true;
+ boolean type1 = isType1(fontFileURI);
+ if (type1) {
effURI = name.substring(0, fontFileURI.length() - 4) + ".pfm";
} else {
effURI = fontFileURI;
}
-
+ if (log.isDebugEnabled()) {
+ log.debug("opening " + effURI);
+ }
InputStream in = openFontFile(resolver, effURI);
+ return loadFontFromInputStream(fontFileURI, resolver, type1, in);
+ }
+
+ /**
+ * Loads and returns a font given an input stream.
+ * @param fontFileURI font file uri
+ * @param resolver font resolver
+ * @param isType1 is it a type1 font?
+ * @param in input stream
+ * @return the loaded font.
+ * @throws IOException In case of an I/O error
+ */
+ protected static CustomFont loadFontFromInputStream(
+ String fontFileURI, FontResolver resolver, boolean isType1,
+ InputStream in)
+ throws IOException {
+ FontLoader loader;
try {
- if (type1) {
+ if (isType1) {
loader = new Type1FontLoader(fontFileURI, in, resolver);
} else {
loader = new TTFFontLoader(fontFileURI, in, resolver);
@@ -70,6 +135,14 @@ public abstract class FontLoader { }
}
+ /**
+ * Opens a font file and returns an input stream.
+ * @param resolver the FontResolver to use for font URI resolution
+ * @param uri the URI representing the font
+ * @return the InputStream to read the font from.
+ * @throws IOException In case of an I/O error
+ * @throws MalformedURLException If an invalid URL is built
+ */
private static InputStream openFontFile(FontResolver resolver, String uri)
throws IOException, MalformedURLException {
InputStream in = null;
@@ -96,11 +169,18 @@ public abstract class FontLoader { }
return in;
}
-
+
/**
- * @return the font loaded by this loader
+ * Reads/parses the font data.
+ * @throws IOException In case of an I/O error
*/
- public abstract CustomFont getFont();
+ protected abstract void read() throws IOException;
-
+ /** @see org.apache.fop.fonts.FontLoader#getFont() */
+ public CustomFont getFont() throws IOException {
+ if (!loaded) {
+ read();
+ }
+ return this.returnFont;
+ }
}
diff --git a/src/java/org/apache/fop/fonts/FontSetup.java b/src/java/org/apache/fop/fonts/FontSetup.java index 9659398ba..0028f3281 100644 --- a/src/java/org/apache/fop/fonts/FontSetup.java +++ b/src/java/org/apache/fop/fonts/FontSetup.java @@ -34,16 +34,11 @@ import org.apache.fop.fonts.base14.CourierOblique; import org.apache.fop.fonts.base14.CourierBoldOblique; import org.apache.fop.fonts.base14.Symbol; import org.apache.fop.fonts.base14.ZapfDingbats; -import org.apache.fop.render.PrintRenderer; // commons logging import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -// Avalon -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; - // Java import java.util.List; @@ -62,8 +57,8 @@ public class FontSetup { /** * logging instance */ - protected static Log log = LogFactory.getLog("org.apache.fop.fonts"); - + protected static Log log = LogFactory.getLog(FontSetup.class); + /** * Sets up the font info object. * @@ -113,52 +108,52 @@ public class FontSetup { // fontInfo.addMetrics("F17", new BauerBodoniBoldItalic()); /* any is treated as serif */ - fontInfo.addFontProperties("F5", "any", "normal", Font.NORMAL); - fontInfo.addFontProperties("F6", "any", "italic", Font.NORMAL); - fontInfo.addFontProperties("F6", "any", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F7", "any", "normal", Font.BOLD); - fontInfo.addFontProperties("F8", "any", "italic", Font.BOLD); - fontInfo.addFontProperties("F8", "any", "oblique", Font.BOLD); - - fontInfo.addFontProperties("F1", "sans-serif", "normal", Font.NORMAL); - fontInfo.addFontProperties("F2", "sans-serif", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F2", "sans-serif", "italic", Font.NORMAL); - fontInfo.addFontProperties("F3", "sans-serif", "normal", Font.BOLD); - fontInfo.addFontProperties("F4", "sans-serif", "oblique", Font.BOLD); - fontInfo.addFontProperties("F4", "sans-serif", "italic", Font.BOLD); - fontInfo.addFontProperties("F5", "serif", "normal", Font.NORMAL); - fontInfo.addFontProperties("F6", "serif", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F6", "serif", "italic", Font.NORMAL); - fontInfo.addFontProperties("F7", "serif", "normal", Font.BOLD); - fontInfo.addFontProperties("F8", "serif", "oblique", Font.BOLD); - fontInfo.addFontProperties("F8", "serif", "italic", Font.BOLD); - fontInfo.addFontProperties("F9", "monospace", "normal", Font.NORMAL); - fontInfo.addFontProperties("F10", "monospace", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F10", "monospace", "italic", Font.NORMAL); - fontInfo.addFontProperties("F11", "monospace", "normal", Font.BOLD); - fontInfo.addFontProperties("F12", "monospace", "oblique", Font.BOLD); - fontInfo.addFontProperties("F12", "monospace", "italic", Font.BOLD); - - fontInfo.addFontProperties("F1", "Helvetica", "normal", Font.NORMAL); - fontInfo.addFontProperties("F2", "Helvetica", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F2", "Helvetica", "italic", Font.NORMAL); - fontInfo.addFontProperties("F3", "Helvetica", "normal", Font.BOLD); - fontInfo.addFontProperties("F4", "Helvetica", "oblique", Font.BOLD); - fontInfo.addFontProperties("F4", "Helvetica", "italic", Font.BOLD); - fontInfo.addFontProperties("F5", "Times", "normal", Font.NORMAL); - fontInfo.addFontProperties("F6", "Times", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F6", "Times", "italic", Font.NORMAL); - fontInfo.addFontProperties("F7", "Times", "normal", Font.BOLD); - fontInfo.addFontProperties("F8", "Times", "oblique", Font.BOLD); - fontInfo.addFontProperties("F8", "Times", "italic", Font.BOLD); - fontInfo.addFontProperties("F9", "Courier", "normal", Font.NORMAL); - fontInfo.addFontProperties("F10", "Courier", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F10", "Courier", "italic", Font.NORMAL); - fontInfo.addFontProperties("F11", "Courier", "normal", Font.BOLD); - fontInfo.addFontProperties("F12", "Courier", "oblique", Font.BOLD); - fontInfo.addFontProperties("F12", "Courier", "italic", Font.BOLD); - fontInfo.addFontProperties("F13", "Symbol", "normal", Font.NORMAL); - fontInfo.addFontProperties("F14", "ZapfDingbats", "normal", Font.NORMAL); + fontInfo.addFontProperties("F5", "any", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "any", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "any", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F7", "any", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "any", "italic", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "any", "oblique", Font.WEIGHT_BOLD); + + fontInfo.addFontProperties("F1", "sans-serif", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F2", "sans-serif", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F2", "sans-serif", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F3", "sans-serif", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F4", "sans-serif", "oblique", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F4", "sans-serif", "italic", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F5", "serif", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "serif", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "serif", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F7", "serif", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "serif", "oblique", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "serif", "italic", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F9", "monospace", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F10", "monospace", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F10", "monospace", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F11", "monospace", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F12", "monospace", "oblique", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F12", "monospace", "italic", Font.WEIGHT_BOLD); + + fontInfo.addFontProperties("F1", "Helvetica", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F2", "Helvetica", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F2", "Helvetica", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F3", "Helvetica", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F4", "Helvetica", "oblique", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F4", "Helvetica", "italic", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F5", "Times", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "Times", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "Times", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F7", "Times", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "Times", "oblique", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "Times", "italic", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F9", "Courier", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F10", "Courier", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F10", "Courier", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F11", "Courier", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F12", "Courier", "oblique", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F12", "Courier", "italic", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F13", "Symbol", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F14", "ZapfDingbats", "normal", Font.WEIGHT_NORMAL); // Custom type 1 fonts step 2/2 // fontInfo.addFontProperties("F15", "OMEP", "normal", FontInfo.NORMAL); @@ -166,20 +161,20 @@ public class FontSetup { // fontInfo.addFontProperties("F17", "BauerBodoni", "italic", FontInfo.BOLD); /* for compatibility with PassiveTex */ - fontInfo.addFontProperties("F5", "Times-Roman", "normal", Font.NORMAL); - fontInfo.addFontProperties("F6", "Times-Roman", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F6", "Times-Roman", "italic", Font.NORMAL); - fontInfo.addFontProperties("F7", "Times-Roman", "normal", Font.BOLD); - fontInfo.addFontProperties("F8", "Times-Roman", "oblique", Font.BOLD); - fontInfo.addFontProperties("F8", "Times-Roman", "italic", Font.BOLD); - fontInfo.addFontProperties("F5", "Times Roman", "normal", Font.NORMAL); - fontInfo.addFontProperties("F6", "Times Roman", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F6", "Times Roman", "italic", Font.NORMAL); - fontInfo.addFontProperties("F7", "Times Roman", "normal", Font.BOLD); - fontInfo.addFontProperties("F8", "Times Roman", "oblique", Font.BOLD); - fontInfo.addFontProperties("F8", "Times Roman", "italic", Font.BOLD); + fontInfo.addFontProperties("F5", "Times-Roman", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "Times-Roman", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "Times-Roman", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F7", "Times-Roman", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "Times-Roman", "oblique", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "Times-Roman", "italic", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F5", "Times Roman", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "Times Roman", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "Times Roman", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F7", "Times Roman", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "Times Roman", "oblique", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "Times Roman", "italic", Font.WEIGHT_BOLD); fontInfo.addFontProperties("F9", "Computer-Modern-Typewriter", - "normal", Font.NORMAL); + "normal", Font.WEIGHT_NORMAL); /* Add configured fonts */ addConfiguredFonts(fontInfo, embedList, 15, resolver); @@ -218,10 +213,7 @@ public class FontSetup { reader.setFontEmbedPath(configFontInfo.getEmbedFile()); fontInfo.addMetrics(internalName, reader.getFont()); */ - LazyFont font = new LazyFont(configFontInfo.getEmbedFile(), - metricsFile, - configFontInfo.getKerning(), - resolver); + LazyFont font = new LazyFont(configFontInfo, resolver); fontInfo.addMetrics(internalName, font); List triplets = configFontInfo.getFontTriplets(); @@ -237,7 +229,7 @@ public class FontSetup { } /** @return a new FontResolver to be used by the font subsystem */ - private static FontResolver createMinimalFontResolver() { + public static FontResolver createMinimalFontResolver() { return new FontResolver() { /** @see org.apache.fop.fonts.FontResolver#resolve(java.lang.String) */ @@ -245,135 +237,6 @@ public class FontSetup { //Minimal functionality here return new StreamSource(href); } - }; - } - - /** - * Builds a list of EmbedFontInfo objects for use with the setup() method. - * - * @param cfg Configuration object - * @param renderer calling Renderer object - * @return List the newly created list of fonts - * @throws ConfigurationException if something's wrong with the config data - */ - public static List buildFontListFromConfiguration(Configuration cfg, PrintRenderer renderer) - throws ConfigurationException { - List fontList = new java.util.ArrayList(); - - FontResolver fontResolver = (renderer != null ? renderer.getFontResolver() : null); - if (fontResolver == null) { - //Ensure that we have minimal font resolution capabilities - fontResolver = FontSetup.createMinimalFontResolver(); - } - - boolean strict = false; - if (renderer != null) { - strict = renderer.getUserAgent().getFactory().validateUserConfigStrictly(); - } - - Configuration[] fonts = cfg.getChildren("fonts"); - for (int f = 0; f < fonts.length; f++) { - - Configuration[] font = fonts[f].getChildren("font"); - for (int i = 0; i < font.length; i++) { - - String metricsUrl = font[i].getAttribute("metrics-url", null); - String embedUrl = font[i].getAttribute("embed-url", null); - - if (metricsUrl == null && embedUrl == null) { - if (strict) { - throw new ConfigurationException( - "Font configuration without metric-url or embed-url"); - } - log.error("Font configuration without metric-url or embed-url"); - continue; - } - - if (metricsUrl != null && fontResolver.resolve(metricsUrl) == null) { - if (strict) { - throw new ConfigurationException("Failed to resolve font metric-url '" - + metricsUrl + "'"); - } - log.error("Failed to resolve font metric-url '" + metricsUrl + "'"); - continue; - } - - if (embedUrl != null && fontResolver.resolve(embedUrl) == null) { - if (strict) { - throw new ConfigurationException("Failed to resolve font with embed-url '" - + embedUrl + "'"); - } - log.error("Failed to resolve font with embed-url '" + embedUrl + "'"); - continue; - } - - boolean useKerning = font[i].getAttributeAsBoolean("kerning", false); - - Configuration[] triple = font[i].getChildren("font-triplet"); - List tripleList = new java.util.ArrayList(); - for (int j = 0; j < triple.length; j++) { - String name = triple[j].getAttribute("name"); - if (name == null) { - if (strict) { - throw new ConfigurationException("font-triplet without name"); - } - log.error("font-triplet without name"); - continue; - } - - String weightStr = triple[j].getAttribute("weight"); - if (weightStr == null) { - if (strict) { - throw new ConfigurationException("font-triplet without weight"); - } - log.error("font-triplet without weight"); - continue; - } - int weight = FontUtil.parseCSS2FontWeight(weightStr); - - String style = triple[j].getAttribute("style"); - if (style == null) { - if (strict) { - throw new ConfigurationException("font-triplet without style"); - } - log.error("font-triplet without style"); - continue; - } - - tripleList.add(FontInfo.createFontKey(name, - style, weight)); - } - - EmbedFontInfo configFontInfo = new EmbedFontInfo(metricsUrl, - useKerning, tripleList, embedUrl); - - if (log.isDebugEnabled()) { - log.debug("Adding font " + configFontInfo.getEmbedFile() - + ", metric file " + configFontInfo.getMetricsFile()); - for (int j = 0; j < tripleList.size(); ++j) { - FontTriplet triplet = (FontTriplet) tripleList.get(j); - log.debug("Font triplet " - + triplet.getName() + ", " - + triplet.getStyle() + ", " - + triplet.getWeight()); - } - } - fontList.add(configFontInfo); - } - } - return fontList; - } - - /** - * Builds a list of EmbedFontInfo objects for use with the setup() method. - * - * @param cfg Configuration object - * @return List the newly created list of fonts - * @throws ConfigurationException if something's wrong with the config data - */ - public static List buildFontListFromConfiguration(Configuration cfg) - throws ConfigurationException { - return buildFontListFromConfiguration(cfg, null); - } + } } diff --git a/src/java/org/apache/fop/fonts/FontUtil.java b/src/java/org/apache/fop/fonts/FontUtil.java index e08ba3815..7ca2a0371 100644 --- a/src/java/org/apache/fop/fonts/FontUtil.java +++ b/src/java/org/apache/fop/fonts/FontUtil.java @@ -57,4 +57,24 @@ public class FontUtil { return weight; } + /** + * Removes all white space from a string (used primarily for font names) + * @param s the string + * @return the processed result + */ + public static String stripWhiteSpace(String s) { + StringBuffer sb = new StringBuffer(s.length()); + for (int i = 0, c = s.length(); i < c; i++) { + final char ch = s.charAt(i); + if (ch != ' ' + && ch != '\r' + && ch != '\n' + && ch != '\t') { + sb.append(ch); + } + } + return sb.toString(); + } + + } diff --git a/src/java/org/apache/fop/fonts/LazyFont.java b/src/java/org/apache/fop/fonts/LazyFont.java index 658c0cf1e..9fff44e10 100644 --- a/src/java/org/apache/fop/fonts/LazyFont.java +++ b/src/java/org/apache/fop/fonts/LazyFont.java @@ -54,14 +54,21 @@ public class LazyFont extends Typeface implements FontDescriptor { * @param useKerning True, if kerning should be enabled * @param resolver the font resolver to handle font URIs */ - public LazyFont(String fontEmbedPath, String metricsFileName - , boolean useKerning, FontResolver resolver) { - this.metricsFileName = metricsFileName; - this.fontEmbedPath = fontEmbedPath; - this.useKerning = useKerning; + public LazyFont(EmbedFontInfo fontInfo, FontResolver resolver) { + + this.metricsFileName = fontInfo.getMetricsFile(); + this.fontEmbedPath = fontInfo.getEmbedFile(); + this.useKerning = fontInfo.getKerning(); this.resolver = resolver; } + /** + * String representation of LazyFont + */ + public String toString() { + return ( "metrics-url=" + metricsFileName + ", embed-url=" + fontEmbedPath + ", kerning=" + useKerning ); + } + private void load(boolean fail) { if (!isMetricsLoaded) { try { @@ -327,6 +334,5 @@ public class LazyFont extends Typeface implements FontDescriptor { load(true); return realFontDescriptor.isEmbeddable(); } - } diff --git a/src/java/org/apache/fop/fonts/MultiByteFont.java b/src/java/org/apache/fop/fonts/MultiByteFont.java index 1b9263d17..e326140b5 100644 --- a/src/java/org/apache/fop/fonts/MultiByteFont.java +++ b/src/java/org/apache/fop/fonts/MultiByteFont.java @@ -108,28 +108,9 @@ public class MultiByteFont extends CIDFont { public void setCIDType(CIDFontType cidType) { this.cidType = cidType; } - - /** - * Removes all white space from a string (used primarily for font names) - * @param s the string - * @return the processed result - */ - public static String stripWhiteSpace(String s) { - StringBuffer sb = new StringBuffer(s.length()); - for (int i = 0, c = s.length(); i < c; i++) { - final char ch = s.charAt(i); - if (ch != ' ' - && ch != '\r' - && ch != '\n' - && ch != '\t') { - sb.append(ch); - } - } - return sb.toString(); - } private String getPrefixedFontName() { - return namePrefix + stripWhiteSpace(super.getFontName()); + return namePrefix + FontUtil.stripWhiteSpace(super.getFontName()); } /** @@ -147,7 +128,7 @@ public class MultiByteFont extends CIDFont { * @see org.apache.fop.fonts.FontDescriptor#isEmbeddable() */ public boolean isEmbeddable() { - return !(getEmbedFileName() == null && embedResourceName == null); + return !(getEmbedFileName() == null && getEmbedResourceName() == null); } /** diff --git a/src/java/org/apache/fop/fonts/apps/TTFReader.java b/src/java/org/apache/fop/fonts/apps/TTFReader.java index 93388c34f..4d5cc3942 100644 --- a/src/java/org/apache/fop/fonts/apps/TTFReader.java +++ b/src/java/org/apache/fop/fonts/apps/TTFReader.java @@ -27,6 +27,7 @@ import javax.xml.parsers.DocumentBuilderFactory; import org.apache.commons.logging.LogFactory; import org.apache.fop.Version; +import org.apache.fop.fonts.FontUtil; import org.apache.fop.fonts.truetype.FontFileReader; import org.apache.fop.fonts.truetype.TTFCmapEntry; import org.apache.fop.fonts.truetype.TTFFile; @@ -258,10 +259,10 @@ public class TTFReader extends AbstractFontReader { // "Perpetua-Bold", but the TrueType spec says that in the ttf file // it should be "Perpetua,Bold". - String s = stripWhiteSpace(ttf.getPostScriptName()); + String s = FontUtil.stripWhiteSpace(ttf.getPostScriptName()); if (fontName != null) { - el.appendChild(doc.createTextNode(stripWhiteSpace(fontName))); + el.appendChild(doc.createTextNode(FontUtil.stripWhiteSpace(fontName))); } else { el.appendChild(doc.createTextNode(s)); } @@ -450,22 +451,6 @@ public class TTFReader extends AbstractFontReader { } - private String stripWhiteSpace(String s) { - char[] ch = new char[s.length()]; - s.getChars(0, s.length(), ch, 0); - StringBuffer stb = new StringBuffer(); - for (int i = 0; i < ch.length; i++) { - if (ch[i] != ' ' - && ch[i] != '\r' - && ch[i] != '\n' - && ch[i] != '\t') { - stb.append(ch[i]); - } - } - - return stb.toString(); - } - /** * Bugzilla 40739, check that attr has a metrics-version attribute * compatible with ours. diff --git a/src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java b/src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java new file mode 100644 index 000000000..a19ab5a38 --- /dev/null +++ b/src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java @@ -0,0 +1,158 @@ +/* + * 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.autodetect; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.io.DirectoryWalker; +import org.apache.commons.io.filefilter.FileFilterUtils; +import org.apache.commons.io.filefilter.IOFileFilter; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Helps to autodetect/locate available operating system fonts. + */ +public class FontFileFinder extends DirectoryWalker implements FontFinder { + + /** logging instance */ + private final Log log = LogFactory.getLog(FontFileFinder.class); + + /** default depth limit of recursion when searching for font files **/ + public static final int DEFAULT_DEPTH_LIMIT = -1; + + /** + * Default constructor + */ + public FontFileFinder() { + super(getDirectoryFilter(), getFileFilter(), DEFAULT_DEPTH_LIMIT); + } + + /** + * Constructor + * @param depthLimit recursion depth limit + */ + public FontFileFinder(int depthLimit) { + super(getDirectoryFilter(), getFileFilter(), depthLimit); + } + + /** + * Font directory filter. Currently ignores hidden directories. + * @return IOFileFilter font directory filter + */ + protected static IOFileFilter getDirectoryFilter() { + return FileFilterUtils.andFileFilter( + FileFilterUtils.directoryFileFilter(), + FileFilterUtils.notFileFilter(FileFilterUtils.prefixFileFilter(".")) + ); + } + + /** + * Font file filter. Currently searches for files with .ttf and .pfb extensions. + * @return IOFileFilter font file filter + */ + protected static IOFileFilter getFileFilter() { + return FileFilterUtils.andFileFilter( + FileFilterUtils.fileFileFilter(), + FileFilterUtils.orFileFilter( + FileFilterUtils.suffixFileFilter(".ttf"), + FileFilterUtils.suffixFileFilter(".pfb") + ) + ); + } + + /** + * @param directory directory to handle + * @param depth recursion depth + * @param results collection + * @return whether directory should be handled + * @see org.apache.commons.io.DirectoryWalker#handleDirectory(File, int, Collection) + */ + protected boolean handleDirectory(File directory, int depth, Collection results) { + return true; + } + + /** + * @param file file to handle + * @param depth recursion depth + * @param results collection + * @see org.apache.commons.io.DirectoryWalker#handleFile(File, int, Collection) + */ + protected void handleFile(File file, int depth, Collection results) { + results.add(file); + } + + /** + * @param directory the directory being processed + * @param depth the current directory level + * @param results the colleciton of results objects + * @see org.apache.commons.io.DirectoryWalker.handleDirectoryEnd + */ + protected void handleDirectoryEnd(File directory, int depth, Collection results) { + if (log.isDebugEnabled()) { + log.debug(directory + ": found " + results.size() + " font" + + ((results.size() == 1) ? "" : "s")); + } + } + + /** + * Automagically finds a list of font files on local system + * + * @return list of font files + * @throws IOException io exception + * @see org.apache.fop.fonts.autodetect.FontFinder#find() + */ + public List find() throws IOException { + final FontFinder fontDirFinder; + final String osName = System.getProperty("os.name"); + if (osName.startsWith("Windows")) { + fontDirFinder = new WindowsFontDirFinder(); + } else { + if (osName.startsWith("Mac")) { + fontDirFinder = new MacFontDirFinder(); + } else { + fontDirFinder = new UnixFontDirFinder(); + } + } + List fontDirs = fontDirFinder.find(); + List results = new java.util.ArrayList(); + for (Iterator iter = fontDirs.iterator(); iter.hasNext();) { + super.walk((File)iter.next(), results); + } + return results; + } + + /** + * Searches a given directory for font files + * + * @param dir directory to search + * @return list of font files + * @throws IOException io exception + */ + public List find(String dir) throws IOException { + List results = new java.util.ArrayList(); + super.walk(new File(dir), results); + return results; + } +} diff --git a/src/java/org/apache/fop/fonts/autodetect/FontFinder.java b/src/java/org/apache/fop/fonts/autodetect/FontFinder.java new file mode 100644 index 000000000..2bcdc9ae2 --- /dev/null +++ b/src/java/org/apache/fop/fonts/autodetect/FontFinder.java @@ -0,0 +1,38 @@ +/* + * 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.autodetect; + +import java.io.IOException; +import java.util.List; + +/** + * Implementers provide find method for searching native operating system + * for available fonts. + */ +public interface FontFinder { + + /** + * Finds a list of font files. + * @return list of font files + * @throws IOException In case of an I/O problem + */ + List find() throws IOException; + +} diff --git a/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java b/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java new file mode 100644 index 000000000..910b5dd59 --- /dev/null +++ b/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java @@ -0,0 +1,171 @@ +/* + * 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.autodetect; + +import java.io.File; +import java.net.MalformedURLException; +import java.util.List; + +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; +import org.apache.fop.fonts.FontCache; +import org.apache.fop.fonts.FontLoader; +import org.apache.fop.fonts.FontResolver; +import org.apache.fop.fonts.FontTriplet; + +/** + * Attempts to determine correct FontInfo + */ +public class FontInfoFinder { + + /** logging instance */ + private Log log = LogFactory.getLog(FontInfoFinder.class); + + /** font constituent names which identify a font as being of "italic" style */ + private static final String[] ITALIC_WORDS = {"italic", "oblique"}; + + /** font constituent names which identify a font as being of "bold" weight */ + private static final String[] BOLD_WORDS = {"bold", "black", "heavy", "ultra", "super"}; + + /** + * Attempts to determine FontTriplet from a given CustomFont. + * It seems to be fairly accurate but will probably require some tweaking over time + * + * @param customFont CustomFont + * @return newly created font triplet + */ + private FontTriplet tripletFromFont(CustomFont customFont) { + // default style and weight triplet vales (fallback) + String name = customFont.getStrippedFontName(); + String subName = customFont.getFontSubName(); + String searchName = name.toLowerCase(); + if (subName != null) { + searchName += subName.toLowerCase(); + } + + // style + String style = Font.STYLE_NORMAL; + if (customFont.getItalicAngle() > 0) { + style = Font.STYLE_ITALIC; + } else { + for (int i = 0; i < ITALIC_WORDS.length; i++) { + if (searchName.indexOf(ITALIC_WORDS[i]) != -1) { + style = Font.STYLE_ITALIC; + break; + } + } + } + + // weight + int weight = Font.WEIGHT_NORMAL; + for (int i = 0; i < BOLD_WORDS.length; i++) { + if (searchName.indexOf(BOLD_WORDS[i]) != -1) { + weight = Font.WEIGHT_BOLD; + break; + } + } + return new FontTriplet(name, style, weight); + } + + /** + * Attempts to determine FontInfo from a given custom font + * @param fontFile the font file + * @param customFont the custom font + * @param fontCache font cache (may be null) + * @return + */ + private EmbedFontInfo fontInfoFromCustomFont( + File fontFile, CustomFont customFont, FontCache fontCache) { + FontTriplet fontTriplet = tripletFromFont(customFont); + List fontTripletList = new java.util.ArrayList(); + fontTripletList.add(fontTriplet); + String embedUrl; + try { + embedUrl = fontFile.toURL().toExternalForm(); + } catch (MalformedURLException e) { + embedUrl = fontFile.getAbsolutePath(); + } + EmbedFontInfo fontInfo = new EmbedFontInfo(null, customFont.isKerningEnabled(), + fontTripletList, embedUrl); + if (fontCache != null) { + fontCache.addFont(fontInfo); + } + return fontInfo; + } + + /** + * Attempts to determine EmbedFontInfo from a given font file. + * + * @param fontFile font file + * @param resolver font resolver used to resolve font + * @param fontCache font cache (may be null) + * @return newly created embed font info + */ + public EmbedFontInfo find(File fontFile, FontResolver resolver, FontCache fontCache) { + String embedUrl = null; + try { + embedUrl = fontFile.toURL().toExternalForm(); + } catch (MalformedURLException mfue) { + // should never happen + log.error("Failed to convert '" + fontFile + "' to URL: " + mfue.getMessage() ); + } + + long fileLastModified = -1; + if (fontCache != null) { + fileLastModified = fontFile.lastModified(); + // 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); + } + // is this a previously failed parsed font? + } else if (fontCache.isFailedFont(embedUrl, fileLastModified)) { + if (log.isDebugEnabled()) { + log.debug("Skipping font file that failed to load previously: " + embedUrl); + } + return null; + } + } + + // try to determine triplet information from font file + CustomFont customFont = null; + try { + customFont = FontLoader.loadFont(fontFile, resolver); + } catch (Exception e) { + //TODO Too verbose (it's an error but we don't care if some fonts can't be loaded) + if (log.isErrorEnabled()) { + log.error("Unable to load font file: " + embedUrl + ". Reason: " + e.getMessage()); + } + if (fontCache != null) { + fontCache.registerFailedFont(embedUrl, fileLastModified); + } + return null; + } + return fontInfoFromCustomFont(fontFile, customFont, fontCache); + } +} diff --git a/src/java/org/apache/fop/fonts/autodetect/MacFontDirFinder.java b/src/java/org/apache/fop/fonts/autodetect/MacFontDirFinder.java new file mode 100644 index 000000000..60d3fd7d3 --- /dev/null +++ b/src/java/org/apache/fop/fonts/autodetect/MacFontDirFinder.java @@ -0,0 +1,39 @@ +/* + * 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.autodetect; + +/** + * Mac font directory finder + */ +public class MacFontDirFinder extends NativeFontDirFinder { + + /** + * Some guesses at possible unix font directory locations + * @return a array of possible font directory locations + */ + protected String[] getSearchableDirectories() { + return new String[] { + System.getProperty("user.home") + "/Library/Fonts/", // user + "/Library/Fonts/", // local + "/System/Library/Fonts/", // system + "/Network/Library/Fonts/" // network + }; + } +} diff --git a/src/java/org/apache/fop/fonts/autodetect/NativeFontDirFinder.java b/src/java/org/apache/fop/fonts/autodetect/NativeFontDirFinder.java new file mode 100644 index 000000000..e9bfe9447 --- /dev/null +++ b/src/java/org/apache/fop/fonts/autodetect/NativeFontDirFinder.java @@ -0,0 +1,55 @@ +/* + * 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.autodetect; + +import java.io.File; +import java.util.List; + +/** + * Native font finder base class + */ +public abstract class NativeFontDirFinder implements FontFinder { + + /** + * Generic method used by Mac and Unix font finders. + * @return list of natively existing font directories + * @see FontFinder#find() + */ + public List find() { + List fontDirList = new java.util.ArrayList(); + String[] searchableDirectories = getSearchableDirectories(); + if (searchableDirectories != null) { + for (int i = 0; i < searchableDirectories.length; i++) { + File fontDir = new File(searchableDirectories[i]); + if (fontDir.exists() && fontDir.canRead()) { + fontDirList.add(fontDir); + } + } + } + return fontDirList; + } + + /** + * Returns an array of directories to search for fonts in. + * @return an array of directories + */ + protected abstract String[] getSearchableDirectories(); + +} diff --git a/src/java/org/apache/fop/fonts/autodetect/UnixFontDirFinder.java b/src/java/org/apache/fop/fonts/autodetect/UnixFontDirFinder.java new file mode 100644 index 000000000..0d02c6daf --- /dev/null +++ b/src/java/org/apache/fop/fonts/autodetect/UnixFontDirFinder.java @@ -0,0 +1,39 @@ +/* + * 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.autodetect; + +/** + * Unix font directory finder + */ +public class UnixFontDirFinder extends NativeFontDirFinder { + + /** + * Some guesses at possible unix font directory locations + * @return a list of possible font locations + */ + protected String[] getSearchableDirectories() { + return new String[] { + System.getProperty("user.home") + "/.fonts", // user + "/usr/local/fonts", // local + "/usr/share/fonts", // system + "/usr/X11R6/lib/X11/fonts" // X + }; + } +} diff --git a/src/java/org/apache/fop/fonts/autodetect/WindowsFontDirFinder.java b/src/java/org/apache/fop/fonts/autodetect/WindowsFontDirFinder.java new file mode 100644 index 000000000..19901dc0a --- /dev/null +++ b/src/java/org/apache/fop/fonts/autodetect/WindowsFontDirFinder.java @@ -0,0 +1,108 @@ +/* + * 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.autodetect; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; + +/** + * FontFinder for native Windows platforms + */ +public class WindowsFontDirFinder implements FontFinder { + + /** + * Attempts to read windir environment variable on windows + * (disclaimer: This is a bit dirty but seems to work nicely) + */ + private String getWinDir(String osName) throws IOException { + Process process = null; + Runtime runtime = Runtime.getRuntime(); + if (osName.startsWith("Windows 9")) { + process = runtime.exec("command.com /c echo %windir%"); + } else { + process = runtime.exec("cmd.exe /c echo %windir%"); + } + BufferedReader bufferedReader = new BufferedReader( + new InputStreamReader(process.getInputStream())); + return bufferedReader.readLine(); + } + + /** + * @see FontFinder#find() + * @return a list of detected font files + */ + public List find() { + List fontDirList = new java.util.ArrayList(); + String windir = null; + try { + windir = System.getProperty("env.windir"); + } catch (SecurityException e) { + // should continue if this fails + } + String osName = System.getProperty("os.name"); + if (windir == null) { + try { + windir = getWinDir(osName); + } catch (IOException e) { + // should continue if this fails + } + } + File osFontsDir = null, psFontsDir = null; + if (windir != null) { + // remove any trailing '/' + if (windir.endsWith("/")) { + windir = windir.substring(0, windir.length() - 1); + } + osFontsDir = new File(windir + File.separator + "FONTS"); + if (osFontsDir.exists() && osFontsDir.canRead()) { + fontDirList.add(osFontsDir); + } + psFontsDir = new File(windir.substring(0, 2) + File.separator + "PSFONTS"); + if (psFontsDir.exists() && psFontsDir.canRead()) { + fontDirList.add(psFontsDir); + } + } else { + String windowsDirName = osName.endsWith("NT") ? "WINNT" : "WINDOWS"; + // look for true type font folder + for (char driveLetter = 'C'; driveLetter <= 'E'; driveLetter++) { + osFontsDir = new File( + driveLetter + ":" + + File.separator + windowsDirName + + File.separator + "FONTS"); + if (osFontsDir.exists() && osFontsDir.canRead()) { + fontDirList.add(osFontsDir); + break; + } + } + // look for type 1 font folder + for (char driveLetter = 'C'; driveLetter <= 'E'; driveLetter++) { + psFontsDir = new File(driveLetter + ":" + File.separator + "PSFONTS"); + if (psFontsDir.exists() && psFontsDir.canRead()) { + fontDirList.add(psFontsDir); + break; + } + } + } + return fontDirList; + } +} diff --git a/src/java/org/apache/fop/fonts/autodetect/package.html b/src/java/org/apache/fop/fonts/autodetect/package.html new file mode 100644 index 000000000..0a29acbb1 --- /dev/null +++ b/src/java/org/apache/fop/fonts/autodetect/package.html @@ -0,0 +1,23 @@ +<!-- + 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: $ --> +<HTML> +<TITLE>org.apache.fop.fonts.autodetect Package</TITLE> +<BODY> +<P>A collection of classes that aid in the autodetection of installed system fonts.</P> +</BODY> +</HTML> diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFile.java b/src/java/org/apache/fop/fonts/truetype/TTFFile.java index 319a208d7..7653d8df1 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFile.java @@ -567,6 +567,14 @@ public class TTFFile { } /** + * Returns the font sub family name of the font. + * @return String The sub family name + */ + public String getSubFamilyName() { + return subFamilyName; + } + + /** * Returns the name of the character set used. * @return String The caracter set */ diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java index 81810874d..f5a0447b4 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java @@ -27,7 +27,6 @@ import java.util.Map; import org.apache.fop.fonts.BFEntry;
import org.apache.fop.fonts.CIDFontType;
-import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.FontLoader;
import org.apache.fop.fonts.FontResolver;
import org.apache.fop.fonts.MultiByteFont;
@@ -37,18 +36,23 @@ import org.apache.fop.fonts.MultiByteFont; */
public class TTFFontLoader extends FontLoader {
- private String fontFileURI;
- private TTFFile ttf;
private MultiByteFont multiFont;
- private CustomFont returnFont;
- private FontResolver resolver;
- public TTFFontLoader(String fontFileURI, InputStream in, FontResolver resolver)
- throws IOException {
- this.fontFileURI = fontFileURI;
- this.resolver = resolver;
-
- this.ttf = new TTFFile();
+ /**
+ * Default constructor
+ * @param fontFileURI the URI representing the font file
+ * @param in the InputStream to load the font from
+ * @param resolver the FontResolver for font URI resolution
+ */
+ public TTFFontLoader(String fontFileURI, InputStream in, FontResolver resolver) {
+ super(fontFileURI, in, resolver);
+ }
+
+ /**
+ * @see FontLoader#read()
+ */
+ protected void read() throws IOException {
+ TTFFile ttf = new TTFFile();
FontFileReader reader = new FontFileReader(in);
boolean supported = ttf.readFont(reader, null);
if (!supported) {
@@ -61,11 +65,9 @@ public class TTFFontLoader extends FontLoader { multiFont = new MultiByteFont();
multiFont.setResolver(this.resolver);
returnFont = multiFont;
- read();
- }
-
- private void read() throws IOException {
+
returnFont.setFontName(ttf.getFamilyName());
+ returnFont.setFontSubFamilyName(ttf.getSubFamilyName());
//multiFont.setTTCName(ttcName)
returnFont.setCapHeight(ttf.getCapHeight());
returnFont.setXHeight(ttf.getXHeight());
@@ -77,6 +79,7 @@ public class TTFFontLoader extends FontLoader { returnFont.setStemV(Integer.parseInt(ttf.getStemV())); //not used for TTF
returnFont.setItalicAngle(Integer.parseInt(ttf.getItalicAngle()));
returnFont.setMissingWidth(0);
+
multiFont.setCIDType(CIDFontType.CIDTYPE2);
int[] wx = ttf.getWidths();
multiFont.setWidthArray(wx);
@@ -93,9 +96,12 @@ public class TTFFontLoader extends FontLoader { multiFont.setBFEntries(bfentries);
copyKerning(ttf, true);
multiFont.setEmbedFileName(this.fontFileURI);
-
+ loaded = true;
}
+ /**
+ * Copy kerning information.
+ */
private void copyKerning(TTFFile ttf, boolean isCid) {
// Get kerning
@@ -115,15 +121,7 @@ public class TTFFontLoader extends FontLoader { } else {
h2 = (Map)ttf.getAnsiKerning().get(kpx1);
}
-
returnFont.putKerningEntry(kpx1, h2);
}
- }
-
-
- /** @see org.apache.fop.fonts.FontLoader#getFont() */
- public CustomFont getFont() {
- return this.returnFont;
- }
-
+ }
}
diff --git a/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java b/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java index ef0d45767..3db4a6d2d 100644 --- a/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java +++ b/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java @@ -22,7 +22,6 @@ package org.apache.fop.fonts.type1; import java.io.IOException;
import java.io.InputStream;
-import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.FontLoader;
import org.apache.fop.fonts.FontResolver;
import org.apache.fop.fonts.FontType;
@@ -33,11 +32,8 @@ import org.apache.fop.fonts.SingleByteFont; */
public class Type1FontLoader extends FontLoader {
- private String fontFileURI;
private PFMFile pfm;
private SingleByteFont singleFont;
- private CustomFont returnFont;
- private FontResolver resolver;
/**
* Constructs a new Type 1 font loader.
@@ -48,19 +44,19 @@ public class Type1FontLoader extends FontLoader { */
public Type1FontLoader(String fontFileURI, InputStream in, FontResolver resolver)
throws IOException {
- this.fontFileURI = fontFileURI;
- this.resolver = resolver;
+ super(fontFileURI, in, resolver);
+ }
+ /**
+ * @see FontLoader#read()
+ */
+ protected void read() throws IOException {
pfm = new PFMFile();
pfm.load(in);
singleFont = new SingleByteFont();
singleFont.setFontType(FontType.TYPE1);
singleFont.setResolver(this.resolver);
returnFont = singleFont;
- read();
- }
-
- private void read() throws IOException {
returnFont.setFontName(pfm.getPostscriptName());
returnFont.setCapHeight(pfm.getCapHeight());
returnFont.setXHeight(pfm.getXHeight());
@@ -77,12 +73,5 @@ public class Type1FontLoader extends FontLoader { singleFont.setWidth(i, pfm.getCharWidth(i));
}
singleFont.setEmbedFileName(this.fontFileURI);
-
- }
-
- /** @see org.apache.fop.fonts.FontLoader#getFont() */
- public CustomFont getFont() {
- return this.returnFont;
}
-
}
diff --git a/src/java/org/apache/fop/pdf/PDFFilterList.java b/src/java/org/apache/fop/pdf/PDFFilterList.java index 3ab0b8419..e0ee7eb4b 100644 --- a/src/java/org/apache/fop/pdf/PDFFilterList.java +++ b/src/java/org/apache/fop/pdf/PDFFilterList.java @@ -24,14 +24,6 @@ import java.io.OutputStream; import java.util.List; import java.util.Map; -// commons logging -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -// Avalon -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; - /** * This class represents a list of PDF filters to be applied when serializing * the output of a PDF object. @@ -56,12 +48,7 @@ public class PDFFilterList { private List filters = new java.util.ArrayList(); private boolean ignoreASCIIFilters = false; - - /** - * logging instance - */ - protected static Log logger = LogFactory.getLog("org.apache.fop.render"); - + /** * Default constructor. * <p> @@ -290,53 +277,4 @@ public class PDFFilterList { } return out; } - - /** - * Builds a filter map from an Avalon Configuration object. - * @param cfg the Configuration object - * @return Map the newly built filter map - * @throws ConfigurationException if a filter list is defined twice - */ - public static Map buildFilterMapFromConfiguration(Configuration cfg) - throws ConfigurationException { - Map filterMap = new java.util.HashMap(); - Configuration[] filterLists = cfg.getChildren("filterList"); - for (int i = 0; i < filterLists.length; i++) { - Configuration filters = filterLists[i]; - String type = filters.getAttribute("type", null); - Configuration[] filt = filters.getChildren("value"); - List filterList = new java.util.ArrayList(); - for (int j = 0; j < filt.length; j++) { - String name = filt[j].getValue(); - filterList.add(name); - } - - if (type == null) { - type = PDFFilterList.DEFAULT_FILTER; - } - - if (!filterList.isEmpty() && logger.isDebugEnabled()) { - StringBuffer debug = new StringBuffer("Adding PDF filter"); - if (filterList.size() != 1) { - debug.append("s"); - } - debug.append(" for type ").append(type).append(": "); - for (int j = 0; j < filterList.size(); j++) { - if (j != 0) { - debug.append(", "); - } - debug.append(filterList.get(j)); - } - logger.debug(debug.toString()); - } - - if (filterMap.get(type) != null) { - throw new ConfigurationException("A filterList of type '" - + type + "' has already been defined"); - } - filterMap.put(type, filterList); - } - return filterMap; - } - } diff --git a/src/java/org/apache/fop/render/AbstractRenderer.java b/src/java/org/apache/fop/render/AbstractRenderer.java index 50c314f15..e2d314885 100644 --- a/src/java/org/apache/fop/render/AbstractRenderer.java +++ b/src/java/org/apache/fop/render/AbstractRenderer.java @@ -69,18 +69,13 @@ import org.apache.fop.fonts.FontInfo; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -// Avalon -import org.apache.avalon.framework.configuration.Configurable; -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; - /** * Abstract base class for all renderers. The Abstract renderer does all the * top level processing of the area tree and adds some abstract methods to * handle viewports. This keeps track of the current block and inline position. */ public abstract class AbstractRenderer - implements Renderer, Configurable, Constants { + implements Renderer, Constants { /** logging instance */ protected static Log log = LogFactory.getLog("org.apache.fop.render"); @@ -118,12 +113,6 @@ public abstract class AbstractRenderer private Set warnedXMLHandlers; /** - * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration) - */ - public void configure(Configuration conf) throws ConfigurationException { - } - - /** * @see org.apache.fop.render.Renderer#setupFontInfo(FontInfo) */ public abstract void setupFontInfo(FontInfo fontInfo); @@ -805,39 +794,6 @@ public abstract class AbstractRenderer } /** - * Returns the configuration subtree for a specific renderer. - * @param cfg the renderer configuration - * @param namespace the namespace (i.e. the XMLHandler) for which the configuration should - * be returned - * @return the requested configuration subtree, null if there's no configuration - */ - public static Configuration getHandlerConfig(Configuration cfg, String namespace) { - - if (cfg == null || namespace == null) { - return null; - } - - Configuration handlerConfig = null; - - Configuration[] children = cfg.getChildren("xml-handler"); - for (int i = 0; i < children.length; ++i) { - try { - if (children[i].getAttribute("namespace").equals(namespace)) { - handlerConfig = children[i]; - break; - } - } catch (ConfigurationException e) { - // silently pass over configurations without namespace - } - } - if (log.isDebugEnabled()) { - log.debug((handlerConfig == null ? "No" : "") - + "XML handler configuration found for namespace " + namespace); - } - return handlerConfig; - } - - /** * Render the xml document with the given xml namespace. * The Render Context is by the handle to render into the current * rendering target. @@ -851,15 +807,9 @@ public abstract class AbstractRenderer this, namespace); if (handler != null) { try { - //Optional XML handler configuration - Configuration cfg = userAgent.getFactory().getUserRendererConfig(getMimeType()); - if (cfg != null) { - cfg = getHandlerConfig(cfg, namespace); - if (cfg != null) { - ctx.setProperty(RendererContextConstants.HANDLER_CONFIGURATION, cfg); - } - } - + XMLHandlerConfigurator configurator + = new XMLHandlerConfigurator(userAgent); + configurator.configure(ctx, namespace); handler.handleXML(ctx, doc, namespace); } catch (Throwable t) { // could not handle document @@ -887,6 +837,4 @@ public abstract class AbstractRenderer public String getMimeType() { return null; } - } - diff --git a/src/java/org/apache/fop/render/AbstractRendererConfigurator.java b/src/java/org/apache/fop/render/AbstractRendererConfigurator.java new file mode 100644 index 000000000..1e485735b --- /dev/null +++ b/src/java/org/apache/fop/render/AbstractRendererConfigurator.java @@ -0,0 +1,91 @@ +/* + * 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.render; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.apps.FOUserAgent; + +/** + * Abstract base classes for renderer-related configurator classes. This class basically just + * provides an accessor to the specific renderer configuration object. + */ +public abstract class AbstractRendererConfigurator { + + /** logger instance */ + protected static Log log = LogFactory.getLog(AbstractRendererConfigurator.class); + + /** fop factory configuration */ + protected FOUserAgent userAgent = null; + + /** + * Default constructor + * @param userAgent user agent + */ + public AbstractRendererConfigurator(FOUserAgent userAgent) { + super(); + this.userAgent = userAgent; + } + + + /** + * Returns the configuration subtree for a specific renderer. + * @param renderer the renderer + * @return the requested configuration subtree, null if there's no configuration + */ + protected Configuration getRendererConfig(Renderer renderer) { + Configuration cfg = userAgent.getFactory().getUserConfig(); + if (cfg == null) { + if (log.isDebugEnabled()) { + log.debug("userconfig is null"); + } + return null; + } + + String mimeType = renderer.getMimeType(); + if (mimeType == null) { + if (log.isInfoEnabled()) { + log.info("renderer mimeType is null"); + } + return null; + } + + Configuration userRendererConfig = null; + + Configuration[] cfgs + = cfg.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; + } +} diff --git a/src/java/org/apache/fop/render/AbstractRendererMaker.java b/src/java/org/apache/fop/render/AbstractRendererMaker.java index 0c6bea631..ab1ddb338 100644 --- a/src/java/org/apache/fop/render/AbstractRendererMaker.java +++ b/src/java/org/apache/fop/render/AbstractRendererMaker.java @@ -29,10 +29,10 @@ public abstract class AbstractRendererMaker { /**
* Instantiates a new renderer.
- * @param ua the user agent
+ * @param userAgent the user agent
* @return the newly instantiated renderer
*/
- public abstract Renderer makeRenderer(FOUserAgent ua);
+ public abstract Renderer makeRenderer(FOUserAgent userAgent);
/**
* @return Indicates whether this renderer requires an OutputStream to work with.
@@ -45,6 +45,16 @@ public abstract class AbstractRendererMaker { public abstract String[] getSupportedMimeTypes();
/**
+ * Returns a renderer config object that can be used to
+ * configure the renderer.
+ * @param userAgent user agent
+ * @return a config object that can be used to configure the renderer
+ */
+ public RendererConfigurator getConfigurator(FOUserAgent userAgent) {
+ return null;
+ }
+
+ /**
* Indicates whether a specific MIME type is supported by this renderer.
* @param mimeType the MIME type (ex. "application/pdf")
* @return true if the MIME type is supported
@@ -58,5 +68,4 @@ public abstract class AbstractRendererMaker { }
return false;
}
-
}
diff --git a/src/java/org/apache/fop/render/PrintRenderer.java b/src/java/org/apache/fop/render/PrintRenderer.java index 6a3cdf2c6..f725bd711 100644 --- a/src/java/org/apache/fop/render/PrintRenderer.java +++ b/src/java/org/apache/fop/render/PrintRenderer.java @@ -46,8 +46,27 @@ public abstract class PrintRenderer extends AbstractRenderer { /** list of fonts */ protected List fontList = null; + + /** + * adds a font list to current list of fonts + * @param fontInfoList font list + */ + public void addFontList(List fontInfoList) { + if (this.fontList == null) { + setFontList(fontInfoList); + } else { + this.fontList.addAll(fontInfoList); + } + } /** + * @param fontList list of available fonts + */ + public void setFontList(List fontList) { + this.fontList = fontList; + } + + /** * Set up the font info * * @param inFontInfo font info to set up diff --git a/src/java/org/apache/fop/render/PrintRendererConfigurator.java b/src/java/org/apache/fop/render/PrintRendererConfigurator.java new file mode 100644 index 000000000..d9b922965 --- /dev/null +++ b/src/java/org/apache/fop/render/PrintRendererConfigurator.java @@ -0,0 +1,332 @@ +/* + * 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.render; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Iterator; +import java.util.List; + +import javax.xml.transform.stream.StreamSource; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.commons.io.FileUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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; +import org.apache.fop.fonts.FontResolver; +import org.apache.fop.fonts.FontSetup; +import org.apache.fop.fonts.FontTriplet; +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; + +/** + * Base Print renderer configurator (mostly handles font configuration) + */ +public class PrintRendererConfigurator extends AbstractRendererConfigurator + implements RendererConfigurator { + + /** have we already autodetected system fonts? */ + private static boolean autodetectedFonts = false; + + /** logger instance */ + protected static Log log = LogFactory.getLog(PrintRendererConfigurator.class); + + /** + * Default constructor + * @param userAgent user agent + */ + public PrintRendererConfigurator(FOUserAgent userAgent) { + super(userAgent); + } + + /** + * Builds a list of EmbedFontInfo objects for use with the setup() method. + * + * @param renderer print renderer + * @throws FOPException if something's wrong with the config data + */ + public void configure(Renderer renderer) throws FOPException { + Configuration cfg = getRendererConfig(renderer); + if (cfg == null) { + return; + } + + PrintRenderer printRenderer = (PrintRenderer)renderer; + FontResolver fontResolver = printRenderer.getFontResolver(); + if (fontResolver == null) { + //Ensure that we have minimal font resolution capabilities + fontResolver = FontSetup.createMinimalFontResolver(); + } + + FopFactory factory = userAgent.getFactory(); + boolean strict = factory.validateUserConfigStrictly(); + FontCache fontCache = factory.getFontCache(); + + List fontInfoList = buildFontListFromConfiguration(cfg, + userAgent.getFontBaseURL(), fontResolver, strict, + fontCache); + + if (fontCache != null && fontCache.hasChanged()) { + fontCache.save(); + } + printRenderer.addFontList(fontInfoList); + } + + /** + * Builds a list of EmbedFontInfo objects for use with the setup() method. + * + * @param cfg Configuration object + * @param fontBaseURL the base URL to resolve relative font URLs with + * @param fontResolver the FontResolver to use + * @param strict true if an Exception should be thrown if an error is found. + * @param fontCache the font cache (or null if it is disabled) + * @return a List of EmbedFontInfo objects. + * @throws FOPException If an error occurs while processing the configuration + */ + public static List buildFontListFromConfiguration(Configuration cfg, + String fontBaseURL, FontResolver fontResolver, + boolean strict, FontCache fontCache) throws FOPException { + List fontInfoList = new java.util.ArrayList(); + + Configuration fonts = cfg.getChild("fonts"); + if (fonts != null) { + long start = 0; + if (log.isDebugEnabled()) { + log.debug("Starting font configuration..."); + start = System.currentTimeMillis(); + } + + // native o/s search (autodetect) configuration + boolean autodetectFonts = (fonts.getChild("auto-detect", false) != null); + if (!autodetectedFonts && autodetectFonts) { + // search in font base if it is defined and + // is a directory but don't recurse + FontFileFinder fontFileFinder = new FontFileFinder(); + if (fontBaseURL != null) { + try { + File fontBase = FileUtils.toFile(new URL(fontBaseURL)); + if (fontBase != null) { + //Can only use the font base URL if it's a file URL + addFontInfoListFromFileList( + fontFileFinder.find(fontBase.getAbsolutePath()), + fontInfoList, + fontResolver, + fontCache + ); + } + } catch (IOException e) { + LogUtil.handleException(log, e, strict); + } + } + + // native o/s font directory finder + try { + addFontInfoListFromFileList( + fontFileFinder.find(), + fontInfoList, + fontResolver, + fontCache + ); + } catch (IOException e) { + LogUtil.handleException(log, e, strict); + } + autodetectedFonts = true; + } + + // directory (multiple font) configuration + Configuration[] directories = fonts.getChildren("directory"); + for (int i = 0; i < directories.length; i++) { + boolean recursive = directories[i].getAttributeAsBoolean("recursive", false); + String directory = null; + try { + directory = directories[i].getValue(); + } catch (ConfigurationException e) { + LogUtil.handleException(log, e, strict); + continue; + } + if (directory == null) { + LogUtil.handleException(log, + new FOPException("directory defined without value"), strict); + continue; + } + FontFileFinder fontFileFinder = new FontFileFinder(recursive ? -1 : 1); + try { + addFontInfoListFromFileList( + fontFileFinder.find(directory), + fontInfoList, + fontResolver, + fontCache + ); + } catch (IOException e) { + LogUtil.handleException(log, e, strict); + } + } + + // font file (singular) configuration + Configuration[] font = fonts.getChildren("font"); + for (int i = 0; i < font.length; i++) { + EmbedFontInfo fontInfo = getFontInfoFromConfiguration( + font[i], fontResolver, strict, fontCache); + if (fontInfo != null) { + fontInfoList.add(fontInfo); + } + } + if (log.isDebugEnabled()) { + log.debug("Finished font configuration in " + + (System.currentTimeMillis() - start) + "ms"); + } + } + return fontInfoList; + } + + /** + * Iterates over font file list adding font info to list + * @param fontFileList font file list + * @param fontInfoList font info list + * @param resolver font resolver + */ + private static void addFontInfoListFromFileList( + List fontFileList, List fontInfoList, FontResolver resolver, FontCache fontCache) { + for (Iterator iter = fontFileList.iterator(); iter.hasNext();) { + File fontFile = (File)iter.next(); + // parse font to ascertain font info + FontInfoFinder finder = new FontInfoFinder(); + EmbedFontInfo fontInfo = finder.find(fontFile, resolver, fontCache); + if (fontInfo != null) { + fontInfoList.add(fontInfo); + } + } + } + + /** + * Returns a font info from a font node Configuration definition + * + * @param fontCfg Configuration object (font node) + * @param fontResolver font resolver used to resolve font + * @param strict validate configuration strictly + * @param fontCache the font cache (or null if it is disabled) + * @return font info + * @throws FOPException if something's wrong with the config data + */ + public static EmbedFontInfo getFontInfoFromConfiguration( + Configuration fontCfg, FontResolver fontResolver, boolean strict, FontCache fontCache) + throws FOPException { + String metricsUrl = fontCfg.getAttribute("metrics-url", null); + String embedUrl = fontCfg.getAttribute("embed-url", null); + + if (metricsUrl == null && embedUrl == null) { + LogUtil.handleError(log, "Font configuration without metric-url or embed-url", strict); + return null; + } + if (embedUrl != null) { + StreamSource source = (StreamSource)fontResolver.resolve(embedUrl); + if (source == null) { + LogUtil.handleError(log, + "Failed to resolve font with embed-url '" + embedUrl + "'", strict); + return null; + } + embedUrl = source.getSystemId(); // absolute path/url + } + if (metricsUrl != null) { + StreamSource source = (StreamSource)fontResolver.resolve(metricsUrl); + if (source == null) { + LogUtil.handleError(log, + "Failed to resolve font with metric-url '" + metricsUrl + "'", strict); + return null; + } + metricsUrl = source.getSystemId(); // absolute path/url + } + boolean useKerning = fontCfg.getAttributeAsBoolean("kerning", true); + + EmbedFontInfo fontInfo = null; + Configuration[] tripletCfg = fontCfg.getChildren("font-triplet"); + // no font triplet info + if (tripletCfg.length == 0) { + 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}); + if (fontFile != null) { + FontInfoFinder finder = new FontInfoFinder(); + return finder.find(fontFile, fontResolver, fontCache); + } else { + return null; + } + } else { + List tripleList = new java.util.ArrayList(); + for (int j = 0; j < tripletCfg.length; j++) { + try { + String name = tripletCfg[j].getAttribute("name"); + if (name == null) { + LogUtil.handleError(log, "font-triplet without name", strict); + continue; + } + String weightStr = tripletCfg[j].getAttribute("weight"); + if (weightStr == null) { + LogUtil.handleError(log, "font-triplet without weight", strict); + continue; + } + int weight = FontUtil.parseCSS2FontWeight(weightStr); + String style = tripletCfg[j].getAttribute("style"); + if (style == null) { + LogUtil.handleError(log, "font-triplet without style", strict); + continue; + } + tripleList.add(FontInfo.createFontKey(name, style, weight)); + } catch (ConfigurationException e) { + LogUtil.handleException(log, e, strict); + } + } + + fontInfo = new EmbedFontInfo(metricsUrl, useKerning, tripleList, embedUrl); + + if (fontCache != null) { + if (!fontCache.containsFont(fontInfo)) { + fontCache.addFont(fontInfo); + } + } + + if (log.isDebugEnabled()) { + log.debug("Adding font " + fontInfo.getEmbedFile() + + ", metric file " + fontInfo.getMetricsFile()); + for (int j = 0; j < tripleList.size(); ++j) { + FontTriplet triplet = (FontTriplet) tripleList.get(j); + log.debug(" Font triplet " + + triplet.getName() + ", " + + triplet.getStyle() + ", " + + triplet.getWeight()); + } + } + } + return fontInfo; + } + +} diff --git a/src/java/org/apache/fop/render/RendererConfigurator.java b/src/java/org/apache/fop/render/RendererConfigurator.java new file mode 100644 index 000000000..566daf07d --- /dev/null +++ b/src/java/org/apache/fop/render/RendererConfigurator.java @@ -0,0 +1,34 @@ +/* + * 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.render; + +import org.apache.fop.apps.FOPException; + +/** + * Renderer configurator interface + */ +public interface RendererConfigurator { + /** + * Configures a renderer + * @param renderer renderer + * @throws FOPException fop exception + */ + void configure(Renderer renderer) throws FOPException; +} diff --git a/src/java/org/apache/fop/render/RendererContext.java b/src/java/org/apache/fop/render/RendererContext.java index 49f53b327..feffc05ed 100644 --- a/src/java/org/apache/fop/render/RendererContext.java +++ b/src/java/org/apache/fop/render/RendererContext.java @@ -23,7 +23,6 @@ package org.apache.fop.render; import java.util.Map; //FOP -import org.apache.avalon.framework.configuration.Configuration; import org.apache.fop.apps.FOUserAgent; /** @@ -156,17 +155,10 @@ public class RendererContext { return ((Integer)context.getProperty(RendererContextConstants.HEIGHT)).intValue(); } - /** @return the handler configuration */ - public Configuration getHandlerConfiguration() { - return (Configuration)context.getProperty( - RendererContextConstants.HANDLER_CONFIGURATION); - } - /** @return the foreign attributes */ public Map getForeignAttributes() { return (Map)context.getProperty(RendererContextConstants.FOREIGN_ATTRIBUTES); - } - + } } } diff --git a/src/java/org/apache/fop/render/RendererFactory.java b/src/java/org/apache/fop/render/RendererFactory.java index 4d3f3a12c..d81f900e0 100644 --- a/src/java/org/apache/fop/render/RendererFactory.java +++ b/src/java/org/apache/fop/render/RendererFactory.java @@ -25,9 +25,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; -import org.apache.avalon.framework.container.ContainerUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -185,18 +182,9 @@ public class RendererFactory { } Renderer rend = maker.makeRenderer(userAgent); rend.setUserAgent(userAgent); - String mimeType = rend.getMimeType(); //Always use main MIME type for this - Configuration userRendererConfig = null; - if (mimeType != null) { - userRendererConfig - = userAgent.getFactory().getUserRendererConfig(mimeType); - } - if (userRendererConfig != null) { - try { - ContainerUtil.configure(rend, userRendererConfig); - } catch (ConfigurationException e) { - throw new FOPException(e); - } + RendererConfigurator configurator = maker.getConfigurator(userAgent); + if (configurator != null) { + configurator.configure(rend); } return rend; } diff --git a/src/java/org/apache/fop/render/XMLHandlerConfigurator.java b/src/java/org/apache/fop/render/XMLHandlerConfigurator.java new file mode 100644 index 000000000..bf63329d7 --- /dev/null +++ b/src/java/org/apache/fop/render/XMLHandlerConfigurator.java @@ -0,0 +1,92 @@ +/* + * 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.render; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; + +/** + * Configurator for XMLHandler objects. + */ +public class XMLHandlerConfigurator extends AbstractRendererConfigurator { + + /** logger instance */ + protected static Log log = LogFactory.getLog(XMLHandlerConfigurator.class); + + /** + * Default constructor + * @param userAgent the user agent + */ + public XMLHandlerConfigurator(FOUserAgent userAgent) { + super(userAgent); + } + + /** + * Returns the configuration subtree for a specific renderer. + * @param cfg the renderer configuration + * @param namespace the namespace (i.e. the XMLHandler) for which the configuration should + * be returned + * @return the requested configuration subtree, null if there's no configuration + */ + private Configuration getHandlerConfig(Configuration cfg, String namespace) { + if (cfg == null || namespace == null) { + return null; + } + Configuration handlerConfig = null; + + Configuration[] children = cfg.getChildren("xml-handler"); + for (int i = 0; i < children.length; ++i) { + try { + if (children[i].getAttribute("namespace").equals(namespace)) { + handlerConfig = children[i]; + break; + } + } catch (ConfigurationException e) { + // silently pass over configurations without namespace + } + } + if (log.isDebugEnabled()) { + log.debug((handlerConfig == null ? "No" : "") + + "XML handler configuration found for namespace " + namespace); + } + return handlerConfig; + } + + /** + * Configures renderer context by setting the handler configuration on it. + * @param context the RendererContext (contains the user agent) + * @param ns the Namespace of the foreign object + * @throws FOPException if configuring the target objects fails + */ + public void configure(RendererContext context, String ns) throws FOPException { + //Optional XML handler configuration + Configuration cfg = getRendererConfig(context.getRenderer()); + if (cfg != null) { + cfg = getHandlerConfig(cfg, ns); + if (cfg != null) { + context.setProperty(RendererContextConstants.HANDLER_CONFIGURATION, cfg); + } + } + } +} diff --git a/src/java/org/apache/fop/render/afp/AFPRenderer.java b/src/java/org/apache/fop/render/afp/AFPRenderer.java index 78d8b7d0a..ea1087893 100644 --- a/src/java/org/apache/fop/render/afp/AFPRenderer.java +++ b/src/java/org/apache/fop/render/afp/AFPRenderer.java @@ -33,8 +33,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; @@ -57,8 +55,6 @@ import org.apache.fop.fo.extensions.ExtensionAttachment; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontMetrics; import org.apache.fop.fonts.FontTriplet; -import org.apache.fop.fonts.FontUtil; -import org.apache.fop.fonts.Typeface; import org.apache.fop.fonts.base14.Courier; import org.apache.fop.fonts.base14.Helvetica; import org.apache.fop.fonts.base14.TimesRoman; @@ -76,7 +72,6 @@ import org.apache.fop.render.afp.fonts.AFPFont; import org.apache.fop.render.afp.fonts.CharacterSet; import org.apache.fop.render.afp.fonts.FopCharacterSet; import org.apache.fop.render.afp.fonts.OutlineFont; -import org.apache.fop.render.afp.fonts.RasterFont; import org.apache.fop.render.afp.modca.AFPConstants; import org.apache.fop.render.afp.modca.AFPDataStream; import org.apache.fop.render.afp.modca.ImageObject; @@ -303,195 +298,6 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { } /** - */ - private AFPFontInfo buildFont(Configuration fontCfg, String _path) - throws ConfigurationException { - - Configuration[] triple = fontCfg.getChildren("font-triplet"); - List tripleList = new java.util.ArrayList(); - if (triple.length == 0) { - log.error("Mandatory font configuration element '<font-triplet...' is missing"); - return null; - } - for (int j = 0; j < triple.length; j++) { - int weight = FontUtil.parseCSS2FontWeight(triple[j].getAttribute("weight")); - tripleList.add(new FontTriplet(triple[j].getAttribute("name"), - triple[j].getAttribute("style"), - weight)); - } - - //build the fonts - Configuration afpFontCfg = fontCfg.getChild("afp-font"); - if (afpFontCfg == null) { - log.error("Mandatory font configuration element '<afp-font...' is missing"); - return null; - } - String path = afpFontCfg.getAttribute("path", _path); - String type = afpFontCfg.getAttribute("type"); - if (type == null) { - log.error("Mandatory afp-font configuration attribute 'type=' is missing"); - return null; - } - String codepage = afpFontCfg.getAttribute("codepage"); - if (codepage == null) { - log.error("Mandatory afp-font configuration attribute 'code=' is missing"); - return null; - } - String encoding = afpFontCfg.getAttribute("encoding"); - if (encoding == null) { - log.error("Mandatory afp-font configuration attribute 'encoding=' is missing"); - return null; - } - - if ("raster".equalsIgnoreCase(type)) { - - String name = afpFontCfg.getAttribute("name", "Unknown"); - - // Create a new font object - RasterFont font = new RasterFont(name); - - Configuration[] rasters = afpFontCfg.getChildren("afp-raster-font"); - if (rasters.length == 0) { - log.error("Mandatory font configuration elements '<afp-raster-font...' are missing"); - return null; - } - for (int j = 0; j < rasters.length; j++) { - Configuration rasterCfg = rasters[j]; - - String characterset = rasterCfg.getAttribute("characterset"); - if (characterset == null) { - log.error("Mandatory afp-raster-font configuration attribute 'characterset=' is missing"); - return null; - } - int size = rasterCfg.getAttributeAsInteger("size"); - String base14 = rasterCfg.getAttribute("base14-font", null); - - if (base14 != null) { - try { - Class clazz = Class.forName("org.apache.fop.fonts.base14." - + base14); - try { - Typeface tf = (Typeface)clazz.newInstance(); - font.addCharacterSet(size, new FopCharacterSet( - codepage, encoding, characterset, size, tf)); - } catch (Exception ie) { - String msg = "The base 14 font class " + clazz.getName() - + " could not be instantiated"; - log.error(msg); - } - } catch (ClassNotFoundException cnfe) { - String msg = "The base 14 font class for " + characterset - + " could not be found"; - log.error(msg); - } - } else { - font.addCharacterSet(size, new CharacterSet( - codepage, encoding, characterset, path)); - } - } - return new AFPFontInfo(font, tripleList); - - } else if ("outline".equalsIgnoreCase(type)) { - - String characterset = afpFontCfg.getAttribute("characterset"); - if (characterset == null) { - log.error("Mandatory afp-font configuration attribute 'characterset=' is missing"); - return null; - } - String name = afpFontCfg.getAttribute("name", characterset); - - CharacterSet characterSet = null; - - String base14 = afpFontCfg.getAttribute("base14-font", null); - - if (base14 != null) { - try { - Class clazz = Class.forName("org.apache.fop.fonts.base14." - + base14); - try { - Typeface tf = (Typeface)clazz.newInstance(); - characterSet = new FopCharacterSet( - codepage, encoding, characterset, 1, tf); - } catch (Exception ie) { - String msg = "The base 14 font class " + clazz.getName() - + " could not be instantiated"; - log.error(msg); - } - } catch (ClassNotFoundException cnfe) { - String msg = "The base 14 font class for " + characterset - + " could not be found"; - log.error(msg); - } - } else { - characterSet = new CharacterSet(codepage, encoding, characterset, path); - } - // Create a new font object - OutlineFont font = new OutlineFont(name, characterSet); - return new AFPFontInfo(font, tripleList); - } else { - log.error("No or incorrect type attribute"); - } - return null; - } - - /** - * Builds a list of AFPFontInfo objects for use with the setup() method. - * @param cfg Configuration object - * @return List the newly created list of fonts - * @throws ConfigurationException if something's wrong with the config data - */ - public List buildFontListFromConfiguration(Configuration cfg) - throws ConfigurationException { - List fontList = new java.util.ArrayList(); - Configuration[] font = cfg.getChild("fonts").getChildren("font"); - for (int i = 0; i < font.length; i++) { - AFPFontInfo afi = buildFont(font[i], null); - if (afi != null) { - if (log.isDebugEnabled()) { - log.debug("Adding font " + afi.getAFPFont().getFontName()); - for (int j = 0; j < afi.getFontTriplets().size(); ++j) { - FontTriplet triplet = (FontTriplet) afi.getFontTriplets().get(j); - log.debug("Font triplet " - + triplet.getName() + ", " - + triplet.getStyle() + ", " - + triplet.getWeight()); - } - } - - fontList.add(afi); - } - } - return fontList; - } - - /** - * Configure the AFP renderer. - * Get the configuration to be used for fonts etc. - * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration) - */ - public void configure(Configuration cfg) throws ConfigurationException { - //Font configuration - this.fontList = buildFontListFromConfiguration(cfg); - Configuration images = cfg.getChild("images"); - if (!"color".equalsIgnoreCase(images.getAttribute("mode", "b+w"))) { - bitsPerPixel = images.getAttributeAsInteger("bits-per-pixel", 8); - switch (bitsPerPixel) { - case 1: - case 4: - case 8: - break; - default: - log.warn("Invalid bits_per_pixel value, must be 1, 4 or 8."); - bitsPerPixel = 8; - break; - } - } else { - colorImages = true; - } - - } - - /** * @see org.apache.fop.render.Renderer#setUserAgent(FOUserAgent) */ public void setUserAgent(FOUserAgent agent) { @@ -1765,5 +1571,22 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { } } + public void setBitsPerPixel(int bitsPerPixel) { + this.bitsPerPixel = bitsPerPixel; + switch (bitsPerPixel) { + case 1: + case 4: + case 8: + break; + default: + log.warn("Invalid bits_per_pixel value, must be 1, 4 or 8."); + bitsPerPixel = 8; + break; + } + } + + public void setColorImages(boolean colorImages) { + this.colorImages = colorImages; + } } diff --git a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java new file mode 100644 index 000000000..aebabd97b --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.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.render.afp; + +import java.util.List; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.fonts.FontTriplet; +import org.apache.fop.fonts.FontUtil; +import org.apache.fop.fonts.Typeface; +import org.apache.fop.render.PrintRendererConfigurator; +import org.apache.fop.render.Renderer; +import org.apache.fop.render.afp.fonts.AFPFontInfo; +import org.apache.fop.render.afp.fonts.CharacterSet; +import org.apache.fop.render.afp.fonts.FopCharacterSet; +import org.apache.fop.render.afp.fonts.OutlineFont; +import org.apache.fop.render.afp.fonts.RasterFont; +import org.apache.fop.util.LogUtil; + +/** + * AFP Renderer configurator + */ +public class AFPRendererConfigurator extends PrintRendererConfigurator { + + /** + * Default constructor + * @param userAgent user agent + */ + public AFPRendererConfigurator(FOUserAgent userAgent) { + super(userAgent); + } + + private AFPFontInfo buildFont(Configuration fontCfg, String fontPath) + throws ConfigurationException { + + Configuration[] triple = fontCfg.getChildren("font-triplet"); + List tripleList = new java.util.ArrayList(); + if (triple.length == 0) { + log.error("Mandatory font configuration element '<font-triplet...' is missing"); + return null; + } + for (int j = 0; j < triple.length; j++) { + int weight = FontUtil.parseCSS2FontWeight(triple[j].getAttribute("weight")); + tripleList.add(new FontTriplet(triple[j].getAttribute("name"), + triple[j].getAttribute("style"), + weight)); + } + + //build the fonts + Configuration afpFontCfg = fontCfg.getChild("afp-font"); + if (afpFontCfg == null) { + log.error("Mandatory font configuration element '<afp-font...' is missing"); + return null; + } + String path = afpFontCfg.getAttribute("path", fontPath); + String type = afpFontCfg.getAttribute("type"); + if (type == null) { + log.error("Mandatory afp-font configuration attribute 'type=' is missing"); + return null; + } + String codepage = afpFontCfg.getAttribute("codepage"); + if (codepage == null) { + log.error("Mandatory afp-font configuration attribute 'code=' is missing"); + return null; + } + String encoding = afpFontCfg.getAttribute("encoding"); + if (encoding == null) { + log.error("Mandatory afp-font configuration attribute 'encoding=' is missing"); + return null; + } + + if ("raster".equalsIgnoreCase(type)) { + + String name = afpFontCfg.getAttribute("name", "Unknown"); + + // Create a new font object + RasterFont font = new RasterFont(name); + + Configuration[] rasters = afpFontCfg.getChildren("afp-raster-font"); + if (rasters.length == 0) { + log.error( + "Mandatory font configuration elements '<afp-raster-font...' are missing"); + return null; + } + for (int j = 0; j < rasters.length; j++) { + Configuration rasterCfg = rasters[j]; + + String characterset = rasterCfg.getAttribute("characterset"); + if (characterset == null) { + log.error( + "Mandatory afp-raster-font configuration attribute 'characterset=' is missing"); + return null; + } + int size = rasterCfg.getAttributeAsInteger("size"); + String base14 = rasterCfg.getAttribute("base14-font", null); + + if (base14 != null) { + try { + Class clazz = Class.forName("org.apache.fop.fonts.base14." + + base14); + try { + Typeface tf = (Typeface)clazz.newInstance(); + font.addCharacterSet(size, new FopCharacterSet( + codepage, encoding, characterset, size, tf)); + } catch (Exception ie) { + String msg = "The base 14 font class " + clazz.getName() + + " could not be instantiated"; + log.error(msg); + } + } catch (ClassNotFoundException cnfe) { + String msg = "The base 14 font class for " + characterset + + " could not be found"; + log.error(msg); + } + } else { + font.addCharacterSet(size, new CharacterSet( + codepage, encoding, characterset, path)); + } + } + return new AFPFontInfo(font, tripleList); + + } else if ("outline".equalsIgnoreCase(type)) { + + String characterset = afpFontCfg.getAttribute("characterset"); + if (characterset == null) { + log.error("Mandatory afp-font configuration attribute 'characterset=' is missing"); + return null; + } + String name = afpFontCfg.getAttribute("name", characterset); + + CharacterSet characterSet = null; + + String base14 = afpFontCfg.getAttribute("base14-font", null); + + if (base14 != null) { + try { + Class clazz = Class.forName("org.apache.fop.fonts.base14." + + base14); + try { + Typeface tf = (Typeface)clazz.newInstance(); + characterSet = new FopCharacterSet( + codepage, encoding, characterset, 1, tf); + } catch (Exception ie) { + String msg = "The base 14 font class " + clazz.getName() + + " could not be instantiated"; + log.error(msg); + } + } catch (ClassNotFoundException cnfe) { + String msg = "The base 14 font class for " + characterset + + " could not be found"; + log.error(msg); + } + } else { + characterSet = new CharacterSet(codepage, encoding, characterset, path); + } + // Create a new font object + OutlineFont font = new OutlineFont(name, characterSet); + return new AFPFontInfo(font, tripleList); + } else { + log.error("No or incorrect type attribute"); + } + return null; + } + + /** + * Builds a list of AFPFontInfo objects for use with the setup() method. + * @param cfg Configuration object + * @return List the newly created list of fonts + * @throws ConfigurationException if something's wrong with the config data + */ + private List buildFontListFromConfiguration(Configuration cfg) + throws ConfigurationException { + List fontList = new java.util.ArrayList(); + Configuration[] font = cfg.getChild("fonts").getChildren("font"); + for (int i = 0; i < font.length; i++) { + AFPFontInfo afi = buildFont(font[i], null); + if (afi != null) { + if (log.isDebugEnabled()) { + log.debug("Adding font " + afi.getAFPFont().getFontName()); + for (int j = 0; j < afi.getFontTriplets().size(); ++j) { + FontTriplet triplet = (FontTriplet) afi.getFontTriplets().get(j); + log.debug(" Font triplet " + + triplet.getName() + ", " + + triplet.getStyle() + ", " + + triplet.getWeight()); + } + } + + fontList.add(afi); + } + } + return fontList; + } + + /** + * Configure the AFP renderer. + * @param renderer AFP renderer + * @throws FOPException fop exception + * @see org.apache.fop.render.PrintRendererConfigurator#configure(Renderer) + */ + public void configure(Renderer renderer) throws FOPException { + Configuration cfg = super.getRendererConfig(renderer); + if (cfg != null) { + AFPRenderer afpRenderer = (AFPRenderer)renderer; + try { + List fontList = buildFontListFromConfiguration(cfg); + afpRenderer.setFontList(fontList); + } catch (ConfigurationException e) { + LogUtil.handleException(log, e, + userAgent.getFactory().validateUserConfigStrictly()); + } + + Configuration images = cfg.getChild("images"); + if (!"color".equalsIgnoreCase(images.getAttribute("mode", "b+w"))) { + afpRenderer.setBitsPerPixel(images.getAttributeAsInteger("bits-per-pixel", 8)); + } else { + afpRenderer.setColorImages(true); + } + } + } +} diff --git a/src/java/org/apache/fop/render/afp/AFPRendererMaker.java b/src/java/org/apache/fop/render/afp/AFPRendererMaker.java index 2d6d5711d..70bbe9076 100644 --- a/src/java/org/apache/fop/render/afp/AFPRendererMaker.java +++ b/src/java/org/apache/fop/render/afp/AFPRendererMaker.java @@ -23,6 +23,7 @@ import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; import org.apache.fop.render.AbstractRendererMaker; import org.apache.fop.render.Renderer; +import org.apache.fop.render.RendererConfigurator; /** * RendererMaker for the AFP Renderer. @@ -35,10 +36,15 @@ public class AFPRendererMaker extends AbstractRendererMaker { /**@see org.apache.fop.render.AbstractRendererMaker */ - public Renderer makeRenderer(FOUserAgent ua) { + public Renderer makeRenderer(FOUserAgent userAgent) { return new AFPRenderer(); } + /** @see org.apache.fop.render.AbstractRendererMaker#getConfigurator(FOUserAgent) */ + public RendererConfigurator getConfigurator(FOUserAgent userAgent) { + return new AFPRendererConfigurator(userAgent); + } + /** @see org.apache.fop.render.AbstractRendererMaker#needsOutputStream() */ public boolean needsOutputStream() { return true; diff --git a/src/java/org/apache/fop/render/awt/AWTRenderer.java b/src/java/org/apache/fop/render/awt/AWTRenderer.java index 6a50c0294..e83d8d220 100644 --- a/src/java/org/apache/fop/render/awt/AWTRenderer.java +++ b/src/java/org/apache/fop/render/awt/AWTRenderer.java @@ -38,6 +38,7 @@ import java.io.IOException; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.FopFactoryConfigurator; import org.apache.fop.apps.MimeConstants; import org.apache.fop.area.Area; import org.apache.fop.area.PageViewport; @@ -149,10 +150,10 @@ public class AWTRenderer extends Java2DRenderer implements Pageable { pageWidth = (int) Math.round(bounds.getWidth() / 1000f); pageHeight = (int) Math.round(bounds.getHeight() / 1000f); double scaleX = scaleFactor - * (25.4 / FOUserAgent.DEFAULT_TARGET_RESOLUTION) + * (25.4 / FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION) / userAgent.getTargetPixelUnitToMillimeter(); double scaleY = scaleFactor - * (25.4 / FOUserAgent.DEFAULT_TARGET_RESOLUTION) + * (25.4 / FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION) / userAgent.getTargetPixelUnitToMillimeter(); int bitmapWidth = (int) ((pageWidth * scaleX) + 0.5); int bitmapHeight = (int) ((pageHeight * scaleY) + 0.5); diff --git a/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java b/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java index c96c82259..5c22c8f34 100644 --- a/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java +++ b/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java @@ -32,9 +32,6 @@ import java.io.IOException; import java.io.OutputStream; import java.util.Iterator; -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; - import org.apache.commons.logging.Log; import org.apache.xmlgraphics.image.GraphicsUtil; @@ -77,12 +74,12 @@ public class TIFFRenderer extends Java2DRenderer { //private static final String COMPRESSION_NONE = "NONE"; //private static final String COMPRESSION_JPEG = "JPEG"; - private static final String COMPRESSION_PACKBITS = "PackBits"; + public static final String COMPRESSION_PACKBITS = "PackBits"; //private static final String COMPRESSION_DEFLATE = "Deflate"; //private static final String COMPRESSION_LZW = "LZW"; //private static final String COMPRESSION_ZLIB = "ZLib"; - private static final String COMPRESSION_CCITT_T6 = "CCITT T.6"; //CCITT Group 4 - private static final String COMPRESSION_CCITT_T4 = "CCITT T.4"; //CCITT Group 3 + public static final String COMPRESSION_CCITT_T6 = "CCITT T.6"; //CCITT Group 4 + public static final String COMPRESSION_CCITT_T4 = "CCITT T.4"; //CCITT Group 3 /** ImageWriter parameters */ private ImageWriterParams writerParams; @@ -115,30 +112,6 @@ public class TIFFRenderer extends Java2DRenderer { writerParams.setResolution(dpi); } - /** - * Configure the TIFF renderer. Get the configuration to be used for - * compression - * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration) - */ - public void configure(Configuration cfg) throws ConfigurationException { - super.configure(cfg); - - //set compression - String name = cfg.getChild("compression").getValue(COMPRESSION_PACKBITS); - //Some compression formats need a special image format: - if (name.equalsIgnoreCase(COMPRESSION_CCITT_T6)) { - bufferedImageType = BufferedImage.TYPE_BYTE_BINARY; - } else if (name.equalsIgnoreCase(COMPRESSION_CCITT_T4)) { - bufferedImageType = BufferedImage.TYPE_BYTE_BINARY; - } else { - bufferedImageType = BufferedImage.TYPE_INT_ARGB; - } - if (!"NONE".equalsIgnoreCase(name)) { - writerParams.setCompressionMethod(name); - } - log.info("TIFF compression set to " + name); - } - /** @see org.apache.fop.render.Renderer#startRenderer(java.io.OutputStream) */ public void startRenderer(OutputStream outputStream) throws IOException { this.outputStream = outputStream; @@ -253,4 +226,12 @@ public class TIFFRenderer extends Java2DRenderer { "Method 'remove' is not supported."); } } + + public void setBufferedImageType(int bufferedImageType) { + this.bufferedImageType = bufferedImageType; + } + + public ImageWriterParams getWriterParams() { + return writerParams; + } } diff --git a/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java new file mode 100644 index 000000000..2e4e29691 --- /dev/null +++ b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java @@ -0,0 +1,72 @@ +/* + * 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.render.bitmap; + +import java.awt.image.BufferedImage; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.render.PrintRendererConfigurator; +import org.apache.fop.render.Renderer; + +/** + * TIFF Renderer configurator + */ +public class TIFFRendererConfigurator extends PrintRendererConfigurator { + + /** + * Default constructor + * @param userAgent user agent + */ + public TIFFRendererConfigurator(FOUserAgent userAgent) { + super(userAgent); + } + + /** + * Configure the TIFF renderer. Get the configuration to be used for + * compression + * @param renderer tiff renderer + * @throws FOPException fop exception + * @see org.apache.fop.render.PrintRendererConfigurator#configure(Renderer) + */ + public void configure(Renderer renderer) throws FOPException { + Configuration cfg = super.getRendererConfig(renderer); + if (cfg != null) { + TIFFRenderer tiffRenderer = (TIFFRenderer)renderer; + //set compression + String name = cfg.getChild("compression").getValue(TIFFRenderer.COMPRESSION_PACKBITS); + //Some compression formats need a special image format: + if (name.equalsIgnoreCase(TIFFRenderer.COMPRESSION_CCITT_T6)) { + tiffRenderer.setBufferedImageType(BufferedImage.TYPE_BYTE_BINARY); + } else if (name.equalsIgnoreCase(TIFFRenderer.COMPRESSION_CCITT_T4)) { + tiffRenderer.setBufferedImageType(BufferedImage.TYPE_BYTE_BINARY); + } else { + tiffRenderer.setBufferedImageType(BufferedImage.TYPE_INT_ARGB); + } + if (!"NONE".equalsIgnoreCase(name)) { + tiffRenderer.getWriterParams().setCompressionMethod(name); + } + if (log.isInfoEnabled()) { + log.info("TIFF compression set to " + name); + } + } + } +} diff --git a/src/java/org/apache/fop/render/bitmap/TIFFRendererMaker.java b/src/java/org/apache/fop/render/bitmap/TIFFRendererMaker.java index ee2ba75fd..5e9f18261 100644 --- a/src/java/org/apache/fop/render/bitmap/TIFFRendererMaker.java +++ b/src/java/org/apache/fop/render/bitmap/TIFFRendererMaker.java @@ -23,6 +23,7 @@ import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants;
import org.apache.fop.render.AbstractRendererMaker;
import org.apache.fop.render.Renderer;
+import org.apache.fop.render.RendererConfigurator;
/**
* RendererMaker for the TIFF Renderer.
@@ -31,12 +32,16 @@ public class TIFFRendererMaker extends AbstractRendererMaker { private static final String[] MIMES = new String[] {MimeConstants.MIME_TIFF};
-
- /** @see org.apache.fop.render.AbstractRendererMaker */
- public Renderer makeRenderer(FOUserAgent ua) {
+ /** @see org.apache.fop.render.AbstractRendererMaker#makeRenderer(FOUserAgent) */
+ public Renderer makeRenderer(FOUserAgent userAgent) {
return new TIFFRenderer();
}
+ /** @see org.apache.fop.render.AbstractRendererMaker#getConfigurator(FOUserAgent) */
+ public RendererConfigurator getConfigurator(FOUserAgent userAgent) {
+ return new TIFFRendererConfigurator(userAgent);
+ }
+
/** @see org.apache.fop.render.AbstractRendererMaker#needsOutputStream() */
public boolean needsOutputStream() {
return true;
diff --git a/src/java/org/apache/fop/render/java2d/FontSetup.java b/src/java/org/apache/fop/render/java2d/FontSetup.java index ceda8f16c..e1dffd0e7 100644 --- a/src/java/org/apache/fop/render/java2d/FontSetup.java +++ b/src/java/org/apache/fop/render/java2d/FontSetup.java @@ -139,52 +139,52 @@ public class FontSetup { // fontInfo.addMetrics("F17", new BauerBodoniBoldItalic()); /* any is treated as serif */ - fontInfo.addFontProperties("F5", "any", "normal", Font.NORMAL); - fontInfo.addFontProperties("F6", "any", "italic", Font.NORMAL); - fontInfo.addFontProperties("F6", "any", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F7", "any", "normal", Font.BOLD); - fontInfo.addFontProperties("F8", "any", "italic", Font.BOLD); - fontInfo.addFontProperties("F8", "any", "oblique", Font.BOLD); + fontInfo.addFontProperties("F5", "any", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "any", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "any", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F7", "any", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "any", "italic", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "any", "oblique", Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F1", "sans-serif", "normal", Font.NORMAL); - fontInfo.addFontProperties("F2", "sans-serif", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F2", "sans-serif", "italic", Font.NORMAL); - fontInfo.addFontProperties("F3", "sans-serif", "normal", Font.BOLD); - fontInfo.addFontProperties("F4", "sans-serif", "oblique", Font.BOLD); - fontInfo.addFontProperties("F4", "sans-serif", "italic", Font.BOLD); - fontInfo.addFontProperties("F5", "serif", "normal", Font.NORMAL); - fontInfo.addFontProperties("F6", "serif", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F6", "serif", "italic", Font.NORMAL); - fontInfo.addFontProperties("F7", "serif", "normal", Font.BOLD); - fontInfo.addFontProperties("F8", "serif", "oblique", Font.BOLD); - fontInfo.addFontProperties("F8", "serif", "italic", Font.BOLD); - fontInfo.addFontProperties("F9", "monospace", "normal", Font.NORMAL); - fontInfo.addFontProperties("F10", "monospace", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F10", "monospace", "italic", Font.NORMAL); - fontInfo.addFontProperties("F11", "monospace", "normal", Font.BOLD); - fontInfo.addFontProperties("F12", "monospace", "oblique", Font.BOLD); - fontInfo.addFontProperties("F12", "monospace", "italic", Font.BOLD); + fontInfo.addFontProperties("F1", "sans-serif", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F2", "sans-serif", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F2", "sans-serif", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F3", "sans-serif", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F4", "sans-serif", "oblique", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F4", "sans-serif", "italic", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F5", "serif", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "serif", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "serif", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F7", "serif", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "serif", "oblique", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "serif", "italic", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F9", "monospace", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F10", "monospace", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F10", "monospace", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F11", "monospace", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F12", "monospace", "oblique", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F12", "monospace", "italic", Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F1", "Helvetica", "normal", Font.NORMAL); - fontInfo.addFontProperties("F2", "Helvetica", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F2", "Helvetica", "italic", Font.NORMAL); - fontInfo.addFontProperties("F3", "Helvetica", "normal", Font.BOLD); - fontInfo.addFontProperties("F4", "Helvetica", "oblique", Font.BOLD); - fontInfo.addFontProperties("F4", "Helvetica", "italic", Font.BOLD); - fontInfo.addFontProperties("F5", "Times", "normal", Font.NORMAL); - fontInfo.addFontProperties("F6", "Times", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F6", "Times", "italic", Font.NORMAL); - fontInfo.addFontProperties("F7", "Times", "normal", Font.BOLD); - fontInfo.addFontProperties("F8", "Times", "oblique", Font.BOLD); - fontInfo.addFontProperties("F8", "Times", "italic", Font.BOLD); - fontInfo.addFontProperties("F9", "Courier", "normal", Font.NORMAL); - fontInfo.addFontProperties("F10", "Courier", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F10", "Courier", "italic", Font.NORMAL); - fontInfo.addFontProperties("F11", "Courier", "normal", Font.BOLD); - fontInfo.addFontProperties("F12", "Courier", "oblique", Font.BOLD); - fontInfo.addFontProperties("F12", "Courier", "italic", Font.BOLD); - fontInfo.addFontProperties("F13", "Symbol", "normal", Font.NORMAL); - fontInfo.addFontProperties("F14", "ZapfDingbats", "normal", Font.NORMAL); + fontInfo.addFontProperties("F1", "Helvetica", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F2", "Helvetica", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F2", "Helvetica", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F3", "Helvetica", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F4", "Helvetica", "oblique", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F4", "Helvetica", "italic", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F5", "Times", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "Times", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "Times", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F7", "Times", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "Times", "oblique", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "Times", "italic", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F9", "Courier", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F10", "Courier", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F10", "Courier", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F11", "Courier", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F12", "Courier", "oblique", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F12", "Courier", "italic", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F13", "Symbol", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F14", "ZapfDingbats", "normal", Font.WEIGHT_NORMAL); // Custom type 1 fonts step 2/2 // fontInfo.addFontProperties("F15", "OMEP", "normal", FontInfo.NORMAL); @@ -192,20 +192,20 @@ public class FontSetup { // fontInfo.addFontProperties("F17", "BauerBodoni", "italic", FontInfo.BOLD); /* for compatibility with PassiveTex */ - fontInfo.addFontProperties("F5", "Times-Roman", "normal", Font.NORMAL); - fontInfo.addFontProperties("F6", "Times-Roman", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F6", "Times-Roman", "italic", Font.NORMAL); - fontInfo.addFontProperties("F7", "Times-Roman", "normal", Font.BOLD); - fontInfo.addFontProperties("F8", "Times-Roman", "oblique", Font.BOLD); - fontInfo.addFontProperties("F8", "Times-Roman", "italic", Font.BOLD); - fontInfo.addFontProperties("F5", "Times Roman", "normal", Font.NORMAL); - fontInfo.addFontProperties("F6", "Times Roman", "oblique", Font.NORMAL); - fontInfo.addFontProperties("F6", "Times Roman", "italic", Font.NORMAL); - fontInfo.addFontProperties("F7", "Times Roman", "normal", Font.BOLD); - fontInfo.addFontProperties("F8", "Times Roman", "oblique", Font.BOLD); - fontInfo.addFontProperties("F8", "Times Roman", "italic", Font.BOLD); + fontInfo.addFontProperties("F5", "Times-Roman", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "Times-Roman", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "Times-Roman", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F7", "Times-Roman", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "Times-Roman", "oblique", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "Times-Roman", "italic", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F5", "Times Roman", "normal", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "Times Roman", "oblique", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F6", "Times Roman", "italic", Font.WEIGHT_NORMAL); + fontInfo.addFontProperties("F7", "Times Roman", "normal", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "Times Roman", "oblique", Font.WEIGHT_BOLD); + fontInfo.addFontProperties("F8", "Times Roman", "italic", Font.WEIGHT_BOLD); fontInfo.addFontProperties("F9", "Computer-Modern-Typewriter", - "normal", Font.NORMAL); + "normal", Font.WEIGHT_NORMAL); configureInstalledAWTFonts(fontInfo, graphics, LAST_PREDEFINED_FONT_NUMBER + 1); } @@ -252,9 +252,9 @@ public class FontSetup { FontMetricsMapper metric = new FontMetricsMapper(family, fontStyle, graphics); fontInfo.addMetrics(fontKey, metric); - int weight = Font.NORMAL; + int weight = Font.WEIGHT_NORMAL; if ((fontStyle & java.awt.Font.BOLD) != 0) { - weight = Font.BOLD; + weight = Font.WEIGHT_BOLD; } String style = "normal"; if ((fontStyle & java.awt.Font.ITALIC) != 0) { diff --git a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java index 2bb3711bb..7d837e699 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java +++ b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java @@ -53,10 +53,9 @@ import java.util.Stack; import org.w3c.dom.Document; -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.FopFactoryConfigurator; import org.apache.fop.area.CTM; import org.apache.fop.area.PageViewport; import org.apache.fop.area.Trait; @@ -73,7 +72,6 @@ import org.apache.fop.fonts.Typeface; import org.apache.fop.image.FopImage; import org.apache.fop.image.ImageFactory; import org.apache.fop.image.XMLImage; -import org.apache.fop.pdf.PDFAMode; import org.apache.fop.render.AbstractPathOrientedRenderer; import org.apache.fop.render.Graphics2DAdapter; import org.apache.fop.render.RendererContext; @@ -151,19 +149,6 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem } /** - * @see org.apache.fop.render.AbstractRenderer#configure( - * org.apache.avalon.framework.configuration.Configuration) - */ - public void configure(Configuration cfg) throws ConfigurationException { - super.configure(cfg); - - String s = cfg.getChild(JAVA2D_TRANSPARENT_PAGE_BACKGROUND, true).getValue(null); - if (s != null) { - this.transparentPageBackground = "true".equalsIgnoreCase(s); - } - } - - /** * @see org.apache.fop.render.Renderer#setUserAgent(org.apache.fop.apps.FOUserAgent) */ public void setUserAgent(FOUserAgent foUserAgent) { @@ -305,10 +290,10 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem + pageHeight + ")"); double scaleX = scaleFactor - * (25.4 / FOUserAgent.DEFAULT_TARGET_RESOLUTION) + * (25.4 / FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION) / userAgent.getTargetPixelUnitToMillimeter(); double scaleY = scaleFactor - * (25.4 / FOUserAgent.DEFAULT_TARGET_RESOLUTION) + * (25.4 / FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION) / userAgent.getTargetPixelUnitToMillimeter(); int bitmapWidth = (int) ((pageWidth * scaleX) + 0.5); int bitmapHeight = (int) ((pageHeight * scaleY) + 0.5); @@ -1023,4 +1008,8 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem //not necessary in Java2D } + public void setTransparentPageBackground(boolean transparentPageBackground) { + this.transparentPageBackground = transparentPageBackground; + } + } diff --git a/src/java/org/apache/fop/render/java2d/Java2DRendererConfigurator.java b/src/java/org/apache/fop/render/java2d/Java2DRendererConfigurator.java new file mode 100644 index 000000000..6732a10fe --- /dev/null +++ b/src/java/org/apache/fop/render/java2d/Java2DRendererConfigurator.java @@ -0,0 +1,57 @@ +/* + * 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.render.java2d; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.render.PrintRendererConfigurator; +import org.apache.fop.render.Renderer; + +/** + * Configurerer for Java 2D renderer + */ +public class Java2DRendererConfigurator extends PrintRendererConfigurator { + + /** + * Default constructor + * @param userAgent user agent + */ + public Java2DRendererConfigurator(FOUserAgent userAgent) { + super(userAgent); + } + + /** + * Configure the Java 2D renderer. + * @param renderer java 2d renderer + * @throws FOPException fop exception + */ + public void configure(Renderer renderer) throws FOPException { + Configuration cfg = super.getRendererConfig(renderer); + if (cfg != null) { + Java2DRenderer java2dRenderer = (Java2DRenderer)renderer; + String value = cfg.getChild( + Java2DRenderer.JAVA2D_TRANSPARENT_PAGE_BACKGROUND, true).getValue(null); + if (value != null) { + java2dRenderer.setTransparentPageBackground("true".equalsIgnoreCase(value)); + } + } + } +} diff --git a/src/java/org/apache/fop/render/pcl/PCLRenderer.java b/src/java/org/apache/fop/render/pcl/PCLRenderer.java index 596dc06d3..733212e48 100644 --- a/src/java/org/apache/fop/render/pcl/PCLRenderer.java +++ b/src/java/org/apache/fop/render/pcl/PCLRenderer.java @@ -53,8 +53,6 @@ import org.w3c.dom.Document; import org.apache.xmlgraphics.java2d.GraphicContext; // FOP -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.apps.FOPException; @@ -143,31 +141,8 @@ public class PCLRenderer extends PrintRenderer { public PCLRenderer() { } - /** - * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration) - */ - public void configure(Configuration cfg) throws ConfigurationException { - super.configure(cfg); - String rendering = cfg.getChild("rendering").getValue(null); - if ("quality".equalsIgnoreCase(rendering)) { - this.qualityBeforeSpeed = true; - } else if ("speed".equalsIgnoreCase(rendering)) { - this.qualityBeforeSpeed = false; - } else if (rendering != null) { - throw new ConfigurationException( - "Valid values for 'rendering' are 'quality' and 'speed'. Value found: " - + rendering); - } - String textRendering = cfg.getChild("text-rendering").getValue(null); - if ("bitmap".equalsIgnoreCase(textRendering)) { - this.allTextAsBitmaps = true; - } else if ("auto".equalsIgnoreCase(textRendering)) { - this.allTextAsBitmaps = false; - } else if (textRendering != null) { - throw new ConfigurationException( - "Valid values for 'text-rendering' are 'auto' and 'bitmap'. Value found: " - + textRendering); - } + public void setQualityBeforeSpeed(boolean qualityBeforeSpeed) { + this.qualityBeforeSpeed = qualityBeforeSpeed; } /** @@ -1499,6 +1474,10 @@ public class PCLRenderer extends PrintRenderer { handleIOTrouble(ioe); } } + + public void setAllTextAsBitmaps(boolean allTextAsBitmaps) { + this.allTextAsBitmaps = allTextAsBitmaps; + } diff --git a/src/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java b/src/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java new file mode 100644 index 000000000..814b6837c --- /dev/null +++ b/src/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java @@ -0,0 +1,74 @@ +/* + * 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.render.pcl; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.render.PrintRendererConfigurator; +import org.apache.fop.render.Renderer; + +/** + * PCL Renderer configurator + */ +public class PCLRendererConfigurator extends PrintRendererConfigurator { + + /** + * Default constructor + * @param userAgent user agent + */ + public PCLRendererConfigurator(FOUserAgent userAgent) { + super(userAgent); + } + + /** + * Configure the TIFF renderer. Get the configuration to be used for + * compression + * @param renderer PCL renderer + * @throws FOPException fop exception + * @see org.apache.fop.render.PrintRendererConfigurator#configure(Renderer) + */ + public void configure(Renderer renderer) throws FOPException { + Configuration cfg = super.getRendererConfig(renderer); + if (cfg != null) { + PCLRenderer pclRenderer = (PCLRenderer)renderer; + String rendering = cfg.getChild("rendering").getValue(null); + if ("quality".equalsIgnoreCase(rendering)) { + pclRenderer.setQualityBeforeSpeed(true); + } else if ("speed".equalsIgnoreCase(rendering)) { + pclRenderer.setQualityBeforeSpeed(false); + } else if (rendering != null) { + throw new FOPException( + "Valid values for 'rendering' are 'quality' and 'speed'. Value found: " + + rendering); + } + String textRendering = cfg.getChild("text-rendering").getValue(null); + if ("bitmap".equalsIgnoreCase(textRendering)) { + pclRenderer.setAllTextAsBitmaps(true); + } else if ("auto".equalsIgnoreCase(textRendering)) { + pclRenderer.setAllTextAsBitmaps(false); + } else if (textRendering != null) { + throw new FOPException( + "Valid values for 'text-rendering' are 'auto' and 'bitmap'. Value found: " + + textRendering); + } + } + } +} diff --git a/src/java/org/apache/fop/render/pcl/PCLRendererMaker.java b/src/java/org/apache/fop/render/pcl/PCLRendererMaker.java index aa0bc292b..b7b395341 100644 --- a/src/java/org/apache/fop/render/pcl/PCLRendererMaker.java +++ b/src/java/org/apache/fop/render/pcl/PCLRendererMaker.java @@ -23,6 +23,7 @@ import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants;
import org.apache.fop.render.AbstractRendererMaker;
import org.apache.fop.render.Renderer;
+import org.apache.fop.render.RendererConfigurator;
/**
* RendererMaker for the PCL Renderer.
@@ -31,14 +32,19 @@ public class PCLRendererMaker extends AbstractRendererMaker { private static final String[] MIMES = new String[] {
MimeConstants.MIME_PCL,
- MimeConstants.MIME_PCL_ALT};
+ MimeConstants.MIME_PCL_ALT
+ };
-
- /**@see org.apache.fop.render.AbstractRendererMaker */
- public Renderer makeRenderer(FOUserAgent ua) {
+ /**@see org.apache.fop.render.AbstractRendererMaker#makeRenderer(FOUserAgent) */
+ public Renderer makeRenderer(FOUserAgent userAgent) {
return new PCLRenderer();
}
+ /** @see org.apache.fop.render.AbstractRendererMaker#getConfigurator(FOUserAgent) */
+ public RendererConfigurator getConfigurator(FOUserAgent userAgent) {
+ return new PCLRendererConfigurator(userAgent);
+ }
+
/** @see org.apache.fop.render.AbstractRendererMaker#needsOutputStream() */
public boolean needsOutputStream() {
return true;
@@ -48,5 +54,4 @@ public class PCLRendererMaker extends AbstractRendererMaker { public String[] getSupportedMimeTypes() {
return MIMES;
}
-
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index 7d584c036..73c38878e 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -41,8 +41,6 @@ import javax.xml.transform.stream.StreamSource; import org.w3c.dom.Document; // Avalon -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.commons.io.IOUtils; // FOP @@ -69,7 +67,6 @@ import org.apache.fop.area.inline.WordArea; import org.apache.fop.area.inline.SpaceArea; import org.apache.fop.fonts.Typeface; import org.apache.fop.fonts.Font; -import org.apache.fop.fonts.FontSetup; import org.apache.fop.image.FopImage; import org.apache.fop.image.ImageFactory; import org.apache.fop.image.XMLImage; @@ -86,7 +83,6 @@ import org.apache.fop.pdf.PDFFilterList; import org.apache.fop.pdf.PDFGoTo; import org.apache.fop.pdf.PDFICCBasedColorSpace; import org.apache.fop.pdf.PDFICCStream; -import org.apache.fop.pdf.PDFGoTo; import org.apache.fop.pdf.PDFInfo; import org.apache.fop.pdf.PDFLink; import org.apache.fop.pdf.PDFMetadata; @@ -266,38 +262,6 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { public PDFRenderer() { } - /** - * Configure the PDF renderer. - * Get the configuration to be used for pdf stream filters, - * fonts etc. - * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration) - */ - public void configure(Configuration cfg) throws ConfigurationException { - //PDF filters - this.filterMap = PDFFilterList.buildFilterMapFromConfiguration(cfg); - - //Font configuration - List cfgFonts = FontSetup.buildFontListFromConfiguration(cfg, this); - if (this.fontList == null) { - this.fontList = cfgFonts; - } else { - this.fontList.addAll(cfgFonts); - } - - String s = cfg.getChild(PDF_A_MODE, true).getValue(null); - if (s != null) { - this.pdfAMode = PDFAMode.valueOf(s); - } - s = cfg.getChild(PDF_X_MODE, true).getValue(null); - if (s != null) { - this.pdfXMode = PDFXMode.valueOf(s); - } - s = cfg.getChild(KEY_OUTPUT_PROFILE, true).getValue(null); - if (s != null) { - this.outputProfileURI = s; - } - } - private boolean booleanValueOf(Object obj) { if (obj instanceof Boolean) { return ((Boolean)obj).booleanValue(); @@ -1891,5 +1855,21 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { public String getMimeType() { return MIME_TYPE; } + + public void setAMode(PDFAMode mode) { + this.pdfAMode = mode; + } + + public void setXMode(PDFXMode mode) { + this.pdfXMode = mode; + } + + public void setOutputProfileURI(String outputProfileURI) { + this.outputProfileURI = outputProfileURI; + } + + public void setFilterMap(Map filterMap) { + this.filterMap = filterMap; + } } diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java b/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java new file mode 100644 index 000000000..5c5894d3b --- /dev/null +++ b/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java @@ -0,0 +1,134 @@ +/* + * 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.render.pdf; + +import java.util.List; +import java.util.Map; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.pdf.PDFAMode; +import org.apache.fop.pdf.PDFFilterList; +import org.apache.fop.pdf.PDFXMode; +import org.apache.fop.render.PrintRendererConfigurator; +import org.apache.fop.render.Renderer; +import org.apache.fop.util.LogUtil; + +/** + * PDF renderer configurator + */ +public class PDFRendererConfigurator extends PrintRendererConfigurator { + + /** + * Default constructor + * @param userAgent user agent + */ + public PDFRendererConfigurator(FOUserAgent userAgent) { + super(userAgent); + } + + /** + * Configure the PDF renderer. + * Get the configuration to be used for pdf stream filters, + * fonts etc. + * @param renderer pdf renderer + * @throws FOPException fop exception + */ + public void configure(Renderer renderer) throws FOPException { + Configuration cfg = super.getRendererConfig(renderer); + if (cfg != null) { + PDFRenderer pdfRenderer = (PDFRenderer)renderer; + //PDF filters + try { + Map filterMap = buildFilterMapFromConfiguration(cfg); + if (filterMap != null) { + pdfRenderer.setFilterMap(filterMap); + } + } catch (ConfigurationException e) { + LogUtil.handleException(log, e, false); + } + + super.configure(renderer); + + String s = cfg.getChild(PDFRenderer.PDF_A_MODE, true).getValue(null); + if (s != null) { + pdfRenderer.setAMode(PDFAMode.valueOf(s)); + } + s = cfg.getChild(PDFRenderer.PDF_X_MODE, true).getValue(null); + if (s != null) { + pdfRenderer.setXMode(PDFXMode.valueOf(s)); + } + s = cfg.getChild(PDFRenderer.KEY_OUTPUT_PROFILE, true).getValue(null); + if (s != null) { + pdfRenderer.setOutputProfileURI(s); + } + } + } + + /** + * Builds a filter map from an Avalon Configuration object. + * @param cfg the Configuration object + * @return Map the newly built filter map + * @throws ConfigurationException if a filter list is defined twice + */ + public static Map buildFilterMapFromConfiguration(Configuration cfg) + throws ConfigurationException { + Map filterMap = new java.util.HashMap(); + Configuration[] filterLists = cfg.getChildren("filterList"); + for (int i = 0; i < filterLists.length; i++) { + Configuration filters = filterLists[i]; + String type = filters.getAttribute("type", null); + Configuration[] filt = filters.getChildren("value"); + List filterList = new java.util.ArrayList(); + for (int j = 0; j < filt.length; j++) { + String name = filt[j].getValue(); + filterList.add(name); + } + + if (type == null) { + type = PDFFilterList.DEFAULT_FILTER; + } + + if (!filterList.isEmpty() && log.isDebugEnabled()) { + StringBuffer debug = new StringBuffer("Adding PDF filter"); + if (filterList.size() != 1) { + debug.append("s"); + } + debug.append(" for type ").append(type).append(": "); + for (int j = 0; j < filterList.size(); j++) { + if (j != 0) { + debug.append(", "); + } + debug.append(filterList.get(j)); + } + log.debug(debug.toString()); + } + + if (filterMap.get(type) != null) { + throw new ConfigurationException("A filterList of type '" + + type + "' has already been defined"); + } + filterMap.put(type, filterList); + } + return filterMap; + } +} diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererMaker.java b/src/java/org/apache/fop/render/pdf/PDFRendererMaker.java index 0f8d8bc14..00fc1a88f 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRendererMaker.java +++ b/src/java/org/apache/fop/render/pdf/PDFRendererMaker.java @@ -23,6 +23,7 @@ import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants;
import org.apache.fop.render.AbstractRendererMaker;
import org.apache.fop.render.Renderer;
+import org.apache.fop.render.RendererConfigurator;
/**
* RendererMaker for the PDF Renderer.
@@ -31,12 +32,16 @@ public class PDFRendererMaker extends AbstractRendererMaker { private static final String[] MIMES = new String[] {MimeConstants.MIME_PDF};
-
- /**@see org.apache.fop.render.AbstractRendererMaker */
- public Renderer makeRenderer(FOUserAgent ua) {
+ /** @see org.apache.fop.render.AbstractRendererMaker#makeRenderer(FOUserAgent) */
+ public Renderer makeRenderer(FOUserAgent userAgent) {
return new PDFRenderer();
}
+ /** @see org.apache.fop.render.AbstractRendererMaker#getConfigurator(FOUserAgent) */
+ public RendererConfigurator getConfigurator(FOUserAgent userAgent) {
+ return new PDFRendererConfigurator(userAgent);
+ }
+
/** @see org.apache.fop.render.AbstractRendererMaker#needsOutputStream() */
public boolean needsOutputStream() {
return true;
diff --git a/src/java/org/apache/fop/render/print/PrintRendererMaker.java b/src/java/org/apache/fop/render/print/PrintRendererMaker.java index 046427682..6ad2cb3d1 100644 --- a/src/java/org/apache/fop/render/print/PrintRendererMaker.java +++ b/src/java/org/apache/fop/render/print/PrintRendererMaker.java @@ -22,7 +22,9 @@ package org.apache.fop.render.print; import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.render.AbstractRendererMaker;
+import org.apache.fop.render.PrintRendererConfigurator;
import org.apache.fop.render.Renderer;
+import org.apache.fop.render.RendererConfigurator;
/**
* RendererMaker for the Print Renderer.
@@ -31,12 +33,16 @@ public class PrintRendererMaker extends AbstractRendererMaker { private static final String[] MIMES = new String[] {MimeConstants.MIME_FOP_PRINT};
-
- /**@see org.apache.fop.render.AbstractRendererMaker */
- public Renderer makeRenderer(FOUserAgent ua) {
+ /**@see org.apache.fop.render.AbstractRendererMaker#makeRenderer(FOUserAgent) */
+ public Renderer makeRenderer(FOUserAgent userAgent) {
return new PrintRenderer();
}
+ /** @see org.apache.fop.render.AbstractRendererMaker#getConfigurator(FOUserAgent) */
+ public RendererConfigurator getConfigurator(FOUserAgent userAgent) {
+ return new PrintRendererConfigurator(userAgent);
+ }
+
/** @see org.apache.fop.render.AbstractRendererMaker#needsOutputStream() */
public boolean needsOutputStream() {
return false;
diff --git a/src/java/org/apache/fop/render/ps/NativeTextHandler.java b/src/java/org/apache/fop/render/ps/NativeTextHandler.java index 47f7fb0b8..5cda145b9 100644 --- a/src/java/org/apache/fop/render/ps/NativeTextHandler.java +++ b/src/java/org/apache/fop/render/ps/NativeTextHandler.java @@ -159,7 +159,7 @@ public class NativeTextHandler implements TextHandler { } int fontSize = 1000 * f.getSize(); String style = f.isItalic() ? "italic" : "normal"; - int weight = f.isBold() ? Font.BOLD : Font.NORMAL; + int weight = f.isBold() ? Font.WEIGHT_BOLD : Font.WEIGHT_NORMAL; FontTriplet triplet = fontInfo.findAdjustWeight(fontFamily, style, weight); if (triplet == null) { diff --git a/src/java/org/apache/fop/render/ps/PSRenderer.java b/src/java/org/apache/fop/render/ps/PSRenderer.java index 68c6cc86c..ad5b0b3ce 100644 --- a/src/java/org/apache/fop/render/ps/PSRenderer.java +++ b/src/java/org/apache/fop/render/ps/PSRenderer.java @@ -35,8 +35,6 @@ import java.util.Map; import javax.xml.transform.Source; // FOP -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -61,7 +59,6 @@ import org.apache.fop.apps.FOUserAgent; import org.apache.fop.fo.Constants; import org.apache.fop.fo.extensions.ExtensionAttachment; import org.apache.fop.fonts.Font; -import org.apache.fop.fonts.FontSetup; import org.apache.fop.fonts.LazyFont; import org.apache.fop.fonts.Typeface; import org.apache.fop.image.EPSImage; @@ -146,24 +143,6 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda private Map formResources; /** - * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration) - */ - public void configure(Configuration cfg) throws ConfigurationException { - super.configure(cfg); - this.autoRotateLandscape = cfg.getChild(AUTO_ROTATE_LANDSCAPE).getValueAsBoolean(false); - this.languageLevel = cfg.getChild(LANGUAGE_LEVEL).getValueAsInteger(this.languageLevel); - this.twoPassGeneration = cfg.getChild(OPTIMIZE_RESOURCES).getValueAsBoolean(false); - - //Font configuration - List cfgFonts = FontSetup.buildFontListFromConfiguration(cfg, this); - if (this.fontList == null) { - this.fontList = cfgFonts; - } else { - this.fontList.addAll(cfgFonts); - } - } - - /** * @see org.apache.fop.render.Renderer#setUserAgent(FOUserAgent) */ public void setUserAgent(FOUserAgent agent) { diff --git a/src/java/org/apache/fop/render/ps/PSRendererConfigurator.java b/src/java/org/apache/fop/render/ps/PSRendererConfigurator.java new file mode 100644 index 000000000..c7b5a025b --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSRendererConfigurator.java @@ -0,0 +1,56 @@ +/* + * 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.render.ps; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.render.PrintRendererConfigurator; +import org.apache.fop.render.Renderer; + +/** + * Postscript renderer config + */ +public class PSRendererConfigurator extends PrintRendererConfigurator { + + /** + * Default constructor + * @param userAgent user agent + */ + public PSRendererConfigurator(FOUserAgent userAgent) { + super(userAgent); + } + + /** + * Configure the PS renderer. + * @param renderer postscript renderer + * @throws FOPException fop exception + */ + public void configure(Renderer renderer) throws FOPException { + Configuration cfg = super.getRendererConfig(renderer); + if (cfg != null) { + super.configure(renderer); + + PSRenderer psRenderer = (PSRenderer)renderer; + psRenderer.setAutoRotateLandscape( + cfg.getChild("auto-rotate-landscape").getValueAsBoolean(false)); + } + } +} diff --git a/src/java/org/apache/fop/render/ps/PSRendererMaker.java b/src/java/org/apache/fop/render/ps/PSRendererMaker.java index 45f7663aa..0db4281d0 100644 --- a/src/java/org/apache/fop/render/ps/PSRendererMaker.java +++ b/src/java/org/apache/fop/render/ps/PSRendererMaker.java @@ -23,6 +23,7 @@ import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants;
import org.apache.fop.render.AbstractRendererMaker;
import org.apache.fop.render.Renderer;
+import org.apache.fop.render.RendererConfigurator;
/**
* RendererMaker for the PostScript Renderer.
@@ -31,12 +32,16 @@ public class PSRendererMaker extends AbstractRendererMaker { private static final String[] MIMES = new String[] {MimeConstants.MIME_POSTSCRIPT};
-
- /** @see org.apache.fop.render.AbstractRendererMaker */
- public Renderer makeRenderer(FOUserAgent ua) {
+ /** @see org.apache.fop.render.AbstractRendererMaker#makeRenderer(FOUserAgent) */
+ public Renderer makeRenderer(FOUserAgent userAgent) {
return new PSRenderer();
}
+ /** @see org.apache.fop.render.AbstractRendererMaker#getConfigurator(FOUserAgent) */
+ public RendererConfigurator getConfigurator(FOUserAgent userAgent) {
+ return new PSRendererConfigurator(userAgent);
+ }
+
/** @see org.apache.fop.render.AbstractRendererMaker#needsOutputStream() */
public boolean needsOutputStream() {
return true;
@@ -46,5 +51,4 @@ public class PSRendererMaker extends AbstractRendererMaker { public String[] getSupportedMimeTypes() {
return MIMES;
}
-
}
diff --git a/src/java/org/apache/fop/render/ps/PSTextPainter.java b/src/java/org/apache/fop/render/ps/PSTextPainter.java index 78efd56b9..f4796fd2b 100644 --- a/src/java/org/apache/fop/render/ps/PSTextPainter.java +++ b/src/java/org/apache/fop/render/ps/PSTextPainter.java @@ -367,8 +367,8 @@ public class PSTextPainter implements TextPainter { private int getWeight(AttributedCharacterIterator aci) { Float taWeight = (Float)aci.getAttribute(TextAttribute.WEIGHT); return ((taWeight != null) && (taWeight.floatValue() > 1.0)) - ? Font.BOLD - : Font.NORMAL; + ? Font.WEIGHT_BOLD + : Font.WEIGHT_NORMAL; } private Font makeFont(AttributedCharacterIterator aci) { @@ -402,7 +402,7 @@ public class PSTextPainter implements TextPainter { } } } - FontTriplet triplet = fontInfo.fontLookup("any", style, Font.NORMAL); + FontTriplet triplet = fontInfo.fontLookup("any", style, Font.WEIGHT_NORMAL); int fsize = (int)(fontSize.floatValue() * 1000); return fontInfo.getFontInstance(triplet, fsize); } @@ -411,7 +411,7 @@ public class PSTextPainter implements TextPainter { final String style = getStyle(aci); final int weight = getWeight(aci); int fStyle = java.awt.Font.PLAIN; - if (weight == Font.BOLD) { + if (weight == Font.WEIGHT_BOLD) { fStyle |= java.awt.Font.BOLD; } if ("italic".equals(style)) { diff --git a/src/java/org/apache/fop/render/txt/TXTRenderer.java b/src/java/org/apache/fop/render/txt/TXTRenderer.java index 85d3dd797..cec1dbc4b 100644 --- a/src/java/org/apache/fop/render/txt/TXTRenderer.java +++ b/src/java/org/apache/fop/render/txt/TXTRenderer.java @@ -27,8 +27,6 @@ import java.io.OutputStream; import java.util.List; import java.util.Map; -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.fop.apps.FOPException; import org.apache.fop.area.Area; import org.apache.fop.area.CTM; @@ -115,12 +113,6 @@ public class TXTRenderer extends AbstractPathOrientedRenderer { public String getMimeType() { return "text/plain"; } - - /** @see org.apache.fop.render.AbstractRenderer */ - public void configure(Configuration conf) throws ConfigurationException { - super.configure(conf); - this.encoding = conf.getChild("encoding", true).getValue(null); - } /** * Sets the encoding of the target file. diff --git a/src/java/org/apache/fop/render/txt/TXTRendererConfigurator.java b/src/java/org/apache/fop/render/txt/TXTRendererConfigurator.java new file mode 100644 index 000000000..ab655c92e --- /dev/null +++ b/src/java/org/apache/fop/render/txt/TXTRendererConfigurator.java @@ -0,0 +1,53 @@ +/* + * 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.render.txt; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.render.PrintRendererConfigurator; +import org.apache.fop.render.Renderer; + +/** + * TXT Renderer configurator + */ +public class TXTRendererConfigurator extends PrintRendererConfigurator { + + /** + * Default constructor + * @param userAgent user agent + */ + public TXTRendererConfigurator(FOUserAgent userAgent) { + super(userAgent); + } + + /** + * Configure the PS renderer. + * @param renderer TXT renderer + * @throws FOPException fop exception + */ + public void configure(Renderer renderer) throws FOPException { + Configuration cfg = super.getRendererConfig(renderer); + if (cfg != null) { + TXTRenderer txtRenderer = (TXTRenderer)renderer; + txtRenderer.setEncoding(cfg.getChild("encoding", true).getValue(null)); + } + } +} diff --git a/src/java/org/apache/fop/render/txt/TXTRendererMaker.java b/src/java/org/apache/fop/render/txt/TXTRendererMaker.java index 5c1b812b6..8a92ed11d 100644 --- a/src/java/org/apache/fop/render/txt/TXTRendererMaker.java +++ b/src/java/org/apache/fop/render/txt/TXTRendererMaker.java @@ -23,6 +23,7 @@ import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants;
import org.apache.fop.render.AbstractRendererMaker;
import org.apache.fop.render.Renderer;
+import org.apache.fop.render.RendererConfigurator;
/**
* RendererMaker for the Plain Text Renderer.
@@ -31,12 +32,16 @@ public class TXTRendererMaker extends AbstractRendererMaker { private static final String[] MIMES = new String[] {MimeConstants.MIME_PLAIN_TEXT};
-
- /**@see org.apache.fop.render.AbstractRendererMaker */
- public Renderer makeRenderer(FOUserAgent ua) {
+ /**@see org.apache.fop.render.AbstractRendererMaker#makeRenderer(FOUserAgent) */
+ public Renderer makeRenderer(FOUserAgent userAgent) {
return new TXTRenderer();
}
+ /**@see org.apache.fop.render.AbstractRendererMaker#getConfigurator(FOUserAgent) */
+ public RendererConfigurator getConfigurator(FOUserAgent userAgent) {
+ return new TXTRendererConfigurator(userAgent);
+ }
+
/** @see org.apache.fop.render.AbstractRendererMaker#needsOutputStream() */
public boolean needsOutputStream() {
return true;
@@ -46,5 +51,4 @@ public class TXTRendererMaker extends AbstractRendererMaker { public String[] getSupportedMimeTypes() {
return MIMES;
}
-
}
diff --git a/src/java/org/apache/fop/render/xml/XMLRenderer.java b/src/java/org/apache/fop/render/xml/XMLRenderer.java index cccdb6d71..b95ea7e18 100644 --- a/src/java/org/apache/fop/render/xml/XMLRenderer.java +++ b/src/java/org/apache/fop/render/xml/XMLRenderer.java @@ -41,8 +41,6 @@ import org.xml.sax.SAXException; import org.xml.sax.ext.LexicalHandler; import org.xml.sax.helpers.AttributesImpl; -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.fop.util.QName; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; @@ -83,7 +81,6 @@ import org.apache.fop.area.inline.WordArea; import org.apache.fop.fo.Constants; import org.apache.fop.fo.extensions.ExtensionAttachment; import org.apache.fop.fonts.FontInfo; -import org.apache.fop.fonts.FontSetup; import org.apache.fop.fonts.FontTriplet; import org.apache.fop.render.PrintRenderer; import org.apache.fop.render.Renderer; @@ -140,22 +137,6 @@ public class XMLRenderer extends PrintRenderer { } /** - * Configure the XML renderer. - * Get the configuration to be used for fonts etc. - * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration) - */ - public void configure(Configuration cfg) throws ConfigurationException { - super.configure(cfg); - //Font configuration - List cfgFonts = FontSetup.buildFontListFromConfiguration(cfg, this); - if (this.fontList == null) { - this.fontList = cfgFonts; - } else { - this.fontList.addAll(cfgFonts); - } - } - - /** * @see org.apache.fop.render.Renderer#setUserAgent(FOUserAgent) */ public void setUserAgent(FOUserAgent agent) { diff --git a/src/java/org/apache/fop/render/xml/XMLRendererMaker.java b/src/java/org/apache/fop/render/xml/XMLRendererMaker.java index 1be56f39a..582cfb9be 100644 --- a/src/java/org/apache/fop/render/xml/XMLRendererMaker.java +++ b/src/java/org/apache/fop/render/xml/XMLRendererMaker.java @@ -22,7 +22,9 @@ package org.apache.fop.render.xml; import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.render.AbstractRendererMaker;
+import org.apache.fop.render.PrintRendererConfigurator;
import org.apache.fop.render.Renderer;
+import org.apache.fop.render.RendererConfigurator;
/**
* RendererMaker for the Area Tree XML Renderer.
@@ -31,12 +33,16 @@ public class XMLRendererMaker extends AbstractRendererMaker { private static final String[] MIMES = new String[] {MimeConstants.MIME_FOP_AREA_TREE};
-
- /**@see org.apache.fop.render.AbstractRendererMaker */
- public Renderer makeRenderer(FOUserAgent ua) {
+ /**@see org.apache.fop.render.AbstractRendererMaker#makeRenderer(FOUserAgent) */
+ public Renderer makeRenderer(FOUserAgent userAgent) {
return new XMLRenderer();
}
+ /**@see org.apache.fop.render.AbstractRendererMaker#getConfigurator(FOUserAgent) */
+ public RendererConfigurator getConfigurator(FOUserAgent userAgent) {
+ return new PrintRendererConfigurator(userAgent);
+ }
+
/** @see org.apache.fop.render.AbstractRendererMaker#needsOutputStream() */
public boolean needsOutputStream() {
return true;
diff --git a/src/java/org/apache/fop/svg/PDFContext.java b/src/java/org/apache/fop/svg/PDFContext.java index 7f96fb060..494d47636 100644 --- a/src/java/org/apache/fop/svg/PDFContext.java +++ b/src/java/org/apache/fop/svg/PDFContext.java @@ -19,8 +19,6 @@ package org.apache.fop.svg; -import java.util.List; - import org.apache.fop.pdf.PDFPage; /** @@ -30,24 +28,10 @@ import org.apache.fop.pdf.PDFPage; public class PDFContext { private PDFPage currentPage; - private List fontList; /** number of pages generated */ private int pagecount; - /** - * Sets the font list as creates by the FontSetup class. - * @param list the font list - */ - public void setFontList(List list) { - this.fontList = list; - } - - /** @return the font list */ - public List getFontList() { - return this.fontList; - } - /** @return true if a page is set up for painting. */ public boolean isPagePending() { return this.currentPage != null; diff --git a/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java b/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java index 0e699dec7..9c72ade1a 100644 --- a/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java +++ b/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java @@ -19,6 +19,7 @@ package org.apache.fop.svg; +import org.apache.fop.Version; import org.apache.fop.pdf.PDFDocument; import org.apache.fop.pdf.PDFFilterList; import org.apache.fop.pdf.PDFPage; @@ -28,13 +29,8 @@ import org.apache.fop.pdf.PDFNumber; import org.apache.fop.pdf.PDFResources; import org.apache.fop.pdf.PDFColor; import org.apache.fop.pdf.PDFAnnotList; -import org.apache.fop.fonts.FontSetup; import org.apache.fop.fonts.FontInfo; -import org.apache.avalon.framework.CascadingRuntimeException; -import org.apache.avalon.framework.activity.Initializable; -import org.apache.avalon.framework.configuration.Configurable; -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.fop.fonts.FontSetup; import java.awt.Graphics; import java.awt.Font; @@ -56,8 +52,7 @@ import java.io.StringWriter; * @version $Id$ * @see org.apache.fop.svg.PDFGraphics2D */ -public class PDFDocumentGraphics2D extends PDFGraphics2D - implements Configurable, Initializable { +public class PDFDocumentGraphics2D extends PDFGraphics2D { private PDFContext pdfContext; @@ -89,9 +84,6 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D */ protected AffineTransform initialTransform; - //Avalon component - private Configuration cfg; - /** * Create a new PDFDocumentGraphics2D. * This is used to create a new pdf document, the height, @@ -106,19 +98,9 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D public PDFDocumentGraphics2D(boolean textAsShapes) { super(textAsShapes); + this.pdfDoc = new PDFDocument("Apache FOP Version " + Version.getVersion() + + ": PDFDocumentGraphics2D"); this.pdfContext = new PDFContext(); - if (!textAsShapes) { - fontInfo = new FontInfo(); - FontSetup.setup(fontInfo, null, null); - //FontState fontState = new FontState("Helvetica", "normal", - // FontInfo.NORMAL, 12, 0); - } - try { - initialize(); - } catch (Exception e) { - //Should never happen - throw new CascadingRuntimeException("Internal error", e); - } } /** @@ -154,33 +136,6 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D } /** - * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration) - */ - public void configure(Configuration cfg) throws ConfigurationException { - this.cfg = cfg; - this.pdfContext.setFontList(FontSetup.buildFontListFromConfiguration(cfg)); - } - - /** - * @see org.apache.avalon.framework.activity.Initializable#initialize() - */ - public void initialize() throws Exception { - if (this.fontInfo == null || this.cfg != null) { - fontInfo = new FontInfo(); - FontSetup.setup(fontInfo, this.pdfContext.getFontList(), null); - //FontState fontState = new FontState("Helvetica", "normal", - // FontInfo.NORMAL, 12, 0); - } - - this.pdfDoc = new PDFDocument("Apache FOP: SVG to PDF Transcoder"); - - if (this.cfg != null) { - this.pdfDoc.setFilterMap( - PDFFilterList.buildFilterMapFromConfiguration(cfg)); - } - } - - /** * Setup the document. * @param stream the output stream to write the document * @param width the width of the page @@ -197,6 +152,18 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D } /** + * Setup a default FontInfo instance if none has been setup before. + */ + public void setupDefaultFontInfo() { + if (fontInfo == null) { + //Default minimal fonts + FontInfo fontInfo = new FontInfo(); + FontSetup.setup(fontInfo, null, null); + setFontInfo(fontInfo); + } + } + + /** * Set the device resolution for rendering. Will take effect at the * start of the next page. * @param deviceDPI the device resolution (in dpi) @@ -213,6 +180,14 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D } /** + * Sets the font info for this PDF document. + * @param fontInfo the font info object with all the fonts + */ + public void setFontInfo(FontInfo fontInfo) { + this.fontInfo = fontInfo; + } + + /** * Get the font info for this pdf document. * @return the font information */ @@ -229,6 +204,14 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D } /** + * Return the PDFContext for this instance. + * @return the PDFContext + */ + public PDFContext getPDFContext() { + return this.pdfContext; + } + + /** * Set the dimensions of the svg document that will be drawn. * This is useful if the dimensions of the svg document are different * from the pdf document that is to be created. @@ -295,6 +278,10 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D if (pdfContext.isPagePending()) { return; } + //Setup default font info if no more font configuration has been done by the user. + if (!this.textAsShapes && getFontInfo() == null) { + setupDefaultFontInfo(); + } try { startPage(); } catch (IOException ioe) { @@ -389,7 +376,6 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D public PDFDocumentGraphics2D(PDFDocumentGraphics2D g) { super(g); this.pdfContext = g.pdfContext; - this.cfg = g.cfg; this.width = g.width; this.height = g.height; this.svgWidth = g.svgWidth; diff --git a/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java b/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java new file mode 100644 index 000000000..fe4d50a4a --- /dev/null +++ b/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java @@ -0,0 +1,66 @@ +/* + * 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.svg; + +import java.util.List; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.fop.apps.FOPException; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontResolver; +import org.apache.fop.fonts.FontSetup; +import org.apache.fop.pdf.PDFDocument; +import org.apache.fop.render.PrintRendererConfigurator; +import org.apache.fop.render.pdf.PDFRendererConfigurator; + +/** + * Configurator class for PDFDocumentGraphics2D. + */ +public class PDFDocumentGraphics2DConfigurator { + + /** + * Configures a PDFDocumentGraphics2D instance using an Avalon Configuration object. + * @param graphics the PDFDocumentGraphics2D instance + * @param cfg the configuration + * @throws ConfigurationException if an error occurs while configuring the object + */ + public void configure(PDFDocumentGraphics2D graphics, Configuration cfg) + throws ConfigurationException { + PDFDocument pdfDoc = graphics.getPDFDocument(); + + //Filter map + pdfDoc.setFilterMap( + PDFRendererConfigurator.buildFilterMapFromConfiguration(cfg)); + + //Fonts + try { + FontResolver fontResolver = FontSetup.createMinimalFontResolver(); + List fontList = PrintRendererConfigurator.buildFontListFromConfiguration( + cfg, null, fontResolver, false, null); + FontInfo fontInfo = new FontInfo(); + FontSetup.setup(fontInfo, fontList, fontResolver); + graphics.setFontInfo(fontInfo); + } catch (FOPException e) { + throw new ConfigurationException("Error while setting up fonts", e); + } + } + +} diff --git a/src/java/org/apache/fop/svg/PDFGraphics2D.java b/src/java/org/apache/fop/svg/PDFGraphics2D.java index 254a93cba..3902b30fd 100644 --- a/src/java/org/apache/fop/svg/PDFGraphics2D.java +++ b/src/java/org/apache/fop/svg/PDFGraphics2D.java @@ -1429,7 +1429,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { } float siz = gFont.getSize2D(); String style = gFont.isItalic() ? "italic" : "normal"; - int weight = gFont.isBold() ? Font.BOLD : Font.NORMAL; + int weight = gFont.isBold() ? Font.WEIGHT_BOLD : Font.WEIGHT_NORMAL; FontTriplet triplet = fontInfo.fontLookup(n, style, weight); fontState = fontInfo.getFontInstance(triplet, (int)(siz * 1000 + 0.5)); } else { diff --git a/src/java/org/apache/fop/svg/PDFTextElementBridge.java b/src/java/org/apache/fop/svg/PDFTextElementBridge.java index cf9b7b7bd..100711eb9 100644 --- a/src/java/org/apache/fop/svg/PDFTextElementBridge.java +++ b/src/java/org/apache/fop/svg/PDFTextElementBridge.java @@ -22,7 +22,6 @@ package org.apache.fop.svg; import org.apache.batik.gvt.TextNode; import org.apache.batik.bridge.SVGTextElementBridge; import org.apache.batik.bridge.BridgeContext; -import org.apache.batik.bridge.TextUtilities; import org.apache.batik.gvt.GraphicsNode; import org.apache.fop.fonts.FontInfo; @@ -82,12 +81,16 @@ public class PDFTextElementBridge extends SVGTextElementBridge { * easily rendered using normal drawString on the PDFGraphics2D */ private boolean isSimple(BridgeContext ctx, Element element, GraphicsNode node) { + /* I cannot find any reference that 36pt is the maximum font size in PDF. Tests show + * no such restriction (jeremias, 28.5.2007) + * // Font size, in user space units. float fs = TextUtilities.convertFontSize(element).floatValue(); // PDF cannot display fonts over 36pt if (fs > 36) { return false; } + */ Element nodeElement; for (Node n = element.getFirstChild(); diff --git a/src/java/org/apache/fop/svg/PDFTextPainter.java b/src/java/org/apache/fop/svg/PDFTextPainter.java index eddd89d09..f05d5ae4f 100644 --- a/src/java/org/apache/fop/svg/PDFTextPainter.java +++ b/src/java/org/apache/fop/svg/PDFTextPainter.java @@ -160,8 +160,8 @@ public class PDFTextPainter implements TextPainter { String style = ((posture != null) && (posture.floatValue() > 0.0)) ? "italic" : "normal"; int weight = ((taWeight != null) - && (taWeight.floatValue() > 1.0)) ? Font.BOLD - : Font.NORMAL; + && (taWeight.floatValue() > 1.0)) ? Font.WEIGHT_BOLD + : Font.WEIGHT_NORMAL; Font fontState = null; FontInfo fi = fontInfo; @@ -187,7 +187,7 @@ public class PDFTextPainter implements TextPainter { } } if (!found) { - FontTriplet triplet = fontInfo.fontLookup("any", style, Font.NORMAL); + FontTriplet triplet = fontInfo.fontLookup("any", style, Font.WEIGHT_NORMAL); int fsize = (int)(size.floatValue() * 1000); fontState = fontInfo.getFontInstance(triplet, fsize); } else { @@ -196,7 +196,7 @@ public class PDFTextPainter implements TextPainter { } } int fStyle = java.awt.Font.PLAIN; - if (weight == Font.BOLD) { + if (weight == Font.WEIGHT_BOLD) { if (style.equals("italic")) { fStyle = java.awt.Font.BOLD | java.awt.Font.ITALIC; } else { diff --git a/src/java/org/apache/fop/svg/PDFTranscoder.java b/src/java/org/apache/fop/svg/PDFTranscoder.java index a90765a31..f6a986d0c 100644 --- a/src/java/org/apache/fop/svg/PDFTranscoder.java +++ b/src/java/org/apache/fop/svg/PDFTranscoder.java @@ -25,7 +25,6 @@ import java.io.IOException; import org.apache.avalon.framework.configuration.Configurable; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; -import org.apache.avalon.framework.container.ContainerUtil; import org.apache.batik.bridge.BridgeContext; import org.apache.batik.bridge.UnitProcessor; import org.apache.batik.bridge.UserAgent; @@ -35,6 +34,9 @@ import org.apache.batik.transcoder.TranscoderOutput; import org.apache.batik.transcoder.TranscodingHints; import org.apache.batik.transcoder.image.ImageTranscoder; import org.apache.batik.transcoder.keys.FloatKey; +import org.apache.fop.Version; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontSetup; import org.w3c.dom.Document; import org.w3c.dom.svg.SVGLength; @@ -120,12 +122,16 @@ public class PDFTranscoder extends AbstractFOPTranscoder throws TranscoderException { graphics = new PDFDocumentGraphics2D(); + graphics.getPDFDocument().getInfo().setProducer("Apache FOP Version " + + Version.getVersion() + + ": PDF Transcoder for Batik"); try { if (this.cfg != null) { - ContainerUtil.configure(graphics, this.cfg); + PDFDocumentGraphics2DConfigurator configurator + = new PDFDocumentGraphics2DConfigurator(); + configurator.configure(graphics, this.cfg); } - ContainerUtil.initialize(graphics); } catch (Exception e) { throw new TranscoderException( "Error while setting up PDFDocumentGraphics2D", e); @@ -133,7 +139,9 @@ public class PDFTranscoder extends AbstractFOPTranscoder super.transcode(document, uri, output); - getLogger().trace("document size: " + width + " x " + height); + if (getLogger().isTraceEnabled()) { + getLogger().trace("document size: " + width + " x " + height); + } // prepare the image to be painted UnitProcessor.Context uctx = UnitProcessor.createContext(ctx, @@ -144,7 +152,9 @@ public class PDFTranscoder extends AbstractFOPTranscoder float heightInPt = UnitProcessor.userSpaceToSVG(height, SVGLength.SVG_LENGTHTYPE_PT, UnitProcessor.HORIZONTAL_LENGTH, uctx); int h = (int)(heightInPt + 0.5); - getLogger().trace("document size: " + w + "pt x " + h + "pt"); + if (getLogger().isTraceEnabled()) { + getLogger().trace("document size: " + w + "pt x " + h + "pt"); + } // prepare the image to be painted //int w = (int)(width + 0.5); diff --git a/src/java/org/apache/fop/util/LogUtil.java b/src/java/org/apache/fop/util/LogUtil.java new file mode 100644 index 000000000..60eafb51a --- /dev/null +++ b/src/java/org/apache/fop/util/LogUtil.java @@ -0,0 +1,57 @@ +/* + * 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.util; + +import org.apache.commons.logging.Log; +import org.apache.fop.apps.FOPException; + +/** + * Convenience Logging utility methods used in FOP + */ +public class LogUtil { + + /** + * Convenience method that handles any error appropriately + * @param log log + * @param errorStr error string + * @param strict validate strictly + * @throws FOPException fop exception + */ + public static void handleError(Log log, String errorStr, boolean strict) throws FOPException { + handleException(log, new FOPException(errorStr), strict); + } + + /** + * Convenience method that handles any error appropriately + * @param log log + * @param e exception + * @param strict validate strictly + * @throws FOPException fop exception + */ + public static void handleException(Log log, Exception e, boolean strict) throws FOPException { + if (strict) { + if (e instanceof FOPException) { + throw (FOPException)e; + } + throw new FOPException(e); + } + log.error(e.getMessage()); + } +} |