diff options
author | Jeremias Maerki <jeremias@apache.org> | 2009-03-10 15:10:07 +0000 |
---|---|---|
committer | Jeremias Maerki <jeremias@apache.org> | 2009-03-10 15:10:07 +0000 |
commit | 1914db175fda0d8776f686cf8409ddf4a5d6e5e6 (patch) | |
tree | 2dbc80310c8bc6317339c4c0904f1f41e7b32a47 /src/java | |
parent | c219edf458b679f2e621cb70bdfe9d2b5b5f6f74 (diff) | |
download | xmlgraphics-fop-1914db175fda0d8776f686cf8409ddf4a5d6e5e6.tar.gz xmlgraphics-fop-1914db175fda0d8776f686cf8409ddf4a5d6e5e6.zip |
Added full URI resolution support for AFP fonts.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@752133 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java')
9 files changed, 163 insertions, 121 deletions
diff --git a/src/java/org/apache/fop/afp/AFPResourceManager.java b/src/java/org/apache/fop/afp/AFPResourceManager.java index 78c06bedf..c44698a10 100644 --- a/src/java/org/apache/fop/afp/AFPResourceManager.java +++ b/src/java/org/apache/fop/afp/AFPResourceManager.java @@ -37,7 +37,6 @@ import org.apache.fop.afp.modca.Registry; import org.apache.fop.afp.modca.ResourceGroup; import org.apache.fop.afp.modca.ResourceObject; import org.apache.fop.afp.util.ResourceAccessor; -import org.apache.fop.afp.util.SimpleResourceAccessor; /** * Manages the creation and storage of document resources @@ -236,11 +235,11 @@ public class AFPResourceManager { /** * Creates an included resource object by loading the contained object from a file. * @param resourceName the name of the resource - * @param basePath the base path in which to look for the resource files + * @param accessor resource accessor to access the resource with * @param resourceObjectType the resource object type ({@link ResourceObject}.*) * @throws IOException if an I/O error occurs while loading the resource */ - public void createIncludedResource(String resourceName, String basePath, + public void createIncludedResource(String resourceName, ResourceAccessor accessor, byte resourceObjectType) throws IOException { AFPResourceLevel resourceLevel = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE); URI uri; @@ -261,9 +260,6 @@ public class AFPResourceManager { if (log.isDebugEnabled()) { log.debug("Adding included resource: " + resourceName); } - //TODO This works with local filenames only. In the long term, this - //should work through FOP's URI resolver. - ResourceAccessor accessor = new SimpleResourceAccessor(basePath); IncludedResourceObject resourceContent = new IncludedResourceObject( resourceName, accessor, uri); diff --git a/src/java/org/apache/fop/afp/fonts/AFPFontCollection.java b/src/java/org/apache/fop/afp/fonts/AFPFontCollection.java index 670373fbf..66b3f5564 100644 --- a/src/java/org/apache/fop/afp/fonts/AFPFontCollection.java +++ b/src/java/org/apache/fop/afp/fonts/AFPFontCollection.java @@ -67,18 +67,14 @@ public class AFPFontCollection implements FontCollection { num++; } } - if (!fontInfo.hasFont("any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL)) { - eventProducer.warnMissingDefaultFont(this, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - } - if (!fontInfo.hasFont("any", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL)) { - eventProducer.warnMissingDefaultFont(this, Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - } - if (!fontInfo.hasFont("any", Font.STYLE_NORMAL, Font.WEIGHT_BOLD)) { - eventProducer.warnMissingDefaultFont(this, Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - } - if (!fontInfo.hasFont("any", Font.STYLE_ITALIC, Font.WEIGHT_BOLD)) { - eventProducer.warnMissingDefaultFont(this, Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - } + checkDefaultFontAvailable(fontInfo, eventProducer, + Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); + checkDefaultFontAvailable(fontInfo, eventProducer, + Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); + checkDefaultFontAvailable(fontInfo, eventProducer, + Font.STYLE_NORMAL, Font.WEIGHT_BOLD); + checkDefaultFontAvailable(fontInfo, eventProducer, + Font.STYLE_ITALIC, Font.WEIGHT_BOLD); } else { eventProducer.warnDefaultFontSetup(this); @@ -89,4 +85,11 @@ public class AFPFontCollection implements FontCollection { return num; } + private void checkDefaultFontAvailable(FontInfo fontInfo, AFPEventProducer eventProducer, + String style, int weight) { + if (!fontInfo.hasFont("any", style, weight)) { + eventProducer.warnMissingDefaultFont(this, style, weight); + } + } + } diff --git a/src/java/org/apache/fop/afp/fonts/AFPFontReader.java b/src/java/org/apache/fop/afp/fonts/AFPFontReader.java index d1e8bd8db..4e6a03259 100644 --- a/src/java/org/apache/fop/afp/fonts/AFPFontReader.java +++ b/src/java/org/apache/fop/afp/fonts/AFPFontReader.java @@ -19,21 +19,19 @@ package org.apache.fop.afp.fonts; -import java.io.File; import java.io.FileNotFoundException; -import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; +import java.net.URI; +import java.net.URISyntaxException; import java.util.List; import java.util.Map; -import org.apache.commons.io.FileUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.afp.AFPConstants; +import org.apache.fop.afp.util.ResourceAccessor; import org.apache.fop.afp.util.StructuredFieldReader; /** @@ -58,7 +56,7 @@ public final class AFPFontReader { /** * Static logging instance */ - protected static final Log log = LogFactory.getLog("org.apache.xmlgraphics.afp.fonts"); + protected static final Log log = LogFactory.getLog(AFPFontReader.class); /** * Template used to convert lists to arrays. @@ -96,7 +94,7 @@ public final class AFPFontReader { /** * The collection of code pages */ - private final Map/*<String, Map<String, String>>*/ codePages + private final Map/*<String, Map<String, String>>*/ codePagesCache = new java.util.HashMap/*<String, Map<String, String>>*/(); /** @@ -108,65 +106,16 @@ public final class AFPFontReader { * * @throws IOException in the event that an I/O exception of some sort has occurred */ - private InputStream openInputStream(String path, String filename) throws IOException { - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - if (classLoader == null) { - classLoader = AFPFontReader.class.getClassLoader(); - } - - URL url = classLoader.getResource(path); - - if (url == null) { - try { - File file = new File(path); - url = file.toURI().toURL(); - if (url == null) { - String msg = "file not found " + filename + " in classpath: " + path; - log.error(msg); - throw new FileNotFoundException(msg); - } - } catch (MalformedURLException ex) { - String msg = "file not found " + filename + " in classpath: " + path; - log.error(msg); - throw new FileNotFoundException(msg); - } - } - - File directory = FileUtils.toFile(url); - if (!directory.canRead()) { - String msg = "Failed to read directory " + url.getPath(); - log.error(msg); - throw new FileNotFoundException(msg); - } - - final String filterpattern = filename.trim(); - FilenameFilter filter = new FilenameFilter() { - public boolean accept(File dir, String name) { - return name.startsWith(filterpattern); - } - }; - - File[] files = directory.listFiles(filter); - - if (files.length < 1) { - String msg = "file search for " + filename + " located " - + files.length + " files"; - log.error(msg); - throw new FileNotFoundException(msg); - } else if (files.length > 1) { - String msg = "file search for " + filename + " located " - + files.length + " files"; - log.warn(msg); - } - - InputStream inputStream = files[0].toURI().toURL().openStream(); - - if (inputStream == null) { - String msg = "AFPFontReader:: getInputStream():: file not found for " + filename; - log.error(msg); - throw new FileNotFoundException(msg); + private InputStream openInputStream(ResourceAccessor accessor, String filename) + throws IOException { + URI uri; + try { + uri = new URI(filename.trim()); + } catch (URISyntaxException e) { + throw new FileNotFoundException("Invalid filename: " + + filename + " (" + e.getMessage() + ")"); } - + InputStream inputStream = accessor.createInputStream(uri); return inputStream; } @@ -206,13 +155,14 @@ public final class AFPFontReader { * chracter global identifier. */ String codePageId = new String(characterSet.getCodePage()); - String path = characterSet.getPath(); + ResourceAccessor accessor = characterSet.getResourceAccessor(); - Map/*<String,String>*/ codePage = (Map/*<String,String>*/)codePages.get(codePageId); + Map/*<String,String>*/ codePage + = (Map/*<String,String>*/)codePagesCache.get(codePageId); if (codePage == null) { - codePage = loadCodePage(codePageId, characterSet.getEncoding(), path); - codePages.put(codePageId, codePage); + codePage = loadCodePage(codePageId, characterSet.getEncoding(), accessor); + codePagesCache.put(codePageId, codePage); } /** @@ -222,7 +172,7 @@ public final class AFPFontReader { */ final String characterSetName = characterSet.getName(); - inputStream = openInputStream(path, characterSetName); + inputStream = openInputStream(accessor, characterSetName); StructuredFieldReader structuredFieldReader = new StructuredFieldReader(inputStream); @@ -246,7 +196,8 @@ public final class AFPFontReader { } //process D3AC89 Font Position - processFontPosition(structuredFieldReader, characterSetOrientations, metricNormalizationFactor); + processFontPosition(structuredFieldReader, characterSetOrientations, + metricNormalizationFactor); //process D38C89 Font Index (per orientation) for (int i = 0; i < characterSetOrientations.length; i++) { @@ -274,17 +225,18 @@ public final class AFPFontReader { * the code page identifier * @param encoding * the encoding to use for the character decoding + * @param accessor the resource accessor * @returns a code page mapping */ private Map/*<String,String>*/ loadCodePage(String codePage, String encoding, - String path) throws IOException { + ResourceAccessor accessor) throws IOException { // Create the HashMap to store code page information Map/*<String,String>*/ codePages = new java.util.HashMap/*<String,String>*/(); InputStream inputStream = null; try { - inputStream = openInputStream(path, codePage.trim()); + inputStream = openInputStream(accessor, codePage.trim()); StructuredFieldReader structuredFieldReader = new StructuredFieldReader(inputStream); byte[] data = structuredFieldReader.getNext(CHARACTER_TABLE_SF); diff --git a/src/java/org/apache/fop/afp/fonts/CharacterSet.java b/src/java/org/apache/fop/afp/fonts/CharacterSet.java index f0b671932..9573506b3 100644 --- a/src/java/org/apache/fop/afp/fonts/CharacterSet.java +++ b/src/java/org/apache/fop/afp/fonts/CharacterSet.java @@ -19,8 +19,10 @@ package org.apache.fop.afp.fonts; +import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.net.URI; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; @@ -34,6 +36,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.afp.AFPConstants; +import org.apache.fop.afp.util.ResourceAccessor; +import org.apache.fop.afp.util.SimpleResourceAccessor; import org.apache.fop.afp.util.StringUtils; /** @@ -80,7 +84,7 @@ public class CharacterSet { protected String name; /** The path to the installed fonts */ - protected String path; + private ResourceAccessor accessor; /** Indicator as to whether to metrics have been loaded */ private boolean isMetricsLoaded = false; @@ -99,8 +103,23 @@ public class CharacterSet { * @param encoding the encoding of the font * @param name the character set name * @param path the path to the installed afp fonts + * @deprecated Please use {@link #CharacterSet(String, String, String, URI)} instead. */ public CharacterSet(String codePage, String encoding, String name, String path) { + this(codePage, encoding, name, + new SimpleResourceAccessor(path != null ? new File(path) : null)); + } + + /** + * Constructor for the CharacterSetMetric object, the character set is used + * to load the font information from the actual AFP font. + * + * @param codePage the code page identifier + * @param encoding the encoding of the font + * @param name the character set name + * @param accessor the resource accessor to load resource with + */ + public CharacterSet(String codePage, String encoding, String name, ResourceAccessor accessor) { if (name.length() > MAX_NAME_LEN) { String msg = "Character set name '" + name + "' must be a maximum of " + MAX_NAME_LEN + " characters"; @@ -123,7 +142,7 @@ public class CharacterSet { //This may happen with "Cp500" on Sun Java 1.4.2 this.encoder = null; } - this.path = path; + this.accessor = accessor; this.characterSetOrientations = new java.util.HashMap(4); } @@ -202,12 +221,11 @@ public class CharacterSet { } /** - * Returns the path where the font resources are installed - * - * @return the path where the font resources are installed + * Returns the resource accessor to load the font resources with. + * @return the resource accessor to load the font resources with */ - public String getPath() { - return path; + public ResourceAccessor getResourceAccessor() { + return this.accessor; } /** diff --git a/src/java/org/apache/fop/afp/fonts/FopCharacterSet.java b/src/java/org/apache/fop/afp/fonts/FopCharacterSet.java index aec220b40..42950dc5b 100644 --- a/src/java/org/apache/fop/afp/fonts/FopCharacterSet.java +++ b/src/java/org/apache/fop/afp/fonts/FopCharacterSet.java @@ -19,6 +19,7 @@ package org.apache.fop.afp.fonts; +import org.apache.fop.afp.util.ResourceAccessor; import org.apache.fop.fonts.Typeface; /** @@ -43,7 +44,7 @@ public class FopCharacterSet extends CharacterSet { String name, Typeface charSet) { - super(codePage, encoding, name, null); + super(codePage, encoding, name, (ResourceAccessor)null); this.charSet = charSet; } diff --git a/src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java b/src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java index 55c8eab7d..97646542b 100644 --- a/src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java +++ b/src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java @@ -19,42 +19,68 @@ package org.apache.fop.afp.util; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URI; +import java.net.URL; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; +import org.apache.commons.io.IOUtils; + import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.FopFactory; +import org.apache.fop.fonts.FontManager; /** * Default implementation of the {@link ResourceAccessor} interface for use inside FOP. */ -public class DefaultFOPResourceAccessor implements ResourceAccessor { +public class DefaultFOPResourceAccessor extends SimpleResourceAccessor { private FOUserAgent userAgent; + private String categoryBaseURI; /** - * Main constructor. + * Constructor for resource to be accessed via the {@link FOUserAgent}. This contructor + * can take two base URIs: the category base URI is the one to use when differentiating between + * normal resources (ex. images) and font resources. So, if fonts need to be accessed, you can + * set the {@link FontManager}'s base URI instead of the one on the {@link FopFactory}. * @param userAgent the FO user agent + * @param categoryBaseURI the category base URI (may be null) + * @param baseURI the custom base URI to resolve relative URIs against (may be null) */ - public DefaultFOPResourceAccessor(FOUserAgent userAgent) { + public DefaultFOPResourceAccessor(FOUserAgent userAgent, String categoryBaseURI, URI baseURI) { + super(baseURI); this.userAgent = userAgent; + this.categoryBaseURI = categoryBaseURI; } /** {@inheritDoc} */ public InputStream createInputStream(URI uri) throws IOException { - Source src = userAgent.resolveURI(uri.toASCIIString()); + //Step 1: resolve against local base URI --> URI + URI resolved = resolveAgainstBase(uri); + + //Step 2: resolve against the user agent --> stream + Source src; + src = userAgent.resolveURI(resolved.toASCIIString(), this.categoryBaseURI); + if (src == null) { - return null; + throw new FileNotFoundException("Resource not found: " + uri.toASCIIString()); } else if (src instanceof StreamSource) { StreamSource ss = (StreamSource)src; InputStream in = ss.getInputStream(); - return in; - } else { - return null; + if (in != null) { + return in; + } + if (ss.getReader() != null) { + //Don't support reader, retry using system ID below + IOUtils.closeQuietly(ss.getReader()); + } } + URL url = new URL(src.getSystemId()); + return url.openStream(); } } diff --git a/src/java/org/apache/fop/afp/util/SimpleResourceAccessor.java b/src/java/org/apache/fop/afp/util/SimpleResourceAccessor.java index 51772c253..7a963928b 100644 --- a/src/java/org/apache/fop/afp/util/SimpleResourceAccessor.java +++ b/src/java/org/apache/fop/afp/util/SimpleResourceAccessor.java @@ -26,7 +26,8 @@ import java.net.URI; import java.net.URL; /** - * Simple implementation of the {@link ResourceAccessor} interface for access via files. + * Simple implementation of the {@link ResourceAccessor} interface for access relative to a + * base URI. */ public class SimpleResourceAccessor implements ResourceAccessor { @@ -34,23 +35,40 @@ public class SimpleResourceAccessor implements ResourceAccessor { /** * Creates a new simple resource accessor. - * @param basePath the base path to resolve relative URIs to + * @param baseURI the base URI to resolve relative URIs against (may be null) */ - public SimpleResourceAccessor(File basePath) { - this.baseURI = basePath.toURI(); + public SimpleResourceAccessor(URI baseURI) { + this.baseURI = baseURI; } /** * Creates a new simple resource accessor. - * @param basePath the base path to resolve relative URIs to + * @param baseDir the base directory to resolve relative filenames against (may be null) */ - public SimpleResourceAccessor(String basePath) { - this(new File(basePath)); + public SimpleResourceAccessor(File baseDir) { + this(baseDir != null ? baseDir.toURI() : null); + } + + /** + * Returns the base URI. + * @return the base URI (or null if no base URI was set) + */ + public URI getBaseURI() { + return this.baseURI; + } + + /** + * Resolve the given URI against the baseURI. + * @param uri the URI to resolve + * @return the resolved URI + */ + protected URI resolveAgainstBase(URI uri) { + return (getBaseURI() != null ? getBaseURI().resolve(uri) : uri); } /** {@inheritDoc} */ public InputStream createInputStream(URI uri) throws IOException { - URI resolved = this.baseURI.resolve(uri); + URI resolved = resolveAgainstBase(uri); URL url = resolved.toURL(); return url.openStream(); } diff --git a/src/java/org/apache/fop/render/afp/AFPPainter.java b/src/java/org/apache/fop/render/afp/AFPPainter.java index 0c2501b87..a92be9d6e 100644 --- a/src/java/org/apache/fop/render/afp/AFPPainter.java +++ b/src/java/org/apache/fop/render/afp/AFPPainter.java @@ -49,6 +49,7 @@ import org.apache.fop.afp.modca.PresentationTextObject; import org.apache.fop.afp.modca.ResourceObject; import org.apache.fop.afp.ptoca.PtocaBuilder; import org.apache.fop.afp.ptoca.PtocaProducer; +import org.apache.fop.afp.util.ResourceAccessor; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontTriplet; @@ -342,12 +343,13 @@ public class AFPPainter extends AbstractIFPainter { try { //Embed fonts (char sets and code pages) //TODO This should be moved to a place where it has less performance impact - if (charSet.getPath() != null) { + if (charSet.getResourceAccessor() != null) { + ResourceAccessor accessor = charSet.getResourceAccessor(); documentHandler.getResourceManager().createIncludedResource( - charSet.getName(), charSet.getPath(), + charSet.getName(), accessor, ResourceObject.TYPE_FONT_CHARACTER_SET); documentHandler.getResourceManager().createIncludedResource( - charSet.getCodePage(), charSet.getPath(), + charSet.getCodePage(), accessor, ResourceObject.TYPE_CODE_PAGE); } } catch (IOException ioe) { diff --git a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java index bd6df6136..fcc1140c7 100644 --- a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java +++ b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java @@ -20,6 +20,8 @@ package org.apache.fop.render.afp; import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; import java.util.List; import org.apache.avalon.framework.configuration.Configuration; @@ -33,6 +35,8 @@ import org.apache.fop.afp.fonts.CharacterSet; import org.apache.fop.afp.fonts.FopCharacterSet; import org.apache.fop.afp.fonts.OutlineFont; import org.apache.fop.afp.fonts.RasterFont; +import org.apache.fop.afp.util.DefaultFOPResourceAccessor; +import org.apache.fop.afp.util.ResourceAccessor; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.fonts.FontCollection; @@ -85,7 +89,29 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator log.error("Mandatory font configuration element '<afp-font...' is missing"); return null; } - String path = afpFontCfg.getAttribute("path", fontPath); + + URI baseURI = null; + String uri = afpFontCfg.getAttribute("base-uri", fontPath); + if (uri == null) { + //Fallback for old attribute which only supports local filenames + String path = afpFontCfg.getAttribute("path", fontPath); + if (path != null) { + File f = new File(path); + baseURI = f.toURI(); + } + } else { + try { + baseURI = new URI(uri); + } catch (URISyntaxException e) { + log.error("Invalid URI: " + e.getMessage()); + return null; + } + } + ResourceAccessor accessor = new DefaultFOPResourceAccessor( + this.userAgent, + this.userAgent.getFactory().getFontManager().getFontBaseURL(), + baseURI); + String type = afpFontCfg.getAttribute("type"); if (type == null) { log.error("Mandatory afp-font configuration attribute 'type=' is missing"); @@ -147,7 +173,7 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator } } else { font.addCharacterSet(size, new CharacterSet( - codepage, encoding, characterset, path)); + codepage, encoding, characterset, accessor)); } } return new AFPFontInfo(font, tripletList); @@ -180,7 +206,7 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator log.error(msg); } } else { - characterSet = new CharacterSet(codepage, encoding, characterset, path); + characterSet = new CharacterSet(codepage, encoding, characterset, accessor); } // Create a new font object OutlineFont font = new OutlineFont(name, characterSet); |