diff options
author | Adrian Cumiskey <acumiskey@apache.org> | 2009-03-20 15:18:54 +0000 |
---|---|---|
committer | Adrian Cumiskey <acumiskey@apache.org> | 2009-03-20 15:18:54 +0000 |
commit | 6caf23b89cd7ec194aa91126bd5691cde323e9ae (patch) | |
tree | d7256c2a4add35f7e9dc8463f3c8b6162df9efc7 /src | |
parent | 41850c971a518fbf1662199518143c8581f179c8 (diff) | |
download | xmlgraphics-fop-6caf23b89cd7ec194aa91126bd5691cde323e9ae.tar.gz xmlgraphics-fop-6caf23b89cd7ec194aa91126bd5691cde323e9ae.zip |
A little font configuration cleaning.
* Extracted business logic from PrintRendererConfigurator and created a new FontDetector and FontAdder in org.apache.fop.fonts package.
* Created a new FontInfoConfigurator that factors out a lot of the static stuff in PrintRendererConfigurator.
* PDFDocumentGraphics2DConfigurator now uses a new FontInfoConfigurator() instead of static PrintRendererConfigurator.buildFontListFromConfiguration() call.
* static method updateReferencedFonts() in PrintRendererConfigurator moved to an instance method in FontManager.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@756522 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
8 files changed, 630 insertions, 407 deletions
diff --git a/src/java/org/apache/fop/fonts/FontAdder.java b/src/java/org/apache/fop/fonts/FontAdder.java new file mode 100644 index 000000000..0d6a730cf --- /dev/null +++ b/src/java/org/apache/fop/fonts/FontAdder.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.fonts; + +import java.net.URL; +import java.util.Iterator; +import java.util.List; + +import org.apache.fop.fonts.autodetect.FontInfoFinder; + +/** + * Adds a list of fonts to a given font info list + */ +public class FontAdder { + private FontEventListener listener; + private FontResolver resolver; + private FontManager manager; + + /** + * Main constructor + * @param manager a font manager + * @param resolver a font resolver + * @param listener a font event handler + */ + public FontAdder(FontManager manager, FontResolver resolver, FontEventListener listener) { + this.manager = manager; + this.resolver = resolver; + this.listener = listener; + } + + /** + * Iterates over font url list adding to font info list + * @param fontURLList font file list + * @param fontInfoList a configured font info list + */ + public void add(List/*<URL>*/ fontURLList, List/*<EmbedFontInfo>*/ fontInfoList) { + FontCache cache = manager.getFontCache(); + FontInfoFinder finder = new FontInfoFinder(); + finder.setEventListener(listener); + + for (Iterator iter = fontURLList.iterator(); iter.hasNext();) { + URL fontUrl = (URL)iter.next(); + EmbedFontInfo[] embedFontInfos = finder.find(fontUrl, resolver, cache); + if (embedFontInfos == null) { + continue; + } + for (int i = 0, c = embedFontInfos.length; i < c; i++) { + EmbedFontInfo fontInfo = embedFontInfos[i]; + if (fontInfo != null) { + fontInfoList.add(fontInfo); + } + } + } + } +} diff --git a/src/java/org/apache/fop/fonts/FontDetector.java b/src/java/org/apache/fop/fonts/FontDetector.java new file mode 100644 index 000000000..09671f1f8 --- /dev/null +++ b/src/java/org/apache/fop/fonts/FontDetector.java @@ -0,0 +1,101 @@ +/* + * 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.net.URL; +import java.util.List; + +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.fonts.autodetect.FontFileFinder; +import org.apache.fop.util.LogUtil; +import org.apache.xmlgraphics.util.ClasspathResource; + +/** + * Detector of operating system and classpath fonts + */ +public class FontDetector { + private static Log log = LogFactory.getLog(FontDetector.class); + + private static final String[] FONT_MIMETYPES = { + "application/x-font", "application/x-font-truetype" + }; + + private FontManager fontManager; + private FontAdder fontAdder; + private boolean strict; + + /** + * Main constructor + * @param manager the font manager + * @param adder the font adder + * @param strict true if an Exception should be thrown if an error is found. + */ + public FontDetector(FontManager manager, FontAdder adder, boolean strict) { + this.fontManager = manager; + this.fontAdder = adder; + this.strict = strict; + } + + /** + * Detect installed fonts on the system + * @param fontInfoList a list of fontinfo to populate + * @throws FOPException thrown if a problem occurred during detection + */ + public void detect(List/*<EmbedFontInfo>*/ fontInfoList) throws FOPException { + // search in font base if it is defined and + // is a directory but don't recurse + FontFileFinder fontFileFinder = new FontFileFinder(); + String fontBaseURL = fontManager.getFontBaseURL(); + if (fontBaseURL != null) { + try { + File fontBase = FileUtils.toFile(new URL(fontBaseURL)); + if (fontBase != null) { + List/*<URL>*/ fontURLList = fontFileFinder.find( + fontBase.getAbsolutePath()); + fontAdder.add(fontURLList, fontInfoList); + + //Can only use the font base URL if it's a file URL + } + } catch (IOException e) { + LogUtil.handleException(log, e, strict); + } + } + + // native o/s font directory finding + List/*<URL>*/ systemFontList; + try { + systemFontList = fontFileFinder.find(); + fontAdder.add(systemFontList, fontInfoList); + } catch (IOException e) { + LogUtil.handleException(log, e, strict); + } + + // classpath font finding + ClasspathResource resource = ClasspathResource.getInstance(); + for (int i = 0; i < FONT_MIMETYPES.length; i++) { + fontAdder.add(resource.listResourcesOfMimeType(FONT_MIMETYPES[i]), fontInfoList); + } + } +} diff --git a/src/java/org/apache/fop/fonts/FontInfoConfigurator.java b/src/java/org/apache/fop/fonts/FontInfoConfigurator.java new file mode 100644 index 000000000..fe0ca85cd --- /dev/null +++ b/src/java/org/apache/fop/fonts/FontInfoConfigurator.java @@ -0,0 +1,310 @@ +/* + * 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.net.MalformedURLException; +import java.net.URL; +import java.util.List; + +import javax.xml.transform.Source; +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.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.apps.FOPException; +import org.apache.fop.fonts.autodetect.FontFileFinder; +import org.apache.fop.fonts.autodetect.FontInfoFinder; +import org.apache.fop.util.LogUtil; + +/** + * An abstract FontInfo configurator + */ +public class FontInfoConfigurator { + /** logger instance */ + protected static Log log = LogFactory.getLog(FontInfoConfigurator.class); + + private Configuration cfg; + private FontManager fontManager; + private FontResolver fontResolver; + private FontEventListener listener; + private boolean strict; + + /** + * Main constructor + * @param cfg the configuration object + * @param fontManager the font manager + * @param fontResolver the font resolver + * @param listener the font event listener + * @param strict true if an Exception should be thrown if an error is found. + */ + public FontInfoConfigurator(Configuration cfg, FontManager fontManager, + FontResolver fontResolver, FontEventListener listener, boolean strict) { + this.cfg = cfg; + this.fontManager = fontManager; + this.fontResolver = fontResolver; + this.listener = listener; + this.strict = strict; + } + + /** + * Initializes font info settings from the user configuration + * @param fontInfoList a font info list + * @throws FOPException if an exception occurs while processing the configuration + */ + public void configure(List/*<EmbedFontInfo>*/ fontInfoList) throws FOPException { + FontCache fontCache = fontManager.getFontCache(); + String fontBaseURL = fontManager.getFontBaseURL(); + + Configuration fonts = cfg.getChild("fonts", false); + if (fonts != null) { + long start = 0; + if (log.isDebugEnabled()) { + log.debug("Starting font configuration..."); + start = System.currentTimeMillis(); + } + + FontAdder fontAdder = new FontAdder(fontManager, fontResolver, listener); + + // native o/s search (autodetect) configuration + boolean autodetectFonts = (fonts.getChild("auto-detect", false) != null); + if (autodetectFonts) { + FontDetector fontDetector = new FontDetector(fontManager, fontAdder, strict); + fontDetector.detect(fontInfoList); + } + + // Add configured directories to FontInfo + addDirectories(fonts, fontAdder, fontInfoList); + + // Add configured fonts to FontInfo + addFonts(fonts, fontCache, fontInfoList); + + // Update referenced fonts (fonts which are not to be embedded) + fontManager.updateReferencedFonts(fontInfoList); + + if (log.isDebugEnabled()) { + log.debug("Finished font configuration in " + + (System.currentTimeMillis() - start) + "ms"); + } + } + } + + private void addDirectories(Configuration fontsCfg, + FontAdder fontAdder, List/*<URL>*/ fontInfoList) throws FOPException { + // directory (multiple font) configuration + Configuration[] directories = fontsCfg.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; + } + + // add fonts found in directory + FontFileFinder fontFileFinder = new FontFileFinder(recursive ? -1 : 1); + List/*<URL>*/ fontURLList; + try { + fontURLList = fontFileFinder.find(directory); + fontAdder.add(fontURLList, fontInfoList); + } catch (IOException e) { + LogUtil.handleException(log, e, strict); + } + } + } + + /** + * Populates the font info list from the fonts configuration + * @param fontsCfg a fonts configuration + * @param fontCache a font cache + * @param fontInfoList a font info list + * @throws FOPException if an exception occurs while processing the configuration + */ + protected void addFonts(Configuration fontsCfg, FontCache fontCache, + List/*<EmbedFontInfo>*/ fontInfoList) throws FOPException { + // font file (singular) configuration + Configuration[] font = fontsCfg.getChildren("font"); + for (int i = 0; i < font.length; i++) { + EmbedFontInfo embedFontInfo = getFontInfo( + font[i], fontCache); + if (embedFontInfo != null) { + fontInfoList.add(embedFontInfo); + } + } + } + + private static void closeSource(Source src) { + if (src instanceof StreamSource) { + StreamSource streamSource = (StreamSource)src; + IOUtils.closeQuietly(streamSource.getInputStream()); + IOUtils.closeQuietly(streamSource.getReader()); + } + } + + /** + * Returns a font info from a font node Configuration definition + * + * @param fontCfg Configuration object (font node) + * @param fontCache the font cache (or null if it is disabled) + * @return the embedded font info + * @throws FOPException if something's wrong with the config data + */ + protected EmbedFontInfo getFontInfo( + Configuration fontCfg, FontCache fontCache) + throws FOPException { + String metricsUrl = fontCfg.getAttribute("metrics-url", null); + String embedUrl = fontCfg.getAttribute("embed-url", null); + String subFont = fontCfg.getAttribute("sub-font", null); + + if (metricsUrl == null && embedUrl == null) { + LogUtil.handleError(log, + "Font configuration without metric-url or embed-url attribute", + strict); + return null; + } + if (strict) { + //This section just checks early whether the URIs can be resolved + //Stream are immediately closed again since they will never be used anyway + if (embedUrl != null) { + Source source = fontResolver.resolve(embedUrl); + closeSource(source); + if (source == null) { + LogUtil.handleError(log, + "Failed to resolve font with embed-url '" + embedUrl + "'", strict); + return null; + } + } + if (metricsUrl != null) { + Source source = fontResolver.resolve(metricsUrl); + closeSource(source); + if (source == null) { + LogUtil.handleError(log, + "Failed to resolve font with metric-url '" + metricsUrl + "'", strict); + return null; + } + } + } + + Configuration[] tripletCfg = fontCfg.getChildren("font-triplet"); + + // no font triplet info + if (tripletCfg.length == 0) { + LogUtil.handleError(log, "font without font-triplet", strict); + + File fontFile = FontCache.getFileFromUrls(new String[] {embedUrl, metricsUrl}); + URL fontUrl; + try { + fontUrl = fontFile.toURI().toURL(); + } catch (MalformedURLException e) { + // Should never happen + log.debug("Malformed Url: " + e.getMessage()); + return null; + } + if (fontFile != null) { + FontInfoFinder finder = new FontInfoFinder(); + finder.setEventListener(listener); + EmbedFontInfo[] infos = finder.find(fontUrl, fontResolver, fontCache); + return infos[0]; //When subFont is set, only one font is returned + } else { + return null; + } + } + + List/*<FontTriplet>*/ tripletList = new java.util.ArrayList/*<FontTriplet>*/(); + for (int j = 0; j < tripletCfg.length; j++) { + FontTriplet fontTriplet = getFontTriplet(tripletCfg[j]); + tripletList.add(fontTriplet); + } + + boolean useKerning = fontCfg.getAttributeAsBoolean("kerning", true); + EncodingMode encodingMode = EncodingMode.valueOf( + fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName())); + EmbedFontInfo embedFontInfo + = new EmbedFontInfo(metricsUrl, useKerning, tripletList, embedUrl, subFont); + embedFontInfo.setEncodingMode(encodingMode); + if (fontCache != null) { + if (!fontCache.containsFont(embedFontInfo)) { + fontCache.addFont(embedFontInfo); + } + } + + if (log.isDebugEnabled()) { + String embedFile = embedFontInfo.getEmbedFile(); + log.debug("Adding font " + (embedFile != null ? embedFile + ", " : "") + + "metric file " + embedFontInfo.getMetricsFile()); + for (int j = 0; j < tripletList.size(); ++j) { + FontTriplet triplet = (FontTriplet) tripletList.get(j); + log.debug(" Font triplet " + + triplet.getName() + ", " + + triplet.getStyle() + ", " + + triplet.getWeight()); + } + } + return embedFontInfo; + } + + /** + * Creates a new FontTriplet given a triple Configuration + * + * @param tripletCfg a triplet configuration + * @return a font triplet font key + * @throws FOPException thrown if a FOP exception occurs + */ + private FontTriplet getFontTriplet(Configuration tripletCfg) throws FOPException { + try { + String name = tripletCfg.getAttribute("name"); + if (name == null) { + LogUtil.handleError(log, "font-triplet without name", strict); + return null; + } + + String weightStr = tripletCfg.getAttribute("weight"); + if (weightStr == null) { + LogUtil.handleError(log, "font-triplet without weight", strict); + return null; + } + int weight = FontUtil.parseCSS2FontWeight(FontUtil.stripWhiteSpace(weightStr)); + + String style = tripletCfg.getAttribute("style"); + if (style == null) { + LogUtil.handleError(log, "font-triplet without style", strict); + return null; + } else { + style = FontUtil.stripWhiteSpace(style); + } + return FontInfo.createFontKey(name, style, weight); + } catch (ConfigurationException e) { + LogUtil.handleException(log, e, strict); + } + return null; + } + +} diff --git a/src/java/org/apache/fop/fonts/FontManager.java b/src/java/org/apache/fop/fonts/FontManager.java index b3833cf50..daf0a0cdb 100644 --- a/src/java/org/apache/fop/fonts/FontManager.java +++ b/src/java/org/apache/fop/fonts/FontManager.java @@ -20,6 +20,8 @@ package org.apache.fop.fonts; import java.net.MalformedURLException; +import java.util.Iterator; +import java.util.List; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; @@ -186,4 +188,27 @@ public class FontManager { public Matcher getReferencedFontsMatcher() { return this.referencedFontsMatcher; } + + /** + * Updates the referenced font list + * @param fontInfoList a font info list + */ + public void updateReferencedFonts(List fontInfoList) { + Matcher matcher = getReferencedFontsMatcher(); + if (matcher == null) { + return; //No referenced fonts + } + Iterator iter = fontInfoList.iterator(); + while (iter.hasNext()) { + EmbedFontInfo fontInfo = (EmbedFontInfo)iter.next(); + Iterator triplets = fontInfo.getFontTriplets().iterator(); + while (triplets.hasNext()) { + FontTriplet triplet = (FontTriplet)triplets.next(); + if (matcher.matches(triplet)) { + fontInfo.setEmbedded(false); + break; + } + } + } + } } diff --git a/src/java/org/apache/fop/render/AbstractConfigurator.java b/src/java/org/apache/fop/render/AbstractConfigurator.java new file mode 100644 index 000000000..b1ac1c61a --- /dev/null +++ b/src/java/org/apache/fop/render/AbstractConfigurator.java @@ -0,0 +1,89 @@ +/* + * 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; + +/** + * An abstract configurator + */ +public abstract class AbstractConfigurator { + /** logger instance */ + protected static Log log = LogFactory.getLog(AbstractConfigurator.class); + + private static final String MIME = "mime"; + + /** fop factory configuration */ + protected FOUserAgent userAgent = null; + + /** + * Default constructor + * @param userAgent user agent + */ + public AbstractConfigurator(FOUserAgent userAgent) { + super(); + this.userAgent = userAgent; + } + + /** + * Returns the configuration subtree for a specific renderer. + * @param mimeType the MIME type of the renderer + * @return the requested configuration subtree, null if there's no configuration + */ + protected Configuration getConfig(String mimeType) { + Configuration cfg = userAgent.getFactory().getUserConfig(); + if (cfg == null) { + if (log.isDebugEnabled()) { + log.debug("userconfig is null"); + } + return null; + } + + Configuration userConfig = null; + + String type = getType(); + Configuration[] cfgs + = cfg.getChild(type + "s").getChildren(type); + for (int i = 0; i < cfgs.length; ++i) { + Configuration child = cfgs[i]; + try { + if (child.getAttribute(MIME).equals(mimeType)) { + userConfig = child; + break; + } + } catch (ConfigurationException e) { + // silently pass over configurations without mime type + } + } + log.debug((userConfig == null ? "No u" : "U") + + "ser configuration found for MIME type " + mimeType); + return userConfig; + } + + /** + * Returns the configurator type + * @return the configurator type + */ + public abstract String getType(); +} diff --git a/src/java/org/apache/fop/render/AbstractRendererConfigurator.java b/src/java/org/apache/fop/render/AbstractRendererConfigurator.java index 09540dfbb..b31e5bfe6 100644 --- a/src/java/org/apache/fop/render/AbstractRendererConfigurator.java +++ b/src/java/org/apache/fop/render/AbstractRendererConfigurator.java @@ -20,31 +20,22 @@ 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; +public abstract class AbstractRendererConfigurator extends AbstractConfigurator { + private static final String TYPE = "renderer"; + /** * Default constructor * @param userAgent user agent */ public AbstractRendererConfigurator(FOUserAgent userAgent) { - super(); - this.userAgent = userAgent; + super(userAgent); } /** @@ -53,15 +44,7 @@ public abstract class AbstractRendererConfigurator { * @return the requested configuration subtree, null if there's no configuration */ protected Configuration getRendererConfig(Renderer renderer) { - String mimeType = renderer.getMimeType(); - if (mimeType == null) { - if (log.isInfoEnabled()) { - log.info("renderer mimeType is null"); - } - return null; - } - - return getRendererConfig(mimeType); + return super.getConfig(renderer.getMimeType()); } /** @@ -70,31 +53,14 @@ public abstract class AbstractRendererConfigurator { * @return the requested configuration subtree, null if there's no configuration */ protected Configuration getRendererConfig(String mimeType) { - Configuration cfg = userAgent.getFactory().getUserConfig(); - if (cfg == null) { - if (log.isDebugEnabled()) { - log.debug("userconfig 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; + return super.getConfig(mimeType); } + + /** + * {@inheritDoc} + */ + public String getType() { + return TYPE; + } + } diff --git a/src/java/org/apache/fop/render/PrintRendererConfigurator.java b/src/java/org/apache/fop/render/PrintRendererConfigurator.java index 3f5a2eb39..26c34585e 100644 --- a/src/java/org/apache/fop/render/PrintRendererConfigurator.java +++ b/src/java/org/apache/fop/render/PrintRendererConfigurator.java @@ -19,42 +19,24 @@ package org.apache.fop.render; -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Iterator; import java.util.List; -import javax.xml.transform.Source; -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.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.xmlgraphics.util.ClasspathResource; - import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FopFactory; import org.apache.fop.fonts.CustomFontCollection; -import org.apache.fop.fonts.EmbedFontInfo; -import org.apache.fop.fonts.EncodingMode; import org.apache.fop.fonts.FontCache; import org.apache.fop.fonts.FontCollection; import org.apache.fop.fonts.FontEventAdapter; import org.apache.fop.fonts.FontEventListener; import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontInfoConfigurator; import org.apache.fop.fonts.FontManager; import org.apache.fop.fonts.FontResolver; -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.fonts.base14.Base14FontCollection; import org.apache.fop.render.intermediate.IFDocumentHandler; import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; @@ -96,7 +78,7 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator FontEventListener listener = new FontEventAdapter( renderer.getUserAgent().getEventBroadcaster()); - List embedFontInfoList = buildFontList(cfg, fontResolver, listener); + List/*<EmbedFontInfo>*/ embedFontInfoList = buildFontList(cfg, fontResolver, listener); printRenderer.addFontList(embedFontInfoList); } @@ -108,7 +90,7 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator * @return the list of {@code EmbedFontInfo} objects * @throws FOPException if an error occurs while processing the configuration */ - protected List buildFontList(Configuration cfg, FontResolver fontResolver, + protected List/*<EmbedFontInfo>*/ buildFontList(Configuration cfg, FontResolver fontResolver, FontEventListener listener) throws FOPException { FopFactory factory = userAgent.getFactory(); FontManager fontManager = factory.getFontManager(); @@ -120,344 +102,18 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator boolean strict = factory.validateUserConfigStrictly(); FontCache fontCache = fontManager.getFontCache(); - List/*<EmbedFontInfo>*/ embedFontInfoList = buildFontListFromConfiguration(cfg, - fontResolver, strict, fontManager, listener); + //Read font configuration + FontInfoConfigurator fontInfoConfigurator + = new FontInfoConfigurator(cfg, fontManager, fontResolver, listener, strict); + List/*<EmbedFontInfo>*/ fontInfoList = new java.util.ArrayList/*<EmbedFontInfo>*/(); + fontInfoConfigurator.configure(fontInfoList); if (fontCache != null && fontCache.hasChanged()) { fontCache.save(); } - return embedFontInfoList; - } - - /** - * Builds a list of EmbedFontInfo objects for use with the setup() method. - * - * @param cfg Configuration object - * @param fontResolver the FontResolver to use - * @param strict true if an Exception should be thrown if an error is found. - * @param fontManager the font manager - * @param listener a font event listener - * @return a List of EmbedFontInfo objects. - * @throws FOPException If an error occurs while processing the configuration - */ - public static List/*<EmbedFontInfo>*/ buildFontListFromConfiguration(Configuration cfg, - FontResolver fontResolver, - boolean strict, FontManager fontManager, - FontEventListener listener) throws FOPException { - FontCache fontCache = fontManager.getFontCache(); - String fontBaseURL = fontManager.getFontBaseURL(); - List/*<EmbedFontInfo>*/ fontInfoList - = new java.util.ArrayList/*<EmbedFontInfo>*/(); - - Configuration fonts = cfg.getChild("fonts", false); - 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 (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, - listener - ); - } - } catch (IOException e) { - LogUtil.handleException(log, e, strict); - } - } - - // native o/s font directory finder - try { - addFontInfoListFromFileList( - fontFileFinder.find(), - fontInfoList, - fontResolver, - fontCache, - listener - ); - } catch (IOException e) { - LogUtil.handleException(log, e, strict); - } - - // load fonts from classpath - addFontInfoListFromFileList(ClasspathResource.getInstance() - .listResourcesOfMimeType("application/x-font"), - fontInfoList, fontResolver, fontCache, listener); - addFontInfoListFromFileList( - ClasspathResource.getInstance() - .listResourcesOfMimeType( - "application/x-font-truetype"), - fontInfoList, fontResolver, fontCache, listener); - } - - // 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, - listener - ); - } 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 embedFontInfo = getFontInfoFromConfiguration( - font[i], fontResolver, strict, fontCache, listener); - if (embedFontInfo != null) { - fontInfoList.add(embedFontInfo); - } - } - - // Update referenced fonts (fonts which are not to be embedded) - updateReferencedFonts(fontInfoList, fontManager.getReferencedFontsMatcher()); - - if (log.isDebugEnabled()) { - log.debug("Finished font configuration in " - + (System.currentTimeMillis() - start) + "ms"); - } - } return fontInfoList; } - - private static void updateReferencedFonts(List fontInfoList, FontTriplet.Matcher matcher) { - if (matcher == null) { - return; //No referenced fonts - } - Iterator iter = fontInfoList.iterator(); - while (iter.hasNext()) { - EmbedFontInfo fontInfo = (EmbedFontInfo)iter.next(); - Iterator triplets = fontInfo.getFontTriplets().iterator(); - while (triplets.hasNext()) { - FontTriplet triplet = (FontTriplet)triplets.next(); - if (matcher.matches(triplet)) { - fontInfo.setEmbedded(false); - break; - } - } - } - } - - - /** - * Iterates over font file list adding font info to list - * @param fontFileList font file list - * @param embedFontInfoList a configured font info list - * @param resolver font resolver - */ - private static void addFontInfoListFromFileList( - List fontFileList, List/*<EmbedFontInfo>*/ embedFontInfoList, - FontResolver resolver, FontCache fontCache, FontEventListener listener) { - for (Iterator iter = fontFileList.iterator(); iter.hasNext();) { - URL fontUrl = (URL)iter.next(); - // parse font to ascertain font info - FontInfoFinder finder = new FontInfoFinder(); - finder.setEventListener(listener); - //EmbedFontInfo fontInfo = finder.find(fontUrl, resolver, fontCache); - - //List<EmbedFontInfo> embedFontInfoList = finder.find(fontUrl, resolver, fontCache); - EmbedFontInfo[] embedFontInfos = finder.find(fontUrl, resolver, fontCache); - - if (embedFontInfos == null) { - continue; - } - - for (int i = 0, c = embedFontInfos.length; i < c; i++) { - EmbedFontInfo fontInfo = embedFontInfos[i]; - if (fontInfo != null) { - embedFontInfoList.add(fontInfo); - } - } - } - } - - private static void closeSource(Source src) { - if (src instanceof StreamSource) { - StreamSource streamSource = (StreamSource)src; - IOUtils.closeQuietly(streamSource.getInputStream()); - IOUtils.closeQuietly(streamSource.getReader()); - } - } - - /** - * Creates a new FontTriplet given a triple Configuration - * - * @param tripletCfg a triplet configuration - * @param strict use strict validation - * @return a font triplet font key - * @throws FOPException thrown if a FOP exception occurs - */ - private static FontTriplet getFontTripletFromConfiguration( - Configuration tripletCfg, boolean strict) throws FOPException { - try { - String name = tripletCfg.getAttribute("name"); - if (name == null) { - LogUtil.handleError(log, "font-triplet without name", strict); - return null; - } - - String weightStr = tripletCfg.getAttribute("weight"); - if (weightStr == null) { - LogUtil.handleError(log, "font-triplet without weight", strict); - return null; - } - int weight = FontUtil.parseCSS2FontWeight(FontUtil.stripWhiteSpace(weightStr)); - - String style = tripletCfg.getAttribute("style"); - if (style == null) { - LogUtil.handleError(log, "font-triplet without style", strict); - return null; - } else { - style = FontUtil.stripWhiteSpace(style); - } - return FontInfo.createFontKey(name, style, weight); - } catch (ConfigurationException e) { - LogUtil.handleException(log, e, strict); - } - return null; - } - - /** - * 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 the embedded font info - * @throws FOPException if something's wrong with the config data - */ - private static EmbedFontInfo getFontInfoFromConfiguration( - Configuration fontCfg, FontResolver fontResolver, boolean strict, - FontCache fontCache, FontEventListener listener) - throws FOPException { - String metricsUrl = fontCfg.getAttribute("metrics-url", null); - String embedUrl = fontCfg.getAttribute("embed-url", null); - String subFont = fontCfg.getAttribute("sub-font", null); - - if (metricsUrl == null && embedUrl == null) { - LogUtil.handleError(log, - "Font configuration without metric-url or embed-url attribute", - strict); - return null; - } - if (strict) { - //This section just checks early whether the URIs can be resolved - //Stream are immediately closed again since they will never be used anyway - if (embedUrl != null) { - Source source = fontResolver.resolve(embedUrl); - closeSource(source); - if (source == null) { - LogUtil.handleError(log, - "Failed to resolve font with embed-url '" + embedUrl + "'", strict); - return null; - } - } - if (metricsUrl != null) { - Source source = fontResolver.resolve(metricsUrl); - closeSource(source); - if (source == null) { - LogUtil.handleError(log, - "Failed to resolve font with metric-url '" + metricsUrl + "'", strict); - return null; - } - } - } - - Configuration[] tripletCfg = fontCfg.getChildren("font-triplet"); - - // no font triplet info - if (tripletCfg.length == 0) { - LogUtil.handleError(log, "font without font-triplet", strict); - - File fontFile = FontCache.getFileFromUrls(new String[] {embedUrl, metricsUrl}); - URL fontUrl; - try { - fontUrl = fontFile.toURI().toURL(); - } catch (MalformedURLException e) { - // Should never happen - log.debug("Malformed Url: " + e.getMessage()); - return null; - } - if (fontFile != null) { - FontInfoFinder finder = new FontInfoFinder(); - finder.setEventListener(listener); - EmbedFontInfo[] infos = finder.find(fontUrl, fontResolver, fontCache); - return infos[0]; //When subFont is set, only one font is returned - } else { - return null; - } - } - - List/*<FontTriplet>*/ tripletList = new java.util.ArrayList/*<FontTriplet>*/(); - for (int j = 0; j < tripletCfg.length; j++) { - FontTriplet fontTriplet = getFontTripletFromConfiguration(tripletCfg[j], strict); - tripletList.add(fontTriplet); - } - - boolean useKerning = fontCfg.getAttributeAsBoolean("kerning", true); - EncodingMode encodingMode = EncodingMode.valueOf( - fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName())); - EmbedFontInfo embedFontInfo - = new EmbedFontInfo(metricsUrl, useKerning, tripletList, embedUrl, subFont); - embedFontInfo.setEncodingMode(encodingMode); - if (fontCache != null) { - if (!fontCache.containsFont(embedFontInfo)) { - fontCache.addFont(embedFontInfo); - } - } - - if (log.isDebugEnabled()) { - String embedFile = embedFontInfo.getEmbedFile(); - log.debug("Adding font " + (embedFile != null ? embedFile + ", " : "") - + "metric file " + embedFontInfo.getMetricsFile()); - for (int j = 0; j < tripletList.size(); ++j) { - FontTriplet triplet = (FontTriplet) tripletList.get(j); - log.debug(" Font triplet " - + triplet.getName() + ", " - + triplet.getStyle() + ", " - + triplet.getWeight()); - } - } - return embedFontInfo; - } - + // ---=== IFDocumentHandler configuration ===--- /** {@inheritDoc} */ @@ -486,5 +142,4 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator new FontCollection[fontCollections.size()])); documentHandler.setFontInfo(fontInfo); } - } diff --git a/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java b/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java index 03ad4ee71..e101a9573 100644 --- a/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java +++ b/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java @@ -25,12 +25,13 @@ 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.FontEventListener; import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontInfoConfigurator; import org.apache.fop.fonts.FontManager; 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; /** @@ -61,15 +62,19 @@ public class PDFDocumentGraphics2DConfigurator { //TODO Make use of fontBaseURL, font substitution and referencing configuration //Requires a change to the expected configuration layout - List/*<EmbedFontInfo>*/ embedFontInfoList - = PrintRendererConfigurator.buildFontListFromConfiguration( - cfg, fontResolver, false, fontManager, null); //TODO Wire in the FontEventListener + final FontEventListener listener = null; + final boolean strict = false; + FontInfoConfigurator fontInfoConfigurator + = new FontInfoConfigurator(cfg, fontManager, fontResolver, listener, strict); + List/*<EmbedFontInfo>*/ fontInfoList = new java.util.ArrayList/*<EmbedFontInfo>*/(); + fontInfoConfigurator.configure(fontInfoList); + if (fontManager.useCache()) { fontManager.getFontCache().save(); } FontInfo fontInfo = new FontInfo(); - FontSetup.setup(fontInfo, embedFontInfoList, fontResolver); + FontSetup.setup(fontInfo, fontInfoList, fontResolver); graphics.setFontInfo(fontInfo); } catch (FOPException e) { throw new ConfigurationException("Error while setting up fonts", e); |