diff options
Diffstat (limited to 'src/java/org/apache/fop')
171 files changed, 6468 insertions, 3984 deletions
diff --git a/src/java/org/apache/fop/afp/AFPDataObjectInfo.java b/src/java/org/apache/fop/afp/AFPDataObjectInfo.java index 7589ef4fe..b93056f02 100644 --- a/src/java/org/apache/fop/afp/AFPDataObjectInfo.java +++ b/src/java/org/apache/fop/afp/AFPDataObjectInfo.java @@ -57,6 +57,8 @@ public class AFPDataObjectInfo { /** controls the mapping of the image data into the image area */ private byte mappingOption = MappingOptionTriplet.SCALE_TO_FILL; + public static final byte DEFAULT_MAPPING_OPTION = 0x00; + /** * Default constructor */ diff --git a/src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java b/src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java index 244e6122c..2d7dd3694 100644 --- a/src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java +++ b/src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java @@ -165,9 +165,8 @@ public class AFPBase12FontCollection implements FontCollection { } private RasterFont createReferencedRasterFont(String fontFamily) { - RasterFont font = new RasterFont(fontFamily); - font.setEmbeddable(false); //Font is assumed to be available on the target platform - return font; + boolean embeddable = false; //Font is assumed to be available on the target platform + return new RasterFont(fontFamily, embeddable); } } diff --git a/src/java/org/apache/fop/afp/fonts/AFPFont.java b/src/java/org/apache/fop/afp/fonts/AFPFont.java index 8a4ae3dc1..06f484f37 100644 --- a/src/java/org/apache/fop/afp/fonts/AFPFont.java +++ b/src/java/org/apache/fop/afp/fonts/AFPFont.java @@ -35,16 +35,18 @@ import org.apache.fop.fonts.Typeface; public abstract class AFPFont extends Typeface { /** The font name */ - protected String name; + protected final String name; - private boolean embeddable = true; + private final boolean embeddable; /** * Constructor for the base font requires the name. * @param name the name of the font + * @param embeddable whether this font is to be embedded */ - public AFPFont(String name) { + public AFPFont(String name, boolean embeddable) { this.name = name; + this.embeddable = embeddable; } /** {@inheritDoc} */ @@ -89,7 +91,7 @@ public abstract class AFPFont extends Typeface { * Returns the kerning map for the font. * @return the kerning map */ - public Map getKerningInfo() { + public Map<Integer, Map<Integer, Integer>> getKerningInfo() { return null; } @@ -101,14 +103,6 @@ public abstract class AFPFont extends Typeface { public abstract CharacterSet getCharacterSet(int size); /** - * Controls whether this font is embeddable or not. - * @param value true to enable embedding, false otherwise. - */ - public void setEmbeddable(boolean value) { - this.embeddable = value; - } - - /** * Indicates if this font may be embedded. * @return True, if embedding is possible/permitted */ diff --git a/src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java b/src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java index fdd238242..1a2611d8d 100644 --- a/src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java +++ b/src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java @@ -32,13 +32,12 @@ public abstract class AbstractOutlineFont extends AFPFont { /** * Constructor for an outline font. * - * @param name - * the name of the font - * @param charSet - * the chracter set + * @param name the name of the font + * @param embeddable sets whether or not this font is to be embedded + * @param charSet the chracter set */ - public AbstractOutlineFont(String name, CharacterSet charSet) { - super(name); + public AbstractOutlineFont(String name, boolean embeddable, CharacterSet charSet) { + super(name, embeddable); this.charSet = charSet; } diff --git a/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java b/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java index 7da2d71ca..18eaf41ee 100644 --- a/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java +++ b/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java @@ -464,7 +464,6 @@ public abstract class CharacterSetBuilder { } } - return orientations.toArray(EMPTY_CSO_ARRAY); } diff --git a/src/java/org/apache/fop/afp/fonts/DoubleByteFont.java b/src/java/org/apache/fop/afp/fonts/DoubleByteFont.java index 4514eac5d..a81805bc5 100644 --- a/src/java/org/apache/fop/afp/fonts/DoubleByteFont.java +++ b/src/java/org/apache/fop/afp/fonts/DoubleByteFont.java @@ -19,6 +19,8 @@ package org.apache.fop.afp.fonts; +import java.lang.Character.UnicodeBlock; +import java.util.HashSet; import java.util.Set; /** @@ -33,7 +35,7 @@ public class DoubleByteFont extends AbstractOutlineFont { //See also http://unicode.org/reports/tr11/ which we've not closely looked at, yet //TODO the Unicode block listed here is probably not complete (ex. Hiragana, Katakana etc.) - private static final Set IDEOGRAPHIC = new java.util.HashSet(); + private static final Set<UnicodeBlock> IDEOGRAPHIC = new HashSet<UnicodeBlock>(); static { IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS); //IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT);//Java 1.5 @@ -45,10 +47,11 @@ public class DoubleByteFont extends AbstractOutlineFont { /** * Constructor for an double-byte outline font. * @param name the name of the font + * @param embeddable whether or not this font is embeddable * @param charSet the character set */ - public DoubleByteFont(String name, CharacterSet charSet) { - super(name, charSet); + public DoubleByteFont(String name, boolean embeddable, CharacterSet charSet) { + super(name, embeddable, charSet); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/afp/fonts/OutlineFont.java b/src/java/org/apache/fop/afp/fonts/OutlineFont.java index 01c605146..103d96eca 100644 --- a/src/java/org/apache/fop/afp/fonts/OutlineFont.java +++ b/src/java/org/apache/fop/afp/fonts/OutlineFont.java @@ -27,10 +27,11 @@ public class OutlineFont extends AbstractOutlineFont { /** * Construct outline font with specified name and character set. * @param name font's name + * @param embeddable whether or not this font is embeddable * @param charSet font's character set */ - public OutlineFont(String name, CharacterSet charSet) { - super(name, charSet); + public OutlineFont(String name, boolean embeddable, CharacterSet charSet) { + super(name, embeddable, charSet); } } diff --git a/src/java/org/apache/fop/afp/fonts/RasterFont.java b/src/java/org/apache/fop/afp/fonts/RasterFont.java index 30704b2b0..5c4c38dc5 100644 --- a/src/java/org/apache/fop/afp/fonts/RasterFont.java +++ b/src/java/org/apache/fop/afp/fonts/RasterFont.java @@ -52,8 +52,8 @@ public class RasterFont extends AFPFont { * @param name * the name of the font */ - public RasterFont(String name) { - super(name); + public RasterFont(String name, boolean embeddable) { + super(name, embeddable); } /** @@ -76,7 +76,7 @@ public class RasterFont extends AFPFont { public CharacterSet getCharacterSet(int sizeInMpt) { Integer requestedSize = Integer.valueOf(sizeInMpt); - CharacterSet csm = (CharacterSet) charSets.get(requestedSize); + CharacterSet csm = charSets.get(requestedSize); double sizeInPt = sizeInMpt / 1000.0; if (csm != null) { @@ -85,7 +85,7 @@ public class RasterFont extends AFPFont { if (substitutionCharSets != null) { //Check first if a substitution has already been added - csm = (CharacterSet) substitutionCharSets.get(requestedSize); + csm = substitutionCharSets.get(requestedSize); } if (csm == null && !charSets.isEmpty()) { @@ -95,9 +95,9 @@ public class RasterFont extends AFPFont { SortedMap<Integer, CharacterSet> smallerSizes = charSets.headMap(requestedSize); SortedMap<Integer, CharacterSet> largerSizes = charSets.tailMap(requestedSize); int smallerSize = smallerSizes.isEmpty() ? 0 - : ((Integer)smallerSizes.lastKey()).intValue(); + : smallerSizes.lastKey().intValue(); int largerSize = largerSizes.isEmpty() ? Integer.MAX_VALUE - : ((Integer)largerSizes.firstKey()).intValue(); + : largerSizes.firstKey().intValue(); Integer fontSize; if (!smallerSizes.isEmpty() @@ -106,7 +106,7 @@ public class RasterFont extends AFPFont { } else { fontSize = Integer.valueOf(largerSize); } - csm = (CharacterSet) charSets.get(fontSize); + csm = charSets.get(fontSize); if (csm != null) { // Add the substitute mapping, so subsequent calls will diff --git a/src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java b/src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java index f379546e2..3599b8e8f 100644 --- a/src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java +++ b/src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java @@ -19,26 +19,22 @@ 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 java.net.URISyntaxException; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.FopFactory; +import org.apache.fop.apps.io.URIResolverWrapper; /** * Default implementation of the {@link ResourceAccessor} interface for use inside FOP. */ public class DefaultFOPResourceAccessor extends SimpleResourceAccessor { - private FOUserAgent userAgent; - private String categoryBaseURI; + private final URIResolverWrapper resolver; + private final String baseURI; /** * Constructor for resource to be accessed via the {@link FOUserAgent}. This contructor @@ -49,38 +45,32 @@ public class DefaultFOPResourceAccessor extends SimpleResourceAccessor { * @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, String categoryBaseURI, URI baseURI) { - super(baseURI); - this.userAgent = userAgent; - this.categoryBaseURI = categoryBaseURI; + public DefaultFOPResourceAccessor(URIResolverWrapper resolver, String baseURI) { + super(resolver.getBaseURI()); + this.resolver = resolver; + this.baseURI = baseURI; } - /** {@inheritDoc} */ - public InputStream createInputStream(URI uri) throws IOException { - //Step 1: resolve against local base URI --> URI - URI resolved = resolveAgainstBase(uri); - - //Step 2: resolve against the user agent --> stream - String base = (this.categoryBaseURI != null - ? this.categoryBaseURI - : this.userAgent.getBaseURL()); - Source src = userAgent.resolveURI(resolved.toASCIIString(), base); + public DefaultFOPResourceAccessor(URIResolverWrapper resolver) { + super(resolver.getBaseURI()); + this.resolver = resolver; + this.baseURI = null; + } - if (src == null) { - throw new FileNotFoundException("Resource not found: " + uri.toASCIIString()); - } else if (src instanceof StreamSource) { - StreamSource ss = (StreamSource)src; - InputStream in = ss.getInputStream(); - if (in != null) { - return in; - } - if (ss.getReader() != null) { - //Don't support reader, retry using system ID below - IOUtils.closeQuietly(ss.getReader()); - } + private URI getResourceURI(URI uri) { + if (baseURI == null) { + return uri; + } + try { + URI baseURI = URIResolverWrapper.getBaseURI(this.baseURI); + return baseURI.resolve(uri); + } catch (URISyntaxException use) { + return uri; } - URL url = new URL(src.getSystemId()); - return url.openStream(); } + /** {@inheritDoc} */ + public InputStream createInputStream(URI uri) throws IOException { + return resolver.resolveIn(getResourceURI(uri)); + } } diff --git a/src/java/org/apache/fop/apps/EnvironmentProfile.java b/src/java/org/apache/fop/apps/EnvironmentProfile.java new file mode 100644 index 000000000..c35219353 --- /dev/null +++ b/src/java/org/apache/fop/apps/EnvironmentProfile.java @@ -0,0 +1,52 @@ +/* + * 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.net.URI; + +import org.apache.fop.apps.io.ResourceResolver; +import org.apache.fop.fonts.FontManager; + +/** + * The environment profile represents the restrictions and allowances that FOP is + */ +public interface EnvironmentProfile { + + /** + * Returns resource resolver for this environment. + * + * @return the resource resolver + */ + ResourceResolver getResourceResolver(); + + /** + * Returns the font manager with restrictions/allowances set for this environment. + * + * @return the font manager + */ + FontManager getFontManager(); + + /** + * The default base URI used for resolving URIs. + * + * @return the default base URI + */ + URI getDefaultBaseURI(); +} diff --git a/src/java/org/apache/fop/apps/EnvironmentalProfileFactory.java b/src/java/org/apache/fop/apps/EnvironmentalProfileFactory.java new file mode 100644 index 000000000..c00a9fad9 --- /dev/null +++ b/src/java/org/apache/fop/apps/EnvironmentalProfileFactory.java @@ -0,0 +1,111 @@ +/* + * 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.net.URI; + +import org.apache.fop.apps.io.ResourceResolver; +import org.apache.fop.apps.io.URIResolverWrapper; +import org.apache.fop.fonts.FontCacheManager; +import org.apache.fop.fonts.FontCacheManagerFactory; +import org.apache.fop.fonts.FontDetector; +import org.apache.fop.fonts.FontDetectorFactory; +import org.apache.fop.fonts.FontManager; + +/** + * Creates an {@link EnvironmentProfile} that sets the environment in which a FOP instance is run. + */ +public final class EnvironmentalProfileFactory { + + private EnvironmentalProfileFactory() { + }; + + /** + * Creates the default environment that FOP is invoked in. This default profile has no + * operational restrictions for FOP. + * + * @param defaultBaseUri the default base URI for resolving resource URIs + * @param resourceResolver the resource resolver + * @return the environment profile + */ + public static EnvironmentProfile createDefault(URI defaultBaseUri, + ResourceResolver resourceResolver) { + return new Profile(defaultBaseUri, resourceResolver, + createFontManager(defaultBaseUri, resourceResolver, + FontDetectorFactory.createDefault(), + FontCacheManagerFactory.createDefault())); + } + + /** + * Creates an IO-restricted environment for FOP by disabling some of the environment-specific + * functionality within FOP. + * + * @param defaultBaseUri the default base URI for resolving resource URIs + * @param resourceResolver the resource resolver + * @return the environment profile + */ + public static EnvironmentProfile createRestrictedIO(URI defaultBaseUri, + ResourceResolver resourceResolver) { + return new Profile(defaultBaseUri, resourceResolver, + createFontManager(defaultBaseUri, resourceResolver, + FontDetectorFactory.createDisabled(), + FontCacheManagerFactory.createDisabled())); + } + + private static final class Profile implements EnvironmentProfile { + + private final ResourceResolver resourceResolver; + + private final FontManager fontManager; + + private final URI defaultBaseURI; + + private Profile(URI defaultBaseURI, ResourceResolver resourceResolver, + FontManager fontManager) { + if (defaultBaseURI == null) { + throw new IllegalArgumentException("Default base URI must not be null"); + } + if (resourceResolver == null) { + throw new IllegalArgumentException("URI Resolver must not be null"); + } + this.defaultBaseURI = defaultBaseURI; + this.resourceResolver = resourceResolver; + this.fontManager = fontManager; + } + + public ResourceResolver getResourceResolver() { + return resourceResolver; + } + + public FontManager getFontManager() { + return fontManager; + } + + public URI getDefaultBaseURI() { + return defaultBaseURI; + } + } + + private static FontManager createFontManager(URI defaultBaseUri, ResourceResolver resourceResolver, + FontDetector fontDetector, FontCacheManager fontCacheManager) { + return new FontManager(new URIResolverWrapper(defaultBaseUri, resourceResolver), fontDetector, + fontCacheManager); + } +} diff --git a/src/java/org/apache/fop/apps/FOUserAgent.java b/src/java/org/apache/fop/apps/FOUserAgent.java index 665c1abf8..c395d01d8 100644 --- a/src/java/org/apache/fop/apps/FOUserAgent.java +++ b/src/java/org/apache/fop/apps/FOUserAgent.java @@ -21,37 +21,54 @@ package org.apache.fop.apps; // Java import java.io.File; -import java.net.MalformedURLException; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; import java.util.Date; import java.util.Map; import javax.xml.transform.Source; -import javax.xml.transform.TransformerException; -import javax.xml.transform.URIResolver; +import javax.xml.transform.stream.StreamSource; +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.xmlgraphics.image.loader.ImageContext; +import org.apache.xmlgraphics.image.loader.ImageManager; import org.apache.xmlgraphics.image.loader.ImageSessionContext; import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext; import org.apache.xmlgraphics.util.UnitConv; +import org.apache.xmlgraphics.util.uri.CommonURIResolver; import org.apache.fop.Version; import org.apache.fop.accessibility.Accessibility; import org.apache.fop.accessibility.DummyStructureTreeEventHandler; import org.apache.fop.accessibility.StructureTreeEventHandler; +import org.apache.fop.apps.io.URIResolverWrapper; import org.apache.fop.events.DefaultEventBroadcaster; import org.apache.fop.events.Event; import org.apache.fop.events.EventBroadcaster; import org.apache.fop.events.EventListener; import org.apache.fop.events.FOPEventListenerProxy; import org.apache.fop.events.LoggingEventListener; +import org.apache.fop.fo.ElementMappingRegistry; import org.apache.fop.fo.FOEventHandler; +import org.apache.fop.fonts.FontManager; +import org.apache.fop.hyphenation.HyphenationTreeResolver; +import org.apache.fop.layoutmgr.LayoutManagerMaker; +import org.apache.fop.render.ImageHandlerRegistry; import org.apache.fop.render.Renderer; +import org.apache.fop.render.RendererConfig; +import org.apache.fop.render.RendererConfig.RendererConfigParser; +import org.apache.fop.render.RendererConfigOptions; import org.apache.fop.render.RendererFactory; import org.apache.fop.render.XMLHandlerRegistry; import org.apache.fop.render.intermediate.IFDocumentHandler; +import org.apache.fop.util.ColorSpaceCache; +import org.apache.fop.util.ContentHandlerFactoryRegistry; /** * This is the user agent for FOP. @@ -75,24 +92,13 @@ import org.apache.fop.render.intermediate.IFDocumentHandler; */ public class FOUserAgent { - /** Defines the default target resolution (72dpi) for FOP */ - 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 base = null; + private final FopFactory factory; - /** A user settable URI Resolver */ - private URIResolver uriResolver = null; + private final URIResolverWrapper newUriResolver; - private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION; + private float targetResolution = FopFactoryConfig.DEFAULT_TARGET_RESOLUTION; private Map rendererOptions = new java.util.HashMap(); private File outputFile = null; private IFDocumentHandler documentHandlerOverride = null; @@ -131,7 +137,7 @@ public class FOUserAgent { private ImageSessionContext imageSessionContext = new AbstractImageSessionContext() { public ImageContext getParentContext() { - return getFactory(); + return factory; } public float getTargetResolution() { @@ -150,19 +156,56 @@ public class FOUserAgent { * @param factory the factory that provides environment-level information * @see org.apache.fop.apps.FopFactory */ - public FOUserAgent(FopFactory factory) { - if (factory == null) { - throw new NullPointerException("The factory parameter must not be null"); - } + FOUserAgent(FopFactory factory, URIResolverWrapper uriResolver) { this.factory = factory; - setBaseURL(factory.getBaseURL()); + this.newUriResolver = uriResolver; setTargetResolution(factory.getTargetResolution()); setAccessibility(factory.isAccessibilityEnabled()); } - /** @return the associated FopFactory instance */ - public FopFactory getFactory() { - return this.factory; + /** + * Returns a new {@link Fop} instance. Use this factory method if your output type + * requires an output stream and you want to configure this very rendering run, + * i.e. if you want to set some metadata like the title and author of the document + * you want to render. In that case, create a new {@link FOUserAgent} instance + * using {@link #newFOUserAgent()}. + * <p> + * MIME types are used to select the output format (ex. "application/pdf" for PDF). You can + * use the constants defined in {@link MimeConstants}. + * @param outputFormat the MIME type of the output format to use (ex. "application/pdf"). + * @param stream the output stream + * @return the new Fop instance + * @throws FOPException when the constructor fails + */ + public Fop newFop(String outputFormat, OutputStream stream) throws FOPException { + return new Fop(outputFormat, this, stream); + } + + + /** + * Returns a new {@link Fop} instance. Use this factory method if you want to configure this + * very rendering run, i.e. if you want to set some metadata like the title and author of the + * document you want to render. In that case, create a new {@link FOUserAgent} + * instance using {@link #newFOUserAgent()}. + * <p> + * MIME types are used to select the output format (ex. "application/pdf" for PDF). You can + * use the constants defined in {@link MimeConstants}. + * @param outputFormat the MIME type of the output format to use (ex. "application/pdf"). + * @return the new Fop instance + * @throws FOPException when the constructor fails + */ + public Fop newFop(String outputFormat) throws FOPException { + return newFop(outputFormat, null); + } + + + /** + * Returns the URI Resolver. + * + * @return the URI resolver + */ + public URIResolverWrapper getNewURIResolver() { + return newUriResolver; } // ---------------------------------------------- rendering-run dependent stuff @@ -345,48 +388,13 @@ public class FOUserAgent { } /** - * Sets the base URL. - * @param baseUrl base URL - */ - public void setBaseURL(String baseUrl) { - this.base = baseUrl; - } - - /** - * Sets font base URL. - * @param fontBaseUrl font base URL - * @deprecated Use {@link FontManager#setFontBaseURL(String)} instead. - */ - public void setFontBaseURL(String fontBaseUrl) { - try { - getFactory().getFontManager().setFontBaseURL(fontBaseUrl); - } catch (MalformedURLException e) { - throw new IllegalArgumentException(e.getMessage()); - } - } - - /** - * Returns the base URL. - * @return the base URL - */ - public String getBaseURL() { - return this.base; - } - - /** - * Sets the URI Resolver. - * @param resolver the new URI resolver - */ - public void setURIResolver(URIResolver resolver) { - this.uriResolver = resolver; - } - - /** - * Returns the URI Resolver. - * @return the URI Resolver - */ - public URIResolver getURIResolver() { - return this.uriResolver; + * Gets the renderer options given an interface representing renderer configuration options. + * + * @param option the renderer option + * @return the value + */ + public Object getRendererOption(RendererConfigOptions option) { + return rendererOptions.get(option.getName()); } /** @@ -396,39 +404,27 @@ public class FOUserAgent { * @param uri URI to access * @return A {@link javax.xml.transform.Source} object, or null if the URI * cannot be resolved. - * @see org.apache.fop.apps.FOURIResolver + * @see org.apache.fop.apps.io.FOURIResolver */ public Source resolveURI(String uri) { - return resolveURI(uri, getBaseURL()); - } - - /** - * Attempts to resolve the given URI. - * Will use the configured resolver and if not successful fall back - * to the default resolver. - * @param href URI to access - * @param base 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 href, String base) { - Source source = null; - //RFC 2397 data URLs don't need to be resolved, just decode them through FOP's default - //URIResolver. - boolean bypassURIResolution = href.startsWith("data:"); - if (!bypassURIResolution && uriResolver != null) { - try { - source = uriResolver.resolve(href, base); - } catch (TransformerException te) { - log.error("Attempt to resolve URI '" + href + "' failed: ", te); + // TODO: What do we want to do when resources aren't found??? + try { + Source src; + // Have to do this so we can resolve data URIs + if (uri.startsWith("data:")) { + CommonURIResolver uriResolver = new CommonURIResolver(); + src = uriResolver.resolve(uri, ""); + } else { + URI actualUri = URIResolverWrapper.cleanURI(uri); + src = new StreamSource(newUriResolver.resolveIn(actualUri)); + src.setSystemId(uri); } + return src; + } catch (URISyntaxException use) { + return null; + } catch (IOException ioe) { + return null; } - if (source == null) { - // URI Resolver not configured or returned null, use default resolver from the factory - source = getFactory().resolveURI(href, base); - } - return source; } /** @@ -498,28 +494,18 @@ public class FOUserAgent { // (convenience access to FopFactory methods) /** - * Returns the font base URL. - * @return the font base URL - * @deprecated Use {@link FontManager#getFontBaseURL()} instead. This method is not used by FOP. - */ - public String getFontBaseURL() { - String fontBase = getFactory().getFontManager().getFontBaseURL(); - return fontBase != null ? fontBase : getBaseURL(); - } - - /** * Returns the conversion factor from pixel units to millimeters. This * depends on the desired source resolution. * @return float conversion factor * @see #getSourceResolution() */ public float getSourcePixelUnitToMillimeter() { - return getFactory().getSourcePixelUnitToMillimeter(); + return factory.getSourcePixelUnitToMillimeter(); } /** @return the resolution for resolution-dependant input */ public float getSourceResolution() { - return getFactory().getSourceResolution(); + return factory.getSourceResolution(); } /** @@ -530,7 +516,7 @@ public class FOUserAgent { * @see FopFactory#getPageHeight() */ public String getPageHeight() { - return getFactory().getPageHeight(); + return factory.getPageHeight(); } /** @@ -541,7 +527,7 @@ public class FOUserAgent { * @see FopFactory#getPageWidth() */ public String getPageWidth() { - return getFactory().getPageWidth(); + return factory.getPageWidth(); } /** @@ -550,7 +536,7 @@ public class FOUserAgent { * @see FopFactory#validateStrictly() */ public boolean validateStrictly() { - return getFactory().validateStrictly(); + return factory.validateStrictly(); } /** @@ -559,21 +545,21 @@ public class FOUserAgent { * @see FopFactory#isBreakIndentInheritanceOnReferenceAreaBoundary() */ public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() { - return getFactory().isBreakIndentInheritanceOnReferenceAreaBoundary(); + return factory.isBreakIndentInheritanceOnReferenceAreaBoundary(); } /** * @return the RendererFactory */ public RendererFactory getRendererFactory() { - return getFactory().getRendererFactory(); + return factory.getRendererFactory(); } /** * @return the XML handler registry */ public XMLHandlerRegistry getXMLHandlerRegistry() { - return getFactory().getXMLHandlerRegistry(); + return factory.getXMLHandlerRegistry(); } /** @@ -662,12 +648,53 @@ public class FOUserAgent { } /** - * Control whether complex script features should be enabled + * Returns the renderer configuration object for a particular MIME type. * - * @param useComplexScriptFeatures true if FOP is to use complex script features + * @param mimeType the config MIME type + * @param configCreator the parser for creating the config for the first run of parsing. + * @return the renderer configuration object + * @throws FOPException if an error occurs when creating the config object */ - public void setComplexScriptFeaturesEnabled(boolean useComplexScriptFeatures) { - factory.setComplexScriptFeaturesEnabled ( useComplexScriptFeatures ); + public RendererConfig getRendererConfig(String mimeType, RendererConfigParser configCreator) + throws FOPException { + return factory.getRendererConfig(this, getRendererConfiguration(mimeType), configCreator); + } + + /** + * Returns a {@link Configuration} object for which contains renderer configuration for a given + * MIME type. + * + * @param mimeType the renderer configuration MIME type + * @return the configuration object + */ + public Configuration getRendererConfiguration(String mimeType) { + Configuration cfg = getUserConfig(); + String type = "renderer"; + String mime = "mime"; + if (cfg == null) { + if (log.isDebugEnabled()) { + log.debug("userconfig is null"); + } + return null; + } + + Configuration userConfig = null; + + 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; } /** @@ -713,5 +740,74 @@ public class FOUserAgent { public StructureTreeEventHandler getStructureTreeEventHandler() { return this.structureTreeEventHandler; } + + /** @see FopFactory#getLayoutManagerMakerOverride() */ + public LayoutManagerMaker getLayoutManagerMakerOverride() { + return factory.getLayoutManagerMakerOverride(); + } + + /** @see FopFactory#getContentHandlerFactoryRegistry() */ + public ContentHandlerFactoryRegistry getContentHandlerFactoryRegistry() { + return factory.getContentHandlerFactoryRegistry(); + } + + /** @see FopFactory#getImageManager() */ + public ImageManager getImageManager() { + return factory.getImageManager(); + } + + /** @see FopFactory#getElementMappingRegistry() */ + public ElementMappingRegistry getElementMappingRegistry() { + return factory.getElementMappingRegistry(); + } + + /** @see FopFactory#getFontManager() */ + public FontManager getFontManager() { + return factory.getFontManager(); + } + + /** + * Indicates whether a namespace URI is on the ignored list. + * @param namespaceURI the namespace URI + * @return true if the namespace is ignored by FOP + */ + public boolean isNamespaceIgnored(String namespaceURI) { + return factory.isNamespaceIgnored(namespaceURI); + } + + /** + * Is the user configuration to be validated? + * @return if the user configuration should be validated + */ + public boolean validateUserConfigStrictly() { + return factory.validateUserConfigStrictly(); + } + + /** + * Get the user configuration. + * @return the user configuration + */ + public Configuration getUserConfig() { + return factory.getUserConfig(); + } + + /** @return the image handler registry */ + public ImageHandlerRegistry getImageHandlerRegistry() { + return factory.getImageHandlerRegistry(); + } + + /** TODO: javadoc*/ + public ColorSpaceCache getColorSpaceCache() { + return factory.getColorSpaceCache(); + } + + /** @return the HyphenationTreeResolver for resolving user-supplied hyphenation patterns. */ + public HyphenationTreeResolver getHyphenationTreeResolver() { + return factory.getHyphenationTreeResolver(); + } + + public Map<String, String> getHyphPatNames() { + return factory.getHyphPatNames(); + } } diff --git a/src/java/org/apache/fop/apps/Fop.java b/src/java/org/apache/fop/apps/Fop.java index 0527ea290..fc82ac1cb 100644 --- a/src/java/org/apache/fop/apps/Fop.java +++ b/src/java/org/apache/fop/apps/Fop.java @@ -66,12 +66,12 @@ public class Fop { * @throws FOPException if setting up the DefaultHandler fails */ Fop(String outputFormat, FOUserAgent ua, OutputStream stream) throws FOPException { + if (ua == null) { + throw new FOPException("Cannot create a new Fop instance without a User Agent."); + } this.outputFormat = outputFormat; foUserAgent = ua; - if (foUserAgent == null) { - foUserAgent = FopFactory.newInstance().newFOUserAgent(); - } this.stream = stream; diff --git a/src/java/org/apache/fop/apps/FopConfParser.java b/src/java/org/apache/fop/apps/FopConfParser.java new file mode 100644 index 000000000..4ab788701 --- /dev/null +++ b/src/java/org/apache/fop/apps/FopConfParser.java @@ -0,0 +1,359 @@ +/* + * 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.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; + +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.xmlgraphics.image.loader.spi.ImageImplRegistry; +import org.apache.xmlgraphics.image.loader.util.Penalty; + +import org.apache.fop.apps.io.DefaultResourceResolver; +import org.apache.fop.apps.io.ResourceResolver; +import org.apache.fop.apps.io.URIResolverWrapper; +import org.apache.fop.fonts.FontManagerConfigurator; +import org.apache.fop.hyphenation.HyphenationTreeCache; +import org.apache.fop.util.LogUtil; + +/** + * Parses the FOP configuration file and returns a {@link FopFactoryBuilder} which builds a + * {@link FopFactory}. + */ +public class FopConfParser { + + private static final String PREFER_RENDERER = "prefer-renderer"; + + private final Log log = LogFactory.getLog(FopConfParser.class); + + private final FopFactoryBuilder fopFactoryBuilder; + + /** + * Constructor that takes the FOP conf in the form of an {@link InputStream}. A default base URI + * must be given as a fall-back mechanism for URI resolution. + * + * @param fopConfStream the fop conf input stream + * @param enviro the profile of the FOP deployment environment + * @throws SAXException if a SAX error was thrown parsing the FOP conf + * @throws IOException if an I/O error is thrown while parsing the FOP conf + */ + public FopConfParser(InputStream fopConfStream, EnvironmentProfile enviro) + throws SAXException, IOException { + DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder(); + Configuration cfg; + try { + cfg = cfgBuilder.build(fopConfStream); + } catch (ConfigurationException e) { + throw new FOPException(e); + } + // The default base URI is taken from the directory in which the fopConf resides + fopFactoryBuilder = new FopFactoryBuilder(enviro).setConfiguration(cfg); + configure(enviro.getDefaultBaseURI(), enviro.getResourceResolver(), cfg); + } + + /** + * Constructor that takes the FOP conf in the form of an {@link InputStream}. A default base URI + * must be given as a fall-back mechanism for URI resolution. + * + * @param fopConfStream the fop conf input stream + * @param defaultBaseURI the default base URI + * @param resolver the URI resolver + * @throws SAXException if a SAX error was thrown parsing the FOP conf + * @throws IOException if an I/O error is thrown while parsing the FOP conf + */ + public FopConfParser(InputStream fopConfStream, URI defaultBaseURI, + ResourceResolver resolver) throws SAXException, IOException { + this(fopConfStream, EnvironmentalProfileFactory.createDefault(defaultBaseURI, resolver)); + } + + /** + * Constructor that takes the FOP conf in the form of an {@link InputStream}. A default base URI + * must be given as a fall-back mechanism for URI resolution. The default URI resolvers is used. + * + * @param fopConfStream the fop conf input stream + * @param defaultBaseURI the default base URI + * @throws SAXException if a SAX error was thrown parsing the FOP conf + * @throws IOException if an I/O error is thrown while parsing the FOP conf + */ + public FopConfParser(InputStream fopConfStream, URI defaultBaseURI) throws SAXException, + IOException { + this(fopConfStream, defaultBaseURI, new DefaultResourceResolver()); + } + + /** + * Constructor that takes the FOP conf and uses the default URI resolver. + * + * @param fopConfFile the FOP conf file + * @throws SAXException if a SAX error was thrown parsing the FOP conf + * @throws IOException if an I/O error is thrown while parsing the FOP conf + */ + public FopConfParser(File fopConfFile) throws SAXException, IOException { + this(fopConfFile, new DefaultResourceResolver()); + } + + /** + * Constructor that parses the FOP conf and uses the URI resolver given. + * + * @param fopConfFile the FOP conf file + * @param resolver the URI resolver + * @throws SAXException if a SAX error was thrown parsing the FOP conf + * @throws IOException if an I/O error is thrown while parsing the FOP conf + */ + public FopConfParser(File fopConfFile, ResourceResolver resolver) + throws SAXException, IOException { + this(new FileInputStream(fopConfFile), + fopConfFile.getAbsoluteFile().getParentFile().toURI(), resolver); + } + + private void configure(final URI defaultBaseURI, final ResourceResolver resolver, + Configuration cfg) throws FOPException { + if (log.isDebugEnabled()) { + log.debug("Initializing FopFactory Configuration"); + } + + // TODO: This makes this variable both strict FO and user-config validation, is that right? + boolean strict = false; + // strict fo validation + if (cfg.getChild("strict-validation", false) != null) { + try { + strict = cfg.getChild("strict-validation").getValueAsBoolean(); + fopFactoryBuilder.setStrictUserConfigValidation(strict); + } catch (ConfigurationException e) { + LogUtil.handleException(log, e, false); + } + } + + if (cfg.getChild("accessibility", false) != null) { + try { + fopFactoryBuilder.setAccessibility(cfg.getChild("accessibility").getValueAsBoolean()); + } catch (ConfigurationException e) { + LogUtil.handleException(log, e, false); + } + } + + // base definitions for relative path resolution + if (cfg.getChild("base", false) != null) { + try { + URI confUri = URIResolverWrapper.getBaseURI(cfg.getChild("base").getValue(null)); + fopFactoryBuilder.setBaseURI(defaultBaseURI.resolve(confUri)); + } catch (URISyntaxException use) { + LogUtil.handleException(log, use, strict); + } + } + + if (cfg.getChild("hyphenation-base", false) != null) { + String path = cfg.getChild("hyphenation-base").getValue(null); + if (defaultBaseURI != null) { + try { + URI hyphBaseUri = URIResolverWrapper.getBaseURI(path); + fopFactoryBuilder.setHyphenationBaseURI(defaultBaseURI.resolve(hyphBaseUri)); + } catch (URISyntaxException use) { + LogUtil.handleException(log, use, strict); + } + } + } + + // renderer options + if (cfg.getChild("source-resolution", false) != null) { + float srcRes = cfg.getChild("source-resolution").getValueAsFloat( + FopFactoryConfig.DEFAULT_SOURCE_RESOLUTION); + fopFactoryBuilder.setSourceResolution(srcRes); + if (log.isDebugEnabled()) { + log.debug("source-resolution set to: " + srcRes + "dpi"); + } + } + if (cfg.getChild("target-resolution", false) != null) { + float targetRes = cfg.getChild("target-resolution").getValueAsFloat( + FopFactoryConfig.DEFAULT_TARGET_RESOLUTION); + fopFactoryBuilder.setTargetResolution(targetRes); + if (log.isDebugEnabled()) { + log.debug("target-resolution set to: " + targetRes + "dpi"); + } + } + if (cfg.getChild("break-indent-inheritance", false) != null) { + try { + fopFactoryBuilder.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) { + String pageHeight = pageConfig.getAttribute("height", + FopFactoryConfig.DEFAULT_PAGE_HEIGHT); + fopFactoryBuilder.setPageHeight(pageHeight); + if (log.isInfoEnabled()) { + log.info("Default page-height set to: " + pageHeight); + } + } + if (pageConfig.getAttribute("width", null) != null) { + String pageWidth = pageConfig.getAttribute("width", + FopFactoryConfig.DEFAULT_PAGE_WIDTH); + fopFactoryBuilder.setPageWidth(pageWidth); + if (log.isInfoEnabled()) { + log.info("Default page-width set to: " + pageWidth); + } + } + + if (cfg.getChild("complex-scripts") != null) { + Configuration csConfig = cfg.getChild("complex-scripts"); + fopFactoryBuilder.setComplexScriptFeatures(!csConfig.getAttributeAsBoolean("disabled", + false)); + } + + setHyphPatNames(cfg, fopFactoryBuilder, strict); + + // prefer Renderer over IFDocumentHandler + if (cfg.getChild(PREFER_RENDERER, false) != null) { + try { + fopFactoryBuilder.setPreferRenderer( + cfg.getChild(PREFER_RENDERER).getValueAsBoolean()); + } catch (ConfigurationException e) { + LogUtil.handleException(log, e, strict); + } + } + + // configure font manager + new FontManagerConfigurator(cfg, fopFactoryBuilder.getBaseUri(), resolver).configure( + fopFactoryBuilder.getFontManager(), strict); + + // configure image loader framework + configureImageLoading(cfg.getChild("image-loading", false), strict); + } + + private void setHyphPatNames(Configuration cfg, FopFactoryBuilder builder, boolean strict) + throws FOPException { + Configuration[] hyphPatConfig = cfg.getChildren("hyphenation-pattern"); + if (hyphPatConfig.length != 0) { + Map<String, String> hyphPatNames = new HashMap<String, String>(); + for (int i = 0; i < hyphPatConfig.length; ++i) { + String lang; + String country; + String filename; + StringBuffer error = new StringBuffer(); + String location = hyphPatConfig[i].getLocation(); + + lang = hyphPatConfig[i].getAttribute("lang", null); + if (lang == null) { + addError("The lang attribute of a hyphenation-pattern configuration" + + " element must exist (" + location + ")", error); + } else if (!lang.matches("[a-zA-Z]{2}")) { + addError("The lang attribute of a hyphenation-pattern configuration" + + " element must consist of exactly two letters (" + + location + ")", error); + } + lang = lang.toLowerCase(); + + country = hyphPatConfig[i].getAttribute("country", null); + if ("".equals(country)) { + country = null; + } + if (country != null) { + if (!country.matches("[a-zA-Z]{2}")) { + addError("The country attribute of a hyphenation-pattern configuration" + + " element must consist of exactly two letters (" + + location + ")", error); + } + country = country.toUpperCase(); + } + + filename = hyphPatConfig[i].getValue(null); + if (filename == null) { + addError("The value of a hyphenation-pattern configuration" + + " element may not be empty (" + location + ")", error); + } + + if (error.length() != 0) { + LogUtil.handleError(log, error.toString(), strict); + continue; + } + + String llccKey = HyphenationTreeCache.constructLlccKey(lang, country); + hyphPatNames.put(llccKey, filename); + if (log.isDebugEnabled()) { + log.debug("Using hyphenation pattern filename " + filename + + " for lang=\"" + lang + "\"" + + (country != null ? ", country=\"" + country + "\"" : "")); + } + } + builder.setHyphPatNames(hyphPatNames); + } + } + + private static void addError(String message, StringBuffer error) { + if (error.length() != 0) { + error.append(". "); + } + error.append(message); + } + + private void configureImageLoading(Configuration parent, boolean strict) throws FOPException { + if (parent == null) { + return; + } + ImageImplRegistry registry = fopFactoryBuilder.getImageManager().getRegistry(); + Configuration[] penalties = parent.getChildren("penalty"); + try { + for (int i = 0, c = penalties.length; i < c; i++) { + Configuration penaltyCfg = penalties[i]; + String className = penaltyCfg.getAttribute("class"); + String value = penaltyCfg.getAttribute("value"); + Penalty p = null; + if (value.toUpperCase().startsWith("INF")) { + p = Penalty.INFINITE_PENALTY; + } else { + try { + p = Penalty.toPenalty(Integer.parseInt(value)); + } catch (NumberFormatException nfe) { + LogUtil.handleException(log, nfe, strict); + } + } + if (p != null) { + registry.setAdditionalPenalty(className, p); + } + } + } catch (ConfigurationException e) { + LogUtil.handleException(log, e, strict); + } + } + + /** + * Returns the {@link FopFactoryBuilder}. + * + * @return the object for configuring the {@link FopFactory} + */ + public FopFactoryBuilder getFopFactoryBuilder() { + return fopFactoryBuilder; + } +} diff --git a/src/java/org/apache/fop/apps/FopFactory.java b/src/java/org/apache/fop/apps/FopFactory.java index 18c84a036..9cb4edc27 100644 --- a/src/java/org/apache/fop/apps/FopFactory.java +++ b/src/java/org/apache/fop/apps/FopFactory.java @@ -21,18 +21,15 @@ package org.apache.fop.apps; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; -import java.net.MalformedURLException; import java.net.URI; -import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; -import javax.xml.transform.URIResolver; import org.xml.sax.SAXException; @@ -44,13 +41,15 @@ import org.apache.xmlgraphics.image.loader.ImageContext; import org.apache.xmlgraphics.image.loader.ImageManager; import org.apache.xmlgraphics.util.UnitConv; +import org.apache.fop.apps.io.URIResolverWrapper; import org.apache.fop.fo.ElementMapping; import org.apache.fop.fo.ElementMappingRegistry; -import org.apache.fop.fonts.FontCache; import org.apache.fop.fonts.FontManager; import org.apache.fop.hyphenation.HyphenationTreeResolver; import org.apache.fop.layoutmgr.LayoutManagerMaker; import org.apache.fop.render.ImageHandlerRegistry; +import org.apache.fop.render.RendererConfig; +import org.apache.fop.render.RendererConfig.RendererConfigParser; import org.apache.fop.render.RendererFactory; import org.apache.fop.render.XMLHandlerRegistry; import org.apache.fop.util.ColorSpaceCache; @@ -59,57 +58,48 @@ import org.apache.fop.util.ContentHandlerFactoryRegistry; /** * Factory class which instantiates new Fop and FOUserAgent instances. This * class also holds environmental information and configuration used by FOP. - * Information that may potentially be different for each rendering run can be + * Information that may potentially be different for each renderingq run can be * found and managed in the FOUserAgent. */ -public class FopFactory implements ImageContext { +public final class FopFactory implements ImageContext { /** logger instance */ private static Log log = LogFactory.getLog(FopFactory.class); /** Factory for Renderers and FOEventHandlers */ - private RendererFactory rendererFactory; + private final RendererFactory rendererFactory; /** Registry for XML handlers */ - private XMLHandlerRegistry xmlHandlers; + private final XMLHandlerRegistry xmlHandlers; /** Registry for image handlers */ - private ImageHandlerRegistry imageHandlers; + private final ImageHandlerRegistry imageHandlers; /** The registry for ElementMapping instances */ - private ElementMappingRegistry elementMappingRegistry; + private final ElementMappingRegistry elementMappingRegistry; /** The registry for ContentHandlerFactory instance */ - private ContentHandlerFactoryRegistry contentHandlerFactoryRegistry - = new ContentHandlerFactoryRegistry(); + private final ContentHandlerFactoryRegistry contentHandlerFactoryRegistry + = new ContentHandlerFactoryRegistry(); - /** The resolver for user-supplied hyphenation patterns */ - private HyphenationTreeResolver hyphResolver = null; + private final ColorSpaceCache colorSpaceCache; - private ColorSpaceCache colorSpaceCache = null; + private final FopFactoryConfig config; - /** Image manager for loading and caching image objects */ - private ImageManager imageManager; + private final URIResolverWrapper uriResolverWrapper; - /** Font manager for font substitution, autodetection and caching **/ - private FontManager fontManager; + private final Map<String, RendererConfig> rendererConfig; - /** Configuration layer used to configure fop */ - private FopFactoryConfigurator config = null; - - /** - * The base URL for all URL resolutions, especially for - * external-graphics. - */ - private String base = null; - - /** - * Controls if accessibility is turned on or off - */ - private boolean accessibility = false; - - /** The base URL for all hyphen URL resolutions. */ - private String hyphenBase = null; + private FopFactory(FopFactoryConfig config) { + this.config = config; + this.uriResolverWrapper = new URIResolverWrapper(config.getBaseURI(), config.getNewURIResolver()); + this.elementMappingRegistry = new ElementMappingRegistry(this); + this.colorSpaceCache = new ColorSpaceCache(config.getURIResolver()); + this.rendererFactory = new RendererFactory(config.preferRenderer()); + this.xmlHandlers = new XMLHandlerRegistry(); + this.imageHandlers = new ImageHandlerRegistry(); + rendererConfig = new HashMap<String, RendererConfig>(); + } /** * Map of configured names of hyphenation pattern file names: ll_CC => name @@ -121,73 +111,52 @@ public class FopFactory implements ImageContext { * input XSL violates that FO's content model. This is the default * behavior for FOP. However, this flag, if set, provides the user the * ability for FOP to halt on all content model violations if desired. + * Returns a new FopFactory instance that is configured using the {@link FopFactoryConfig} object. + * + * @param config the fop configuration + * @return the requested FopFactory instance. */ - private boolean strictFOValidation = FopFactoryConfigurator.DEFAULT_STRICT_FO_VALIDATION; + public static FopFactory newInstance(FopFactoryConfig config) { + return new FopFactory(config); + } /** - * FOP will validate the contents of the user configuration strictly - * (e.g. base-urls and font urls/paths). + * Returns a new FopFactory instance that is configured using the {@link FopFactoryConfig} object that + * is created when the fopConf is parsed. + * + * @param fopConf the fop conf configuration file to parse + * @return the requested FopFactory instance. + * @throws IOException + * @throws SAXException */ - private boolean strictUserConfigValidation - = FopFactoryConfigurator.DEFAULT_STRICT_USERCONFIG_VALIDATION; - - /** Source resolution in dpi */ - private float sourceResolution = FopFactoryConfigurator.DEFAULT_SOURCE_RESOLUTION; - - /** Target resolution in dpi */ - private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION; - - /** Page height */ - private String pageHeight = FopFactoryConfigurator.DEFAULT_PAGE_HEIGHT; - - /** Page width */ - private String pageWidth = FopFactoryConfigurator.DEFAULT_PAGE_WIDTH; - - /** Complex scripts support enabled */ - private boolean useComplexScriptFeatures - = FopFactoryConfigurator.DEFAULT_COMPLEX_SCRIPT_FEATURES; - - /** @see #setBreakIndentInheritanceOnReferenceAreaBoundary(boolean) */ - private boolean breakIndentInheritanceOnReferenceAreaBoundary - = FopFactoryConfigurator.DEFAULT_BREAK_INDENT_INHERITANCE; - - /** Optional overriding LayoutManagerMaker */ - private LayoutManagerMaker lmMakerOverride = null; - - private Set<String> ignoredNamespaces; - - private FOURIResolver foURIResolver; + public static FopFactory newInstance(File fopConf) throws SAXException, IOException { + return new FopConfParser(fopConf).getFopFactoryBuilder().build(); + } /** - * Main constructor. + * Returns a new FopFactory instance that is configured only by the default configuration + * parameters. + * + * @param baseURI the base URI to resolve resource URIs against + * @return the requested FopFactory instance. */ - protected FopFactory() { - this.config = new FopFactoryConfigurator(this); - this.elementMappingRegistry = new ElementMappingRegistry(this); - this.foURIResolver = new FOURIResolver(validateUserConfigStrictly()); - this.fontManager = new FontManager() { - - /** {@inheritDoc} */ - @Override - public void setFontBaseURL(String fontBase) throws MalformedURLException { - super.setFontBaseURL(getFOURIResolver().checkBaseURL(fontBase)); - } - - }; - this.colorSpaceCache = new ColorSpaceCache(foURIResolver); - this.imageManager = new ImageManager(this); - this.rendererFactory = new RendererFactory(); - this.xmlHandlers = new XMLHandlerRegistry(); - this.imageHandlers = new ImageHandlerRegistry(); - this.ignoredNamespaces = new java.util.HashSet<String>(); + public static FopFactory newInstance(URI baseURI) { + return new FopFactoryBuilder(baseURI).build(); } /** - * Returns a new FopFactory instance. + * Returns a new FopFactory instance that is configured using the {@link FopFactoryConfig} object that + * is created when the fopConf is parsed. + * + * @param baseURI the base URI to resolve resource URIs against + * @param confStream the fop conf configuration stream to parse * @return the requested FopFactory instance. + * @throws SAXException + * @throws IOException */ - public static FopFactory newInstance() { - return new FopFactory(); + public static FopFactory newInstance(URI baseURI, InputStream confStream) throws SAXException, + IOException { + return new FopConfParser(confStream, baseURI).getFopFactoryBuilder().build(); } /** @@ -198,34 +167,12 @@ public class FopFactory implements ImageContext { * @throws FOPException */ public FOUserAgent newFOUserAgent() { - FOUserAgent userAgent = new FOUserAgent(this); + FOUserAgent userAgent = new FOUserAgent(this, uriResolverWrapper); return userAgent; } - /** - * Sets accessibility support. - * - * @param value <code>true</code> to enable accessibility, <code>false</code> otherwise - */ - void setAccessibility(boolean value) { - this.accessibility = value; - } - - boolean isAccessibilityEnabled() { - return accessibility; - } - - /** - * Sets complex script support. - * @param value <code>true</code> to enable complex script features, - * <code>false</code> otherwise - */ - void setComplexScriptFeaturesEnabled(boolean value) { - this.useComplexScriptFeatures = value; - } - boolean isComplexScriptFeaturesEnabled() { - return useComplexScriptFeatures; + return config.isComplexScriptFeaturesEnabled(); } /** @@ -239,7 +186,7 @@ public class FopFactory implements ImageContext { * @throws FOPException when the constructor fails */ public Fop newFop(String outputFormat) throws FOPException { - return newFop(outputFormat, newFOUserAgent()); + return newFOUserAgent().newFop(outputFormat); } /** @@ -256,7 +203,7 @@ public class FopFactory implements ImageContext { * @throws FOPException when the constructor fails */ public Fop newFop(String outputFormat, FOUserAgent userAgent) throws FOPException { - return newFop(outputFormat, userAgent, null); + return userAgent.newFop(outputFormat, null); } /** @@ -271,7 +218,7 @@ public class FopFactory implements ImageContext { * @throws FOPException when the constructor fails */ public Fop newFop(String outputFormat, OutputStream stream) throws FOPException { - return newFop(outputFormat, newFOUserAgent(), stream); + return newFOUserAgent().newFop(outputFormat, stream); } /** @@ -290,11 +237,8 @@ public class FopFactory implements ImageContext { * @throws FOPException when the constructor fails */ public Fop newFop(String outputFormat, FOUserAgent userAgent, OutputStream stream) - throws FOPException { - if (userAgent == null) { - throw new NullPointerException("The userAgent parameter must not be null!"); - } - return new Fop(outputFormat, userAgent, stream); + throws FOPException { + return userAgent.newFop(outputFormat, stream); } /** @@ -343,11 +287,28 @@ public class FopFactory implements ImageContext { } /** - * Returns the image manager. - * @return the image manager - */ - public ImageManager getImageManager() { - return this.imageManager; + * Returns the renderer configuration object for a specific renderer given the parser and + * configuration to read. The renderer config is cached such that the {@link Configuration} is + * only parsed once per renderer, per FopFactory instance. + * + * @param userAgent the user agent + * @param cfg the configuration to be parsed + * @param configCreator the parser that creates the config object + * @return the config object + * @throws FOPException when an error occurs while creating the configuration object + */ + public RendererConfig getRendererConfig(FOUserAgent userAgent, Configuration cfg, + RendererConfigParser configCreator) throws FOPException { + RendererConfig config = rendererConfig.get(configCreator.getMimeType()); + if (config == null) { + try { + config = configCreator.build(userAgent, cfg); + rendererConfig.put(configCreator.getMimeType(), config); + } catch (Exception e) { + throw new FOPException(e); + } + } + return config; } /** @@ -359,143 +320,41 @@ public class FopFactory implements ImageContext { } /** - * Sets an explicit LayoutManagerMaker instance which overrides the one - * defined by the AreaTreeHandler. - * @param lmMaker the LayoutManagerMaker instance - */ - public void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker) { - this.lmMakerOverride = lmMaker; - } - - /** - * Returns the overriding LayoutManagerMaker instance, if any. - * @return the overriding LayoutManagerMaker or null - */ - public LayoutManagerMaker getLayoutManagerMakerOverride() { - return this.lmMakerOverride; - } - - /** - * Sets the base URL. - * @param base the base URL - * @throws MalformedURLException if there's a problem with a file URL + * Returns whether accessibility is enabled. + * @return true if accessibility is enabled */ - public void setBaseURL(String base) throws MalformedURLException { - this.base = foURIResolver.checkBaseURL(base); - } - - /** - * Returns the base URL. - * @return the base URL - */ - public String getBaseURL() { - return this.base; - } - - /** - * Sets the font base URL. - * @param fontBase font base URL - * @throws MalformedURLException if there's a problem with a file URL - * @deprecated use getFontManager().setFontBaseURL(fontBase) instead - */ - @Deprecated - public void setFontBaseURL(String fontBase) throws MalformedURLException { - getFontManager().setFontBaseURL(fontBase); - } - - /** - * @return the font base URL - * @deprecated use getFontManager().setFontBaseURL(fontBase) instead - */ - @Deprecated - public String getFontBaseURL() { - return getFontManager().getFontBaseURL(); - } - - /** @return the hyphen base URL */ - public String getHyphenBaseURL() { - return this.hyphenBase; - } - - /** - * Sets the hyphen base URL. - * @param hyphenBase hythen base URL - * @throws MalformedURLException if there's a problem with a file URL - * */ - public void setHyphenBaseURL(final String hyphenBase) throws MalformedURLException { - if (hyphenBase != null) { - setHyphenationTreeResolver( - new HyphenationTreeResolver() { - public Source resolve(String href) { - return resolveURI(href, hyphenBase); - } - }); - } - this.hyphenBase = foURIResolver.checkBaseURL(hyphenBase); - } - - /** - * @return the hyphPatNames - */ - public Map getHyphPatNames() { - return hyphPatNames; - } - - /** - * @param hyphPatNames the hyphPatNames to set - */ - public void setHyphPatNames(Map hyphPatNames) { - if (hyphPatNames == null) { - hyphPatNames = new HashMap(); - } - this.hyphPatNames = hyphPatNames; + boolean isAccessibilityEnabled() { + return config.isAccessibilityEnabled(); } /** - * 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. - * @param uriResolver the new URI resolver + * Returns the image manager. + * @return the image manager */ - public void setURIResolver(URIResolver uriResolver) { - foURIResolver.setCustomURIResolver(uriResolver); + public ImageManager getImageManager() { + return config.getImageManager(); } /** - * Returns the URI Resolver. - * @return the URI Resolver + * Returns the overriding LayoutManagerMaker instance, if any. + * @return the overriding LayoutManagerMaker or null */ - public URIResolver getURIResolver() { - return foURIResolver; + public LayoutManagerMaker getLayoutManagerMakerOverride() { + return config.getLayoutManagerMakerOverride(); } - /** - * Returns the FO URI Resolver. - * @return the FO URI Resolver - */ - public FOURIResolver getFOURIResolver() { - return foURIResolver; + /** @return the hyphen base URI */ + public String getHyphenBaseURI() { + return config.getHyphenationBaseURI().toASCIIString(); } /** @return the HyphenationTreeResolver for resolving user-supplied hyphenation patterns. */ public HyphenationTreeResolver getHyphenationTreeResolver() { - return this.hyphResolver; - } - - /** - * Sets the HyphenationTreeResolver to be used for resolving user-supplied hyphenation files. - * @param hyphResolver the HyphenationTreeResolver instance - */ - public void setHyphenationTreeResolver(HyphenationTreeResolver hyphResolver) { - this.hyphResolver = hyphResolver; + return config.getHyphenationTreeResolver(); } - /** - * Activates strict XSL content model validation for FOP - * Default is false (FOP will continue processing where it can) - * @param validateStrictly true to turn on strict validation - */ - public void setStrictValidation(boolean validateStrictly) { - this.strictFOValidation = validateStrictly; + public Map<String, String> getHyphPatNames() { + return config.getHyphPatNames(); } /** @@ -503,7 +362,7 @@ public class FopFactory implements ImageContext { * @return true of strict validation turned on, false otherwise */ public boolean validateStrictly() { - return strictFOValidation; + return config.validateStrictly(); } /** @@ -511,48 +370,12 @@ public class FopFactory implements ImageContext { * boundaries (for more info, see the javadoc for the relative member variable) */ public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() { - return breakIndentInheritanceOnReferenceAreaBoundary; - } - - /** - * Controls whether to enable a feature that breaks indent inheritance when crossing - * reference area boundaries. - * <p> - * This flag controls whether FOP will enable special code that breaks property - * inheritance for start-indent and end-indent when the evaluation of the inherited - * value would cross a reference area. This is described under - * http://wiki.apache.org/xmlgraphics-fop/IndentInheritance as is intended to - * improve interoperability with commercial FO implementations and to produce - * results that are more in line with the expectation of unexperienced FO users. - * Note: Enabling this features violates the XSL specification! - * @param value true to enable the feature - */ - public void setBreakIndentInheritanceOnReferenceAreaBoundary(boolean value) { - this.breakIndentInheritanceOnReferenceAreaBoundary = value; + return config.isBreakIndentInheritanceOnReferenceAreaBoundary(); } - /** - * @return true if kerning on base 14 fonts is enabled - * @deprecated use getFontManager().isBase14KerningEnabled() instead - */ - @Deprecated - public boolean isBase14KerningEnabled() { - return getFontManager().isBase14KerningEnabled(); - } - - /** - * Controls whether kerning is activated on base 14 fonts. - * @param value true if kerning should be activated - * @deprecated use getFontManager().setBase14KerningEnabled(boolean) instead - */ - @Deprecated - public void setBase14KerningEnabled(boolean value) { - getFontManager().setBase14KerningEnabled(value); - } - - /** @return the resolution for resolution-dependant input */ + /** @return the resolution for resolution-dependent input */ public float getSourceResolution() { - return this.sourceResolution; + return config.getSourceResolution(); } /** @@ -565,22 +388,9 @@ public class FopFactory implements ImageContext { return UnitConv.IN2MM / getSourceResolution(); } - /** - * Sets the source resolution in dpi. This value is used to interpret the pixel size - * of source documents like SVG images and bitmap images without resolution information. - * @param dpi resolution in dpi - */ - public void setSourceResolution(float dpi) { - this.sourceResolution = dpi; - if (log.isDebugEnabled()) { - log.debug("source-resolution set to: " + sourceResolution - + "dpi (px2mm=" + getSourcePixelUnitToMillimeter() + ")"); - } - } - /** @return the resolution for resolution-dependant output */ public float getTargetResolution() { - return this.targetResolution; + return config.getTargetResolution(); } /** @@ -590,25 +400,7 @@ public class FopFactory implements ImageContext { * @see #getTargetResolution() */ public float getTargetPixelUnitToMillimeter() { - return UnitConv.IN2MM / this.targetResolution; - } - - /** - * Sets the source resolution in dpi. This value is used to interpret the pixel size - * of source documents like SVG images and bitmap images without resolution information. - * @param dpi resolution in dpi - */ - public void setTargetResolution(float dpi) { - this.targetResolution = dpi; - } - - /** - * Sets the source resolution in dpi. This value is used to interpret the pixel size - * of source documents like SVG images and bitmap images without resolution information. - * @param dpi resolution in dpi - */ - public void setSourceResolution(int dpi) { - setSourceResolution((float)dpi); + return 25.4f / getTargetResolution(); } /** @@ -618,20 +410,7 @@ public class FopFactory implements ImageContext { * @return the page-height, as a String */ public String getPageHeight() { - return this.pageHeight; - } - - /** - * Sets the page-height to use as fallback, in case - * page-height="auto" - * - * @param pageHeight page-height as a String - */ - public void setPageHeight(String pageHeight) { - this.pageHeight = pageHeight; - if (log.isDebugEnabled()) { - log.debug("Default page-height set to: " + pageHeight); - } + return config.getPageHeight(); } /** @@ -641,40 +420,7 @@ public class FopFactory implements ImageContext { * @return the page-width, as a String */ public String getPageWidth() { - return this.pageWidth; - } - - /** - * Sets the page-width to use as fallback, in case - * page-width="auto" - * - * @param pageWidth page-width as a String - */ - public void setPageWidth(String pageWidth) { - this.pageWidth = pageWidth; - if (log.isDebugEnabled()) { - log.debug("Default page-width set to: " + pageWidth); - } - } - - /** - * Adds a namespace to the set of ignored namespaces. - * If FOP encounters a namespace which it cannot handle, it issues a warning except if this - * namespace is in the ignored set. - * @param namespaceURI the namespace URI - */ - public void ignoreNamespace(String namespaceURI) { - this.ignoredNamespaces.add(namespaceURI); - } - - /** - * Adds a collection of namespaces to the set of ignored namespaces. - * If FOP encounters a namespace which it cannot handle, it issues a warning except if this - * namespace is in the ignored set. - * @param namespaceURIs the namespace URIs - */ - public void ignoreNamespaces(Collection<String> namespaceURIs) { - this.ignoredNamespaces.addAll(namespaceURIs); + return config.getPageWidth(); } /** @@ -683,55 +429,17 @@ public class FopFactory implements ImageContext { * @return true if the namespace is ignored by FOP */ public boolean isNamespaceIgnored(String namespaceURI) { - return this.ignoredNamespaces.contains(namespaceURI); + return config.isNamespaceIgnored(namespaceURI); } /** @return the set of namespaces that are ignored by FOP */ public Set<String> getIgnoredNamespace() { - return Collections.unmodifiableSet(this.ignoredNamespaces); + return config.getIgnoredNamespaces(); } //------------------------------------------- Configuration stuff /** - * 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 { - config.setUserConfig(userConfigFile); - } - - /** - * 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 { - config.setUserConfig(uri); - } - - /** - * Set the user configuration. - * @param userConfig configuration - * @throws FOPException if a configuration problem occurs - */ - public void setUserConfig(Configuration userConfig) throws FOPException { - config.setUserConfig(userConfig); - } - - /** - * Set the base URI for the user configuration - * Useful for programmatic configurations - * @param baseURI the base URI - */ - public void setUserConfigBaseURI(URI baseURI) { - config.setBaseURI(baseURI); - } - - /** * Get the user configuration. * @return the user configuration */ @@ -741,59 +449,20 @@ public class FopFactory implements ImageContext { /** * Is the user configuration to be validated? - * @param strictUserConfigValidation strict user config validation - */ - public void setStrictUserConfigValidation(boolean strictUserConfigValidation) { - this.strictUserConfigValidation = strictUserConfigValidation; - this.foURIResolver.setThrowExceptions(strictUserConfigValidation); - } - - /** - * Is the user configuration to be validated? * @return if the user configuration should be validated */ public boolean validateUserConfigStrictly() { - return this.strictUserConfigValidation; + return config.validateUserConfigStrictly(); } //------------------------------------------- Font related stuff /** - * Whether or not to cache results of font triplet detection/auto-config - * @param useCache use cache or not - * @deprecated use getFontManager().setUseCache(boolean) instead - */ - @Deprecated - public void setUseCache(boolean useCache) { - getFontManager().setUseCache(useCache); - } - - /** - * Cache results of font triplet detection/auto-config? - * @return whether this factory is uses the cache - * @deprecated use getFontManager().useCache() instead - */ - @Deprecated - public boolean useCache() { - return getFontManager().useCache(); - } - - /** - * Returns the font cache instance used by this factory. - * @return the font cache - * @deprecated use getFontManager().getFontCache() instead - */ - @Deprecated - public FontCache getFontCache() { - return getFontManager().getFontCache(); - } - - /** * Returns the font manager. * @return the font manager */ public FontManager getFontManager() { - return this.fontManager; + return config.getFontManager(); } /** @@ -804,12 +473,12 @@ public class FopFactory implements ImageContext { * @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 + * @see org.apache.fop.apps.io.FOURIResolver */ public Source resolveURI(String href, String baseUri) { Source source = null; try { - source = foURIResolver.resolve(href, baseUri); + source = config.getURIResolver().resolve(href, baseUri); } catch (TransformerException e) { log.error("Attempt to resolve URI '" + href + "' failed: ", e); } @@ -825,5 +494,4 @@ public class FopFactory implements ImageContext { public ColorSpaceCache getColorSpaceCache() { return this.colorSpaceCache; } - } diff --git a/src/java/org/apache/fop/apps/FopFactoryBuilder.java b/src/java/org/apache/fop/apps/FopFactoryBuilder.java new file mode 100644 index 000000000..b2d134db0 --- /dev/null +++ b/src/java/org/apache/fop/apps/FopFactoryBuilder.java @@ -0,0 +1,744 @@ +/* + * 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.net.URI; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.xml.transform.URIResolver; + +import org.apache.avalon.framework.configuration.Configuration; + +import org.apache.xmlgraphics.image.loader.ImageContext; +import org.apache.xmlgraphics.image.loader.ImageManager; + +import org.apache.fop.apps.io.DefaultResourceResolver; +import org.apache.fop.apps.io.FOURIResolver; +import org.apache.fop.apps.io.ResourceResolver; +import org.apache.fop.fonts.FontManager; +import org.apache.fop.hyphenation.HyphenationTreeResolver; +import org.apache.fop.layoutmgr.LayoutManagerMaker; + +/** + * This is the builder class for {@link FopFactory}. Setters can be chained to + * make building a {@link FopFactory} object more concise and intuitive e.g. + * + * <pre> + * {@code + * FopFactoryBuilder fopFactoryBuilder = new FopFactoryBuilder(<URI>) + * .setURIResolver(<URIResolver>) + * .setPageHeight(<String>) + * .setPageWidth(<String>) + * .setStrictUserConfigValidation(<boolean>) + * ... etc ... + * FopFactory fopFactory = fopFactoryBuilder.build(); + * } + * </pre> + */ +public final class FopFactoryBuilder { + + private final FopFactoryConfig config; + + private FopFactoryConfigBuilder fopFactoryConfigBuilder; + + /** + * A builder class for {@link FopFactory} which can be used for setting configuration. This is + * a helper constructor that uses the default URI resolver implementation that FOP packages + * provide ({@link DefaultResourceResolver}). + * + * @param defaultBaseURI the default base URI for resolving URIs against + */ + public FopFactoryBuilder(URI defaultBaseURI) { + this(defaultBaseURI, new DefaultResourceResolver()); + } + + /** + * A builder class for {@link FopFactory} which can be used for setting configuration. + * + * @param defaultBaseURI the default base URI for resolving URIs against + * @param uriResolver the URI resolver + */ + public FopFactoryBuilder(URI defaultBaseURI, ResourceResolver uriResolver) { + this(EnvironmentalProfileFactory.createDefault(defaultBaseURI, uriResolver)); + } + + /** + * A builder class for {@link FopFactory} which can be used for setting configuration. + * + * @param enviro the profile of the FOP deployment environment + */ + public FopFactoryBuilder(EnvironmentProfile enviro) { + config = new FopFactoryConfigImpl(enviro); + fopFactoryConfigBuilder = new ActiveFopFactoryConfigBuilder((FopFactoryConfigImpl) config); + } + + /** + * Returns the {@link FopFactoryConfig} which is needed to get an instance of + * {@link FopFactory}. + * + * @return build the {@link FopFactoryConfig} + * @deprecated Exposing the {@link FopFactoryConfig} is only to maintain backwards compatibility + */ + public FopFactoryConfig buildConfig() { + fopFactoryConfigBuilder = CompletedFopFactoryConfigBuilder.INSTANCE; + return config; + } + + /** + * Builds an instance of the the {@link FopFactory}. + * + * @return the FopFactory instance + */ + public FopFactory build() { + return FopFactory.newInstance(buildConfig()); + } + + /** + * Gets the base URI used to resolve all URIs within FOP. + * + * @return the base URI + */ + URI getBaseUri() { + return config.getBaseURI(); + } + + /** + * Returns the {@link FontManager} used for managing the fonts within FOP. + * + * @return the font managing object + */ + public FontManager getFontManager() { + return config.getFontManager(); + } + + /** + * Return the {@link ImageManager} used for handling images through out FOP. + * + * @return the image manager + */ + public ImageManager getImageManager() { + return config.getImageManager(); + } + + /** + * Sets whether to include accessibility features in document creation. + * + * @param enableAccessibility true to set accessibility on + * @return <code>this</code> + */ + public FopFactoryBuilder setAccessibility(boolean enableAccessibility) { + fopFactoryConfigBuilder.setAccessibility(enableAccessibility); + return this; + } + + /** + * Sets the {@link LayoutManagerMaker} so that users can configure how FOP creates + * {@link LayoutManager}s. + * + * @param lmMaker he layout manager maker + * @return <code>this</code> + */ + public FopFactoryBuilder setLayoutManagerMakerOverride( + LayoutManagerMaker lmMaker) { + fopFactoryConfigBuilder.setLayoutManagerMakerOverride(lmMaker); + return this; + } + + /** + * Sets the URI resolver to be used for controlling FOP's file access. + * + * @param resolver the URI resolver + * @return <code>this</code> + * @deprecated this URIResolver will be phased out in favour of a unified URI resolution + * mechanism + */ + public FopFactoryBuilder setURIResolver(URIResolver resolver) { + fopFactoryConfigBuilder.setURIResolver(resolver); + return this; + } + + /** + * Sets the base URI, this will be used for resolving all URIs given to FOP. + * + * @param baseURI the base URI + * @return <code>this</code> + */ + public FopFactoryBuilder setBaseURI(URI baseURI) { + fopFactoryConfigBuilder.setBaseURI(baseURI); + return this; + } + + /** + * Sets the base URI for hyphenation data. + * + * @param hyphenationBase the hyphenation-base-URI + * @return <code>this</code> + * @deprecated this will be phased out in favour of a unified URI resolution mechanism + */ + public FopFactoryBuilder setHyphenationBaseURI(URI hyphenationBase) { + fopFactoryConfigBuilder.setHyphenationBaseURI(hyphenationBase); + return this; + } + + /** + * Sets the URI resolver specific to Hyphenation data. + * + * @param hyphResolver the hyphenation-URI-resolver + * @return <code>this</code> + * @deprecated this will be phased out in favour of a unified URI resolution mechanism + */ + public FopFactoryBuilder setHyphenationTreeResolver( + HyphenationTreeResolver hyphResolver) { + fopFactoryConfigBuilder.setHyphenationTreeResolver(hyphResolver); + return this; + + } + + /** + * Sets whether to perform strict validation on the FO used. + * + * @param validateStrictly true if the FO is to be strictly validated + * @return <code>this</code> + */ + public FopFactoryBuilder setStrictFOValidation(boolean validateStrictly) { + fopFactoryConfigBuilder.setStrictFOValidation(validateStrictly); + return this; + } + + /** + * Sets whether to perform strict alidation on the user-configuration. + * + * @param validateStrictly true if the fop conf is to be strictly validated + * @return <code>this</code> + */ + public FopFactoryBuilder setStrictUserConfigValidation( + boolean validateStrictly) { + fopFactoryConfigBuilder.setStrictUserConfigValidation(validateStrictly); + return this; + } + + /** + * Sets whether the indent inheritance should be broken when crossing reference area boundaries. + * + * @param value true to break inheritance when crossing reference area boundaries + * @return <code>this</code> + */ + public FopFactoryBuilder setBreakIndentInheritanceOnReferenceAreaBoundary( + boolean value) { + fopFactoryConfigBuilder.setBreakIndentInheritanceOnReferenceAreaBoundary(value); + return this; + } + + /** + * Sets the resolution of resolution-dependent input. + * + * @param dpi the source resolution + * @return <code>this</code> + */ + public FopFactoryBuilder setSourceResolution(float dpi) { + fopFactoryConfigBuilder.setSourceResolution(dpi); + return this; + } + + /** + * Sets the resolution of resolution-dependent output. + * + * @param dpi the target resolution + * @return <code>this</code> + */ + public FopFactoryBuilder setTargetResolution(float dpi) { + fopFactoryConfigBuilder.setTargetResolution(dpi); + return this; + } + + /** + * Sets the page height of the paginated output. + * + * @param pageHeight the page height + * @return <code>this</code> + */ + public FopFactoryBuilder setPageHeight(String pageHeight) { + fopFactoryConfigBuilder.setPageHeight(pageHeight); + return this; + } + + /** + * Sets the page width of the paginated output. + * + * @param pageWidth the page width + * @return <code>this</code> + */ + public FopFactoryBuilder setPageWidth(String pageWidth) { + fopFactoryConfigBuilder.setPageWidth(pageWidth); + return this; + } + + /** + * FOP will ignore the specified XML element namespace. + * + * @param namespaceURI the namespace URI to ignore + * @return <code>this</code> + */ + public FopFactoryBuilder ignoreNamespace(String namespaceURI) { + fopFactoryConfigBuilder.ignoreNamespace(namespaceURI); + return this; + } + + /** + * FOP will ignore the colletion of XML element namespaces. + * + * @param namespaceURIs a collection of namespace URIs to ignore + * @return <code>this</code> + */ + public FopFactoryBuilder ignoreNamespaces(Collection<String> namespaceURIs) { + fopFactoryConfigBuilder.ignoreNamespaces(namespaceURIs); + return this; + } + + /** + * Sets the Avalon configuration if a FOP conf is used. + * + * @param cfg the fop conf configuration + * @return <code>this</code> + */ + public FopFactoryBuilder setConfiguration(Configuration cfg) { + fopFactoryConfigBuilder.setConfiguration(cfg); + return this; + } + + /** + * Sets whether to chose a {@link Renderer} in preference to an + * {@link org.apache.fop.render.intermediate.IFDocumentHandler}. + * + * @see {@link RendererFactory} + * @param preferRenderer true to prefer {@link Renderer} + * @return <code>this</code> + */ + public FopFactoryBuilder setPreferRenderer(boolean preferRenderer) { + fopFactoryConfigBuilder.setPreferRenderer(preferRenderer); + return this; + } + + public FopFactoryBuilder setComplexScriptFeatures(boolean csf) { + fopFactoryConfigBuilder.setComplexScriptFeaturesEnabled(csf); + return this; + } + + public FopFactoryBuilder setHyphPatNames(Map<String, String> hyphPatNames) { + fopFactoryConfigBuilder.setHyphPatNames(hyphPatNames); + return this; + } + + public static class FopFactoryConfigImpl implements FopFactoryConfig { + + private final EnvironmentProfile enviro; + + private final ImageManager imageManager; + + private boolean accessibility; + + private LayoutManagerMaker layoutManagerMaker; + + private URI baseURI; + + private URI hyphenationBaseURI; + + private HyphenationTreeResolver hyphenationTreeResolver; + + private boolean hasStrictFOValidation = true; + + private boolean hasStrictUserValidation = FopFactoryConfig.DEFAULT_STRICT_USERCONFIG_VALIDATION; + + private boolean breakIndentInheritanceOnReferenceBoundary + = FopFactoryConfig.DEFAULT_BREAK_INDENT_INHERITANCE; + + private float sourceResolution = FopFactoryConfig.DEFAULT_SOURCE_RESOLUTION; + + private float targetResolution = FopFactoryConfig.DEFAULT_TARGET_RESOLUTION; + + private String pageHeight = FopFactoryConfig.DEFAULT_PAGE_HEIGHT; + + private String pageWidth = FopFactoryConfig.DEFAULT_PAGE_WIDTH; + + private Set<String> ignoredNamespaces = new HashSet<String>(); + + private URIResolver resolver; + + private Configuration cfg; + + private boolean preferRenderer; + + private boolean isComplexScript = true; + + private Map<String, String> hyphPatNames; + + private static final class ImageContextImpl implements ImageContext { + + private final FopFactoryConfig config; + + ImageContextImpl(FopFactoryConfig config) { + this.config = config; + } + + public float getSourceResolution() { + return config.getSourceResolution(); + } + } + + FopFactoryConfigImpl(EnvironmentProfile enviro) { + this.enviro = enviro; + this.baseURI = enviro.getDefaultBaseURI(); + this.imageManager = new ImageManager(new ImageContextImpl(this)); + this.resolver = new FOURIResolver(); + } + + /** {@inheritDoc} */ + public boolean isAccessibilityEnabled() { + return accessibility; + } + + /** {@inheritDoc} */ + public LayoutManagerMaker getLayoutManagerMakerOverride() { + return layoutManagerMaker; + } + + /** {@inheritDoc} */ + public ResourceResolver getNewURIResolver() { + return enviro.getResourceResolver(); + } + + /** {@inheritDoc} */ + public URIResolver getURIResolver() { + return resolver; + } + + /** {@inheritDoc} */ + public URI getBaseURI() { + return baseURI; + } + + /** {@inheritDoc} */ + public URI getHyphenationBaseURI() { + return hyphenationBaseURI; + } + + /** {@inheritDoc} */ + public HyphenationTreeResolver getHyphenationTreeResolver() { + return hyphenationTreeResolver; + } + + /** {@inheritDoc} */ + public boolean validateStrictly() { + return hasStrictFOValidation; + } + + /** {@inheritDoc} */ + public boolean validateUserConfigStrictly() { + return hasStrictUserValidation; + } + + /** {@inheritDoc} */ + public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() { + return breakIndentInheritanceOnReferenceBoundary; + } + + /** {@inheritDoc} */ + public float getSourceResolution() { + return sourceResolution; + } + + /** {@inheritDoc} */ + public float getTargetResolution() { + return targetResolution; + } + + /** {@inheritDoc} */ + public String getPageHeight() { + return pageHeight; + } + + /** {@inheritDoc} */ + public String getPageWidth() { + return pageWidth; + } + + /** {@inheritDoc} */ + public Set<String> getIgnoredNamespaces() { + return Collections.unmodifiableSet(ignoredNamespaces); + } + + /** {@inheritDoc} */ + public boolean isNamespaceIgnored(String namespace) { + return ignoredNamespaces.contains(namespace); + } + + /** {@inheritDoc} */ + public Configuration getUserConfig() { + return cfg; + } + + /** {@inheritDoc} */ + public boolean preferRenderer() { + return preferRenderer; + } + + /** {@inheritDoc} */ + public FontManager getFontManager() { + return enviro.getFontManager(); + } + + /** {@inheritDoc} */ + public ImageManager getImageManager() { + return imageManager; + } + + public boolean isComplexScriptFeaturesEnabled() { + return isComplexScript; + } + + public Map<String, String> getHyphPatNames() { + return hyphPatNames; + } + } + + private interface FopFactoryConfigBuilder { + + void setAccessibility(boolean enableAccessibility); + + void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker); + + void setURIResolver(URIResolver resolver); + + void setBaseURI(URI baseURI); + + void setHyphenationBaseURI(URI hyphenationBase); + + void setHyphenationTreeResolver(HyphenationTreeResolver hyphResolver); + + void setStrictFOValidation(boolean validateStrictly); + + void setStrictUserConfigValidation(boolean validateStrictly); + + void setBreakIndentInheritanceOnReferenceAreaBoundary(boolean value); + + void setSourceResolution(float dpi); + + void setTargetResolution(float dpi); + + void setPageHeight(String pageHeight); + + void setPageWidth(String pageWidth); + + void ignoreNamespace(String namespaceURI); + + void ignoreNamespaces(Collection<String> namespaceURIs); + + void setConfiguration(Configuration cfg); + + void setPreferRenderer(boolean preferRenderer); + + void setComplexScriptFeaturesEnabled(boolean csf); + + void setHyphPatNames(Map<String, String> hyphPatNames); + } + + private static final class CompletedFopFactoryConfigBuilder implements FopFactoryConfigBuilder { + + private static final CompletedFopFactoryConfigBuilder INSTANCE + = new CompletedFopFactoryConfigBuilder(); + + private void throwIllegalStateException() { + throw new IllegalStateException("The final FOP Factory configuration has already been built"); + } + + public void setAccessibility(boolean enableAccessibility) { + throwIllegalStateException(); + } + + public void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker) { + throwIllegalStateException(); + + } + + public void setURIResolver(URIResolver resolver) { + throwIllegalStateException(); + } + + public void setBaseURI(URI baseURI) { + throwIllegalStateException(); + } + + public void setHyphenationBaseURI(URI hyphenationBase) { + throwIllegalStateException(); + } + + public void setHyphenationTreeResolver( + HyphenationTreeResolver hyphResolver) { + throwIllegalStateException(); + } + + public void setStrictFOValidation(boolean validateStrictly) { + throwIllegalStateException(); + } + + public void setStrictUserConfigValidation(boolean validateStrictly) { + throwIllegalStateException(); + } + + public void setBreakIndentInheritanceOnReferenceAreaBoundary( + boolean value) { + throwIllegalStateException(); + } + + public void setSourceResolution(float dpi) { + throwIllegalStateException(); + } + + public void setTargetResolution(float dpi) { + throwIllegalStateException(); + } + + public void setPageHeight(String pageHeight) { + throwIllegalStateException(); + } + + public void setPageWidth(String pageWidth) { + throwIllegalStateException(); + } + + public void ignoreNamespace(String namespaceURI) { + throwIllegalStateException(); + } + + public void ignoreNamespaces(Collection<String> namespaceURIs) { + throwIllegalStateException(); + } + + public void setConfiguration(Configuration cfg) { + throwIllegalStateException(); + } + + public void setPreferRenderer(boolean preferRenderer) { + throwIllegalStateException(); + } + + public void setComplexScriptFeaturesEnabled(boolean csf) { + throwIllegalStateException(); + } + + public void setHyphPatNames(Map<String, String> hyphPatNames) { + throwIllegalStateException(); + } + + } + + private static final class ActiveFopFactoryConfigBuilder implements FopFactoryConfigBuilder { + + private final FopFactoryConfigImpl config; + + private ActiveFopFactoryConfigBuilder(FopFactoryConfigImpl config) { + this.config = config; + } + + public void setAccessibility(boolean enableAccessibility) { + config.accessibility = enableAccessibility; + } + + public void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker) { + config.layoutManagerMaker = lmMaker; + } + + public void setURIResolver(URIResolver resolver) { + config.resolver = resolver; + } + + public void setBaseURI(URI baseURI) { + config.baseURI = baseURI; + } + + public void setHyphenationBaseURI(URI hyphenationBase) { + config.hyphenationBaseURI = hyphenationBase; + } + + public void setHyphenationTreeResolver(HyphenationTreeResolver hyphResolver) { + config.hyphenationTreeResolver = hyphResolver; + } + + public void setStrictFOValidation(boolean validateStrictly) { + config.hasStrictFOValidation = validateStrictly; + } + + public void setStrictUserConfigValidation( + boolean validateStrictly) { + config.hasStrictUserValidation = validateStrictly; + } + + public void setBreakIndentInheritanceOnReferenceAreaBoundary( + boolean value) { + config.breakIndentInheritanceOnReferenceBoundary = value; + } + + public void setSourceResolution(float dpi) { + config.sourceResolution = dpi; + } + + public void setTargetResolution(float dpi) { + config.targetResolution = dpi; + } + + public void setPageHeight(String pageHeight) { + config.pageHeight = pageHeight; + } + + public void setPageWidth(String pageWidth) { + config.pageWidth = pageWidth; + } + + public void ignoreNamespace(String namespaceURI) { + config.ignoredNamespaces.add(namespaceURI); + } + + public void ignoreNamespaces( + Collection<String> namespaceURIs) { + config.ignoredNamespaces.addAll(namespaceURIs); + } + + public void setConfiguration(Configuration cfg) { + config.cfg = cfg; + } + + public void setPreferRenderer(boolean preferRenderer) { + config.preferRenderer = preferRenderer; + } + + public void setComplexScriptFeaturesEnabled(boolean csf) { + config.isComplexScript = csf; + } + + public void setHyphPatNames(Map<String, String> hyphPatNames) { + config.hyphPatNames = hyphPatNames; + } + } + +} diff --git a/src/java/org/apache/fop/apps/FopFactoryConfig.java b/src/java/org/apache/fop/apps/FopFactoryConfig.java new file mode 100644 index 000000000..792f2fa04 --- /dev/null +++ b/src/java/org/apache/fop/apps/FopFactoryConfig.java @@ -0,0 +1,159 @@ +/* + * 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.net.URI; +import java.util.Map; +import java.util.Set; + +import javax.xml.transform.URIResolver; + +import org.apache.avalon.framework.configuration.Configuration; + +import org.apache.xmlgraphics.image.loader.ImageManager; + +import org.apache.fop.apps.io.ResourceResolver; +import org.apache.fop.fonts.FontManager; +import org.apache.fop.hyphenation.HyphenationTreeResolver; +import org.apache.fop.layoutmgr.LayoutManagerMaker; + +/** + * The configuration data for a {@link FopFactory} instance. + */ +public interface FopFactoryConfig { + + /** Defines if FOP should use an alternative rule to determine text indents */ + boolean DEFAULT_BREAK_INDENT_INHERITANCE = false; + + /** Defines if FOP should validate the user config strictly */ + boolean DEFAULT_STRICT_USERCONFIG_VALIDATION = true; + + /** Defines if FOP should use strict validation for FO and user config */ + boolean DEFAULT_STRICT_FO_VALIDATION = true; + + /** Defines the default page-width */ + String DEFAULT_PAGE_WIDTH = "8.26in"; + + /** Defines the default page-height */ + String DEFAULT_PAGE_HEIGHT = "11in"; + + /** Defines the default source resolution (72dpi) for FOP */ + float DEFAULT_SOURCE_RESOLUTION = 72.0f; //dpi + + /** Defines the default target resolution (72dpi) for FOP */ + float DEFAULT_TARGET_RESOLUTION = 72.0f; //dpi + + /** + * Whether accessibility features are switched on. + * + * @return true if accessibility features have been requested + */ + boolean isAccessibilityEnabled(); + + /** @see {@link FopFactory#getLayoutManagerMakerOverride()} */ + LayoutManagerMaker getLayoutManagerMakerOverride(); + + /** + * The URI resolver used through-out FOP for controlling all file access. + * + * @return the URI resolver + */ + ResourceResolver getNewURIResolver(); + + /** + * The URI resolver for controlling file access. + * + * @return the URI resolver + * @deprecated please use the {@link #getNewURIResolver()} method. + */ + URIResolver getURIResolver(); + + /** + * The base URI from which URIs are resolved against. + * + * @return the base URI + */ + URI getBaseURI(); + + /** + * The base URI of hyphenation data. + * + * @return the hyphenation-base-URI + * @deprecated this intelligence can be configured in the URI resolver set in + * {@link #getNewURIResolver()} + */ + URI getHyphenationBaseURI(); + + /** + * The URI resolver for resolving hyphenation data. + * + * @return the hyphenation-URI-resolver + * @deprecated this intelligence can be configured in the URI resolver set in + * {@link #getNewURIResolver()} + */ + HyphenationTreeResolver getHyphenationTreeResolver(); + + /** @see {@link FopFactory#validateStrictly()} */ + boolean validateStrictly(); + + /** @see {@link FopFactory#validateUserConfigStrictly()} */ + boolean validateUserConfigStrictly(); + + /** @see {@link FopFactory#isBreakIndentInheritanceOnReferenceAreaBoundary()} */ + boolean isBreakIndentInheritanceOnReferenceAreaBoundary(); + + /** @see {@link FopFactory#getSourceResolution()} */ + float getSourceResolution(); + + /** @see {@link FopFactory#getTargetResolution()} */ + float getTargetResolution(); + + /** @see {@link FopFactory#getPageHeight()} */ + String getPageHeight(); + + /** @see {@link FopFactory#getPageWidth()} */ + String getPageWidth(); + + /** @see {@link FopFactory#getIgnoredNamespace()} */ + Set<String> getIgnoredNamespaces(); + + /** @see {@link FopFactory#isNamespaceIgnored(String)} */ + boolean isNamespaceIgnored(String namespace); + + /** + * Returns the Avalon {@link Configuration} object. + * + * @return the Avalon config object + */ + Configuration getUserConfig(); + + /** @see {@link org.apache.fop.render.RendererFactory#isRendererPreferred()} */ + boolean preferRenderer(); + + /** @see {@link FopFactory#getFontManager()} */ + FontManager getFontManager(); + + /** @see {@link FopFactory#getImageManager()} */ + ImageManager getImageManager(); + + boolean isComplexScriptFeaturesEnabled(); + + Map<String, String> getHyphPatNames(); +} diff --git a/src/java/org/apache/fop/apps/FopFactoryConfigurator.java b/src/java/org/apache/fop/apps/FopFactoryConfigurator.java deleted file mode 100644 index c1555a7e7..000000000 --- a/src/java/org/apache/fop/apps/FopFactoryConfigurator.java +++ /dev/null @@ -1,406 +0,0 @@ -/* - * 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 java.net.URI; -import java.net.URISyntaxException; -import java.util.HashMap; -import java.util.Map; - -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.xmlgraphics.image.GraphicsConstants; -import org.apache.xmlgraphics.image.loader.spi.ImageImplRegistry; -import org.apache.xmlgraphics.image.loader.util.Penalty; - -import org.apache.fop.fonts.FontManagerConfigurator; -import org.apache.fop.hyphenation.HyphenationTreeCache; -import org.apache.fop.util.LogUtil; - -/** - * 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 = GraphicsConstants.DEFAULT_DPI; //dpi - - /** Defines the default target resolution (72dpi) for FOP */ - public static final float DEFAULT_TARGET_RESOLUTION = GraphicsConstants.DEFAULT_DPI; //dpi - - /** Defines the default complex script support */ - public static final boolean DEFAULT_COMPLEX_SCRIPT_FEATURES = true; - - private static final String PREFER_RENDERER = "prefer-renderer"; - - /** logger instance */ - private final Log log = LogFactory.getLog(FopFactoryConfigurator.class); - - /** Fop factory */ - private FopFactory factory = null; - - /** Fop factory configuration */ - private Configuration cfg = null; - - /** The base URI of the configuration file **/ - private URI baseURI = 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 { // CSOK: MethodLength - // 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(); - if (log.isDebugEnabled()) { - log.debug("Initializing FopFactory Configuration" - + "with " + (strict ? "strict" : "permissive") + " validation"); - } - - if (cfg.getChild("accessibility", false) != null) { - try { - this.factory.setAccessibility( - cfg.getChild("accessibility").getValueAsBoolean()); - } catch (ConfigurationException e) { - LogUtil.handleException(log, e, strict); - } - } - - // 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) { - String path = cfg.getChild("base").getValue(null); - if (baseURI != null) { - path = baseURI.resolve(path).normalize().toString(); - } - try { - factory.setBaseURL(path); - } catch (MalformedURLException mfue) { - LogUtil.handleException(log, mfue, strict); - } - } - if (cfg.getChild("hyphenation-base", false) != null) { - String path = cfg.getChild("hyphenation-base").getValue(null); - if (baseURI != null) { - path = baseURI.resolve(path).normalize().toString(); - } - try { - factory.setHyphenBaseURL(path); - } catch (MalformedURLException mfue) { - LogUtil.handleException(log, mfue, strict); - } - } - - /** - * Read configuration elements hyphenation-pattern, - * construct a map ll_CC => filename, and set it on the factory - */ - Configuration[] hyphPatConfig = cfg.getChildren("hyphenation-pattern"); - if (hyphPatConfig.length != 0) { - Map/*<String,String>*/ hyphPatNames = new HashMap/*<String,String>*/(); - for (int i = 0; i < hyphPatConfig.length; ++i) { - String lang; - String country; - String filename; - StringBuffer error = new StringBuffer(); - String location = hyphPatConfig[i].getLocation(); - - lang = hyphPatConfig[i].getAttribute("lang", null); - if (lang == null) { - addError("The lang attribute of a hyphenation-pattern configuration" - + " element must exist (" + location + ")", error); - } else if (!lang.matches("[a-zA-Z]{2}")) { - addError("The lang attribute of a hyphenation-pattern configuration" - + " element must consist of exactly two letters (" - + location + ")", error); - } - lang = lang.toLowerCase(); - - country = hyphPatConfig[i].getAttribute("country", null); - if ("".equals(country)) { - country = null; - } - if (country != null) { - if (!country.matches("[a-zA-Z]{2}")) { - addError("The country attribute of a hyphenation-pattern configuration" - + " element must consist of exactly two letters (" - + location + ")", error); - } - country = country.toUpperCase(); - } - - filename = hyphPatConfig[i].getValue(null); - if (filename == null) { - addError("The value of a hyphenation-pattern configuration" - + " element may not be empty (" + location + ")", error); - } - - if (error.length() != 0) { - LogUtil.handleError(log, error.toString(), strict); - continue; - } - - String llccKey = HyphenationTreeCache.constructLlccKey(lang, country); - hyphPatNames.put(llccKey, filename); - if (log.isDebugEnabled()) { - log.debug("Using hyphenation pattern filename " + filename - + " for lang=\"" + lang + "\"" - + (country != null ? ", country=\"" + country + "\"" : "")); - } - } - factory.setHyphPatNames(hyphPatNames); - } - - // 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()); - } - } - - // prefer Renderer over IFDocumentHandler - if (cfg.getChild(PREFER_RENDERER, false) != null) { - try { - factory.getRendererFactory().setRendererPreferred( - cfg.getChild(PREFER_RENDERER).getValueAsBoolean()); - } catch (ConfigurationException e) { - LogUtil.handleException(log, e, strict); - } - } - - // configure complex script support - Configuration csConfig = cfg.getChild("complex-scripts"); - if (csConfig != null) { - this.factory.setComplexScriptFeaturesEnabled - (!csConfig.getAttributeAsBoolean ( "disabled", false )); - } - - // configure font manager - new FontManagerConfigurator(cfg, baseURI).configure(factory.getFontManager(), strict); - - // configure image loader framework - configureImageLoading(cfg.getChild("image-loading", false), strict); - } - - private static void addError(String message, StringBuffer error) { - if (error.length() != 0) { - error.append(". "); - } - error.append(message); - } - - private void configureImageLoading(Configuration parent, boolean strict) throws FOPException { - if (parent == null) { - return; - } - ImageImplRegistry registry = factory.getImageManager().getRegistry(); - Configuration[] penalties = parent.getChildren("penalty"); - try { - for (int i = 0, c = penalties.length; i < c; i++) { - Configuration penaltyCfg = penalties[i]; - String className = penaltyCfg.getAttribute("class"); - String value = penaltyCfg.getAttribute("value"); - Penalty p = null; - if (value.toUpperCase().startsWith("INF")) { - p = Penalty.INFINITE_PENALTY; - } else { - try { - p = Penalty.toPenalty(Integer.parseInt(value)); - } catch (NumberFormatException nfe) { - LogUtil.handleException(log, nfe, strict); - } - } - if (p != null) { - registry.setAdditionalPenalty(className, p); - } - } - } catch (ConfigurationException e) { - LogUtil.handleException(log, e, 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; - setBaseURI(); - configure(this.factory); - } - - /** - * Get the avalon user configuration. - * @return the user configuration - */ - public Configuration getUserConfig() { - return this.cfg; - } - - /** - * @return the baseURI - */ - public URI getBaseURI() { - return baseURI; - } - - /** - * @param baseURI the baseURI to set - */ - public void setBaseURI(URI baseURI) { - this.baseURI = baseURI; - } - - private void setBaseURI() throws FOPException { - String loc = cfg.getLocation(); - try { - if (loc != null && loc.startsWith("file:")) { - baseURI = new URI(loc); - baseURI = baseURI.resolve(".").normalize(); - } - if (baseURI == null) { - baseURI = new File(System.getProperty("user.dir")).toURI(); - } - } catch (URISyntaxException e) { - throw new FOPException(e); - } - } - -} diff --git a/src/java/org/apache/fop/apps/io/DefaultResourceResolver.java b/src/java/org/apache/fop/apps/io/DefaultResourceResolver.java new file mode 100644 index 000000000..af04f218a --- /dev/null +++ b/src/java/org/apache/fop/apps/io/DefaultResourceResolver.java @@ -0,0 +1,49 @@ +/* + * 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.io; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URI; + + +public class DefaultResourceResolver implements ResourceResolver { + + public Resource getResource(URI uri) throws IOException { + try { + return new Resource(uri.toURL().openStream()); + } catch (MalformedURLException mue) { + throw new RuntimeException(mue); + } + } + + public OutputStream getOutputStream(URI uri) throws IOException { + throw new UnsupportedOperationException(); + } + + public static URIResolverWrapper createDefaultWrapper() { + // Not sure if this is the right place for this, but I don't have any better ideas as of yet + URI thisUri = new File(".").getAbsoluteFile().toURI(); + return new URIResolverWrapper(thisUri, new DefaultResourceResolver()); + } + +} diff --git a/src/java/org/apache/fop/apps/FOURIResolver.java b/src/java/org/apache/fop/apps/io/FOURIResolver.java index a1d7fd673..b73c67fa8 100644 --- a/src/java/org/apache/fop/apps/FOURIResolver.java +++ b/src/java/org/apache/fop/apps/io/FOURIResolver.java @@ -17,7 +17,7 @@ /* $Id$ */ -package org.apache.fop.apps; +package org.apache.fop.apps.io; import java.io.ByteArrayOutputStream; import java.io.File; @@ -37,6 +37,7 @@ import javax.xml.transform.stream.StreamSource; import org.apache.commons.io.FileUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.apps.FOUserAgent; import org.apache.xmlgraphics.util.io.Base64EncodeStream; import org.apache.xmlgraphics.util.uri.CommonURIResolver; diff --git a/src/java/org/apache/fop/apps/io/Resource.java b/src/java/org/apache/fop/apps/io/Resource.java new file mode 100644 index 000000000..0a8b8c22a --- /dev/null +++ b/src/java/org/apache/fop/apps/io/Resource.java @@ -0,0 +1,59 @@ +/* + * 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.io; + +import java.io.FilterInputStream; +import java.io.InputStream; + +/** + * This class represents a resolved resource. The type property is used by FOP to identify the resource + * content. + * + */ +public class Resource extends FilterInputStream { + + private final String type; + + /** + * @param type resource type + * @param inputStream input stream of the resource + */ + public Resource(String type, InputStream inputStream) { + super(inputStream); + this.type = type; + } + + /** + * Constructs a resource of 'unknown' type. + * + * @param inputStream input stream of the resource + */ + public Resource(InputStream inputStream) { + this("unknown", inputStream); + } + + /** + * @return the resource type + */ + public String getType() { + return this.type; + } + +} diff --git a/src/java/org/apache/fop/render/ps/PSConfigurationConstants.java b/src/java/org/apache/fop/apps/io/ResourceResolver.java index 6b3550f57..3d20aaebc 100644 --- a/src/java/org/apache/fop/render/ps/PSConfigurationConstants.java +++ b/src/java/org/apache/fop/apps/io/ResourceResolver.java @@ -17,17 +17,16 @@ /* $Id$ */ -package org.apache.fop.render.ps; +package org.apache.fop.apps.io; -/** - * Constants used for configuring PostScript output. - */ -public interface PSConfigurationConstants { +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; + +public interface ResourceResolver { + + Resource getResource(URI uri) throws IOException; + + OutputStream getOutputStream(URI uri) throws IOException; - /** Controls the behaviour for landscape pages */ - String AUTO_ROTATE_LANDSCAPE = "auto-rotate-landscape"; - /** Controls whether resources are optimized (rather than inlined) */ - String OPTIMIZE_RESOURCES = "optimize-resources"; - /** Determines the PostScript language level to be generated */ - String LANGUAGE_LEVEL = "language-level"; } diff --git a/src/java/org/apache/fop/apps/io/URIResolverWrapper.java b/src/java/org/apache/fop/apps/io/URIResolverWrapper.java new file mode 100644 index 000000000..7ff912089 --- /dev/null +++ b/src/java/org/apache/fop/apps/io/URIResolverWrapper.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.apps.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; + + +public class URIResolverWrapper { + private final URI baseUri; + private final ResourceResolver uriResolver; + + public URIResolverWrapper(URI baseUri, ResourceResolver uriResolver) { + this.baseUri = baseUri; + this.uriResolver = uriResolver; + } + + public URI getBaseURI() { + return baseUri; + } + + public InputStream resolveIn(String stringUri) throws IOException, URISyntaxException { + return resolveIn(cleanURI(stringUri)); + } + + public InputStream resolveIn(URI uri) throws IOException { + return uriResolver.getResource(resolveFromBase(uri)); + } + + public OutputStream resolveOut(URI uri) throws IOException { + return uriResolver.getOutputStream(resolveFromBase(uri)); + } + + private URI resolveFromBase(URI uri) { + return baseUri.resolve(uri); + } + + public static URI cleanURI(String base) throws URISyntaxException { + // replace back slash with forward slash to ensure windows file:/// URLS are supported + if (base == null) { + return null; + } + String fixedUri = base.replace('\\', '/'); + fixedUri = fixedUri.replace(" ", "%20"); + URI baseURI = new URI(fixedUri); + return baseURI; + } + + public static URI getBaseURI(String base) throws URISyntaxException { + String path = base + (base.endsWith("/") ? "" : "/"); + return cleanURI(path); + } + +} diff --git a/src/java/org/apache/fop/apps/io/package.html b/src/java/org/apache/fop/apps/io/package.html new file mode 100644 index 000000000..d631dc998 --- /dev/null +++ b/src/java/org/apache/fop/apps/io/package.html @@ -0,0 +1,6 @@ +<HTML> +<TITLE>org.apache.fop.io Package</TITLE> +<BODY> +<P>Classes that control all IO in FOP.</P> +</BODY> +</HTML>
\ No newline at end of file diff --git a/src/java/org/apache/fop/area/AreaTreeHandler.java b/src/java/org/apache/fop/area/AreaTreeHandler.java index c87a728e6..71d22f6d9 100644 --- a/src/java/org/apache/fop/area/AreaTreeHandler.java +++ b/src/java/org/apache/fop/area/AreaTreeHandler.java @@ -104,7 +104,7 @@ public class AreaTreeHandler extends FOEventHandler { setupModel(userAgent, outputFormat, stream); - this.lmMaker = userAgent.getFactory().getLayoutManagerMakerOverride(); + this.lmMaker = userAgent.getLayoutManagerMakerOverride(); if (lmMaker == null) { lmMaker = new LayoutManagerMapping(); } diff --git a/src/java/org/apache/fop/area/AreaTreeParser.java b/src/java/org/apache/fop/area/AreaTreeParser.java index ebb35f9bf..e965d15fc 100644 --- a/src/java/org/apache/fop/area/AreaTreeParser.java +++ b/src/java/org/apache/fop/area/AreaTreeParser.java @@ -132,7 +132,7 @@ public class AreaTreeParser { */ public ContentHandler getContentHandler(AreaTreeModel treeModel, FOUserAgent userAgent) { ElementMappingRegistry elementMappingRegistry - = userAgent.getFactory().getElementMappingRegistry(); + = userAgent.getElementMappingRegistry(); return new Handler(treeModel, userAgent, elementMappingRegistry); } @@ -292,7 +292,7 @@ public class AreaTreeParser { } } else { ContentHandlerFactoryRegistry registry - = userAgent.getFactory().getContentHandlerFactoryRegistry(); + = userAgent.getContentHandlerFactoryRegistry(); ContentHandlerFactory factory = registry.getFactory(uri); if (factory != null) { delegate = factory.createContentHandler(); @@ -1102,7 +1102,7 @@ public class AreaTreeParser { bkg.setURL(uri); try { - ImageManager manager = userAgent.getFactory().getImageManager(); + ImageManager manager = userAgent.getImageManager(); ImageSessionContext sessionContext = userAgent.getImageSessionContext(); ImageInfo info = manager.getImageInfo(uri, sessionContext); diff --git a/src/java/org/apache/fop/cli/CommandLineOptions.java b/src/java/org/apache/fop/cli/CommandLineOptions.java index 7d5752d6d..e0cf0fbb6 100644 --- a/src/java/org/apache/fop/cli/CommandLineOptions.java +++ b/src/java/org/apache/fop/cli/CommandLineOptions.java @@ -39,9 +39,10 @@ import org.apache.fop.Version; import org.apache.fop.accessibility.Accessibility; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.FopConfParser; import org.apache.fop.apps.FopFactory; +import org.apache.fop.apps.FopFactoryBuilder; import org.apache.fop.apps.MimeConstants; -import org.apache.fop.fonts.FontManager; import org.apache.fop.pdf.PDFAMode; import org.apache.fop.pdf.PDFEncryptionManager; import org.apache.fop.pdf.PDFEncryptionParams; @@ -51,12 +52,13 @@ import org.apache.fop.render.awt.AWTRenderer; import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFDocumentHandler; import org.apache.fop.render.intermediate.IFSerializer; -import org.apache.fop.render.pdf.PDFConfigurationConstants; import org.apache.fop.render.print.PagesMode; import org.apache.fop.render.print.PrintRenderer; import org.apache.fop.render.xml.XMLRenderer; import org.apache.fop.util.CommandLineLogger; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.ENCRYPTION_PARAMS; + /** * Options parses the commandline arguments */ @@ -116,12 +118,14 @@ public class CommandLineOptions { private Map renderingOptions = new java.util.HashMap(); /* target resolution (for the user agent) */ private int targetResolution = 0; + + private boolean strictValidation = true; /* control memory-conservation policy */ private boolean conserveMemoryPolicy = false; /* true if a complex script features are enabled */ private boolean useComplexScriptFeatures = true; - private FopFactory factory = FopFactory.newInstance(); + private FopFactory factory; private FOUserAgent foUserAgent; private InputHandler inputHandler; @@ -183,9 +187,10 @@ public class CommandLineOptions { addXSLTParameter("fop-output-format", getOutputFormat()); addXSLTParameter("fop-version", Version.getVersion()); foUserAgent.setConserveMemoryPolicy(conserveMemoryPolicy); - if (!useComplexScriptFeatures) { - foUserAgent.setComplexScriptFeaturesEnabled(false); - } + // TODO: Handle this!! + //if (!useComplexScriptFeatures) { + // foUserAgent.setComplexScriptFeaturesEnabled(false); + //} } else { return false; } @@ -225,9 +230,7 @@ public class CommandLineOptions { } else if (MimeConstants.MIME_FOP_IF.equals(outputmode) && mimicRenderer != null) { // render from FO to Intermediate Format - IFSerializer serializer = new IFSerializer(); - serializer.setContext(new IFContext(foUserAgent)); - + IFSerializer serializer = new IFSerializer(new IFContext(foUserAgent)); IFDocumentHandler targetHandler = foUserAgent.getRendererFactory().createDocumentHandler( foUserAgent, mimicRenderer); @@ -288,7 +291,7 @@ public class CommandLineOptions { } else if (args[i].equals("-d")) { setLogOption("debug", "debug"); } else if (args[i].equals("-r")) { - factory.setStrictValidation(false); + strictValidation = false; } else if (args[i].equals("-conserve")) { conserveMemoryPolicy = true; } else if (args[i].equals("-flush")) { @@ -819,15 +822,14 @@ public class CommandLineOptions { } private PDFEncryptionParams getPDFEncryptionParams() throws FOPException { - PDFEncryptionParams params = (PDFEncryptionParams)renderingOptions.get( - PDFConfigurationConstants.ENCRYPTION_PARAMS); + PDFEncryptionParams params = (PDFEncryptionParams) renderingOptions.get(ENCRYPTION_PARAMS); if (params == null) { if (!PDFEncryptionManager.checkAvailableAlgorithms()) { throw new FOPException("PDF encryption requested but it is not available." + " Please make sure MD5 and RC4 algorithms are available."); } params = new PDFEncryptionParams(); - renderingOptions.put(PDFConfigurationConstants.ENCRYPTION_PARAMS, params); + renderingOptions.put(ENCRYPTION_PARAMS, params); } return params; } @@ -860,7 +862,7 @@ public class CommandLineOptions { throw new FOPException("You must specify a PDF profile"); } else { String profile = args[i + 1]; - PDFAMode pdfAMode = PDFAMode.valueOf(profile); + PDFAMode pdfAMode = PDFAMode.getValueOf(profile); if (pdfAMode != null && pdfAMode != PDFAMode.DISABLED) { if (renderingOptions.get("pdf-a-mode") != null) { throw new FOPException("PDF/A mode already set"); @@ -868,7 +870,7 @@ public class CommandLineOptions { renderingOptions.put("pdf-a-mode", pdfAMode.getName()); return 1; } else { - PDFXMode pdfXMode = PDFXMode.valueOf(profile); + PDFXMode pdfXMode = PDFXMode.getValueOf(profile); if (pdfXMode != null && pdfXMode != PDFXMode.DISABLED) { if (renderingOptions.get("pdf-x-mode") != null) { throw new FOPException("PDF/X mode already set"); @@ -1027,14 +1029,18 @@ public class CommandLineOptions { * @throws IOException */ private void setUserConfig() throws FOPException, IOException { + FopFactoryBuilder fopFactoryBuilder; if (userConfigFile == null) { - return; - } - try { - factory.setUserConfig(userConfigFile); - } catch (SAXException e) { - throw new FOPException(e); + fopFactoryBuilder = new FopFactoryBuilder(new File(".").toURI()); + } else { + try { + fopFactoryBuilder = new FopConfParser(userConfigFile).getFopFactoryBuilder(); + } catch (SAXException e) { + throw new FOPException(e); + } + fopFactoryBuilder.setStrictFOValidation(strictValidation); } + factory = fopFactoryBuilder.build(); } /** @@ -1390,13 +1396,7 @@ public class CommandLineOptions { } private void flushCache() throws FOPException { - FontManager fontManager = factory.getFontManager(); - File cacheFile = fontManager.getCacheFile(); - if (!fontManager.deleteCache()) { - System.err.println("Failed to flush the font cache file '" - + cacheFile + "'."); - System.exit(1); - } + factory.getFontManager().deleteCache(); } } diff --git a/src/java/org/apache/fop/cli/IFInputHandler.java b/src/java/org/apache/fop/cli/IFInputHandler.java index 6b4031a27..f01252cb2 100644 --- a/src/java/org/apache/fop/cli/IFInputHandler.java +++ b/src/java/org/apache/fop/cli/IFInputHandler.java @@ -62,7 +62,7 @@ public class IFInputHandler extends InputHandler { public void renderTo(FOUserAgent userAgent, String outputFormat, OutputStream out) throws FOPException { IFDocumentHandler documentHandler - = userAgent.getFactory().getRendererFactory().createDocumentHandler( + = userAgent.getRendererFactory().createDocumentHandler( userAgent, outputFormat); try { documentHandler.setResult(new StreamResult(out)); diff --git a/src/java/org/apache/fop/cli/InputHandler.java b/src/java/org/apache/fop/cli/InputHandler.java index 5054f12e1..3320c0b1f 100644 --- a/src/java/org/apache/fop/cli/InputHandler.java +++ b/src/java/org/apache/fop/cli/InputHandler.java @@ -51,7 +51,6 @@ import org.apache.fop.ResourceEventProducer; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.Fop; -import org.apache.fop.apps.FopFactory; import org.apache.fop.render.awt.viewer.Renderable; /** @@ -103,25 +102,11 @@ public class InputHandler implements ErrorListener, Renderable { public void renderTo(FOUserAgent userAgent, String outputFormat, OutputStream out) throws FOPException { - FopFactory factory = userAgent.getFactory(); Fop fop; if (out != null) { - fop = factory.newFop(outputFormat, userAgent, out); + fop = userAgent.newFop(outputFormat, out); } else { - fop = factory.newFop(outputFormat, userAgent); - } - - // if base URL was not explicitly set in FOUserAgent, obtain here - if (fop.getUserAgent().getBaseURL() == null && sourcefile != null) { - String baseURL = null; - - try { - baseURL = new File(sourcefile.getAbsolutePath()) - .getParentFile().toURI().toURL().toExternalForm(); - } catch (Exception e) { - baseURL = ""; - } - fop.getUserAgent().setBaseURL(baseURL); + fop = userAgent.newFop(outputFormat); } // Resulting SAX events (the generated FO) must be piped through to FOP diff --git a/src/java/org/apache/fop/fo/FOTreeBuilder.java b/src/java/org/apache/fop/fo/FOTreeBuilder.java index e312a8038..9040c464a 100644 --- a/src/java/org/apache/fop/fo/FOTreeBuilder.java +++ b/src/java/org/apache/fop/fo/FOTreeBuilder.java @@ -99,7 +99,7 @@ public class FOTreeBuilder extends DefaultHandler { throws FOPException { this.userAgent = foUserAgent; - this.elementMappingRegistry = userAgent.getFactory().getElementMappingRegistry(); + this.elementMappingRegistry = userAgent.getElementMappingRegistry(); //This creates either an AreaTreeHandler and ultimately a Renderer, or //one of the RTF-, MIF- etc. Handlers. foEventHandler = foUserAgent.getRendererFactory().createFOEventHandler( diff --git a/src/java/org/apache/fop/fo/PropertyList.java b/src/java/org/apache/fop/fo/PropertyList.java index 0852c6e29..c9e9250f0 100644 --- a/src/java/org/apache/fop/fo/PropertyList.java +++ b/src/java/org/apache/fop/fo/PropertyList.java @@ -27,7 +27,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.xmlgraphics.util.QName; -import org.apache.fop.apps.FopFactory; +import org.apache.fop.apps.FOUserAgent; import org.apache.fop.fo.expr.PropertyException; import org.apache.fop.fo.properties.CommonAbsolutePosition; import org.apache.fop.fo.properties.CommonAural; @@ -308,7 +308,7 @@ public abstract class PropertyList { String attributeNS; String attributeName; String attributeValue; - FopFactory factory = getFObj().getUserAgent().getFactory(); + FOUserAgent userAgent = getFObj().getUserAgent(); for (int i = 0; i < attributes.getLength(); i++) { /* convert all attributes with the same namespace as the fo element * the "xml:lang" and "xml:base" properties are special cases */ @@ -319,8 +319,8 @@ public abstract class PropertyList { || "xml:lang".equals(attributeName) || "xml:base".equals(attributeName)) { convertAttributeToProperty(attributes, attributeName, attributeValue); - } else if (!factory.isNamespaceIgnored(attributeNS)) { - ElementMapping mapping = factory.getElementMappingRegistry().getElementMapping( + } else if (!userAgent.isNamespaceIgnored(attributeNS)) { + ElementMapping mapping = userAgent.getElementMappingRegistry().getElementMapping( attributeNS); QName attr = new QName(attributeNS, attributeName); if (mapping != null) { diff --git a/src/java/org/apache/fop/fo/extensions/svg/SVGElement.java b/src/java/org/apache/fop/fo/extensions/svg/SVGElement.java index 72cf19bc7..7b771776d 100644 --- a/src/java/org/apache/fop/fo/extensions/svg/SVGElement.java +++ b/src/java/org/apache/fop/fo/extensions/svg/SVGElement.java @@ -23,7 +23,8 @@ package org.apache.fop.fo.extensions.svg; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; -import java.net.URL; +import java.io.File; +import java.net.URI; import org.w3c.dom.Element; @@ -71,12 +72,11 @@ public class SVGElement extends SVGObj { /* if width and height are zero, get the bounds of the content. */ try { - URL baseURL = new URL(getUserAgent().getBaseURL() == null - ? new java.io.File("").toURI().toURL().toExternalForm() - : getUserAgent().getBaseURL()); - if (baseURL != null) { + URI baseUri = getUserAgent().getNewURIResolver().getBaseURI(); + baseUri = baseUri == null ? new File("").toURI() : baseUri; + if (baseUri != null) { SVGOMDocument svgdoc = (SVGOMDocument)doc; - svgdoc.setURLObject(baseURL); + svgdoc.setURLObject(baseUri.toURL()); //The following line should not be called to leave FOP compatible to Batik 1.6. //svgdoc.setDocumentURI(baseURL.toString()); } diff --git a/src/java/org/apache/fop/fo/flow/ExternalGraphic.java b/src/java/org/apache/fop/fo/flow/ExternalGraphic.java index 0dd8ed9f8..dc8584abc 100644 --- a/src/java/org/apache/fop/fo/flow/ExternalGraphic.java +++ b/src/java/org/apache/fop/fo/flow/ExternalGraphic.java @@ -75,7 +75,7 @@ public class ExternalGraphic extends AbstractGraphics { //Additional processing: obtain the image's intrinsic size and baseline information url = URISpecification.getURL(src); FOUserAgent userAgent = getUserAgent(); - ImageManager manager = userAgent.getFactory().getImageManager(); + ImageManager manager = userAgent.getImageManager(); ImageInfo info = null; try { info = manager.getImageInfo(url, userAgent.getImageSessionContext()); diff --git a/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java b/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java index 0e7f3d978..85a17ccd6 100644 --- a/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java +++ b/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java @@ -374,7 +374,7 @@ public class CommonBorderPaddingBackground { String uri = URISpecification.getURL(newInstance.backgroundImage); FObj fobj = pList.getFObj(); FOUserAgent userAgent = pList.getFObj().getUserAgent(); - ImageManager manager = userAgent.getFactory().getImageManager(); + ImageManager manager = userAgent.getImageManager(); ImageSessionContext sessionContext = userAgent.getImageSessionContext(); ImageInfo info; try { diff --git a/src/java/org/apache/fop/fonts/CIDFont.java b/src/java/org/apache/fop/fonts/CIDFont.java index 8f468f7a4..e7dfe9656 100644 --- a/src/java/org/apache/fop/fonts/CIDFont.java +++ b/src/java/org/apache/fop/fonts/CIDFont.java @@ -19,6 +19,8 @@ package org.apache.fop.fonts; +import org.apache.fop.apps.io.URIResolverWrapper; + //Java /** @@ -29,6 +31,13 @@ public abstract class CIDFont extends CustomFont { /** Contains the character widths for all characters in the font */ protected int[] width = null; + /** + * @param resolver the URI resolver for controlling file access + */ + public CIDFont(URIResolverWrapper resolver) { + super(resolver); + } + // ---- Required ---- /** * Returns the type of the CID font. diff --git a/src/java/org/apache/fop/fonts/CustomFont.java b/src/java/org/apache/fop/fonts/CustomFont.java index c6b43fe98..a07f4397a 100644 --- a/src/java/org/apache/fop/fonts/CustomFont.java +++ b/src/java/org/apache/fop/fonts/CustomFont.java @@ -20,13 +20,15 @@ package org.apache.fop.fonts; import java.io.IOException; +import java.io.InputStream; +import java.net.URI; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; -import javax.xml.transform.Source; +import org.apache.fop.apps.io.URIResolverWrapper; /** @@ -35,26 +37,26 @@ import javax.xml.transform.Source; public abstract class CustomFont extends Typeface implements FontDescriptor, MutableFont { - private String fontName = null; - private String fullName = null; - private Set<String> familyNames = null; - private String fontSubName = null; - private String embedFileName = null; - private String embedResourceName = null; - private FontResolver resolver = null; - - private int capHeight = 0; - private int xHeight = 0; - private int ascender = 0; - private int descender = 0; + private String fontName; + private String fullName; + private Set<String> familyNames; + private String fontSubName; + private URI embedFileURI; + private String embedResourceName; + private final URIResolverWrapper resolver; + + private int capHeight; + private int xHeight; + private int ascender; + private int descender; private int[] fontBBox = {0, 0, 0, 0}; private int flags = 4; - private int weight = 0; //0 means unknown weight - private int stemV = 0; - private int italicAngle = 0; - private int missingWidth = 0; + private int weight; //0 means unknown weight + private int stemV; + private int italicAngle; + private int missingWidth; private FontType fontType = FontType.TYPE1; - private int firstChar = 0; + private int firstChar; private int lastChar = 255; private Map<Integer, Map<Integer, Integer>> kerning; @@ -62,6 +64,13 @@ public abstract class CustomFont extends Typeface private boolean useKerning = true; private boolean useAdvanced = true; + /** + * @param resolver the URI resolver for controlling file access + */ + public CustomFont(URIResolverWrapper resolver) { + this.resolver = resolver; + } + /** {@inheritDoc} */ public String getFontName() { return fontName; @@ -103,29 +112,22 @@ public abstract class CustomFont extends Typeface } /** - * Returns an URI representing an embeddable font file. The URI will often - * be a filename or an URL. + * Returns an URI representing an embeddable font file. + * * @return URI to an embeddable font file or null if not available. */ - public String getEmbedFileName() { - return embedFileName; + public URI getEmbedFileURI() { + return embedFileURI; } /** - * Returns a Source representing an embeddable font file. - * @return Source for an embeddable font file + * Returns an {@link InputStream} representing an embeddable font file. + * + * @return {@link InputStream} for an embeddable font file * @throws IOException if embedFileName is not null but Source is not found */ - public Source getEmbedFileSource() throws IOException { - Source result = null; - if (resolver != null && embedFileName != null) { - result = resolver.resolve(embedFileName); - if (result == null) { - throw new IOException("Unable to resolve Source '" - + embedFileName + "' for embedded font"); - } - } - return result; + public InputStream getInputStream() throws IOException { + return resolver.resolveIn(embedFileURI); } /** @@ -323,8 +325,8 @@ public abstract class CustomFont extends Typeface /** * {@inheritDoc} */ - public void setEmbedFileName(String path) { - this.embedFileName = path; + public void setEmbedURI(URI path) { + this.embedFileURI = path; } /** @@ -444,14 +446,6 @@ public abstract class CustomFont extends Typeface this.useAdvanced = enabled; } - /** - * Sets the font resolver. Needed for URI resolution. - * @param resolver the font resolver - */ - public void setResolver(FontResolver resolver) { - this.resolver = resolver; - } - /** {@inheritDoc} */ public void putKerningEntry(Integer key, Map<Integer, Integer> value) { if (kerning == null) { diff --git a/src/java/org/apache/fop/fonts/CustomFontCollection.java b/src/java/org/apache/fop/fonts/CustomFontCollection.java index 6e798a8f7..ab1ddd754 100644 --- a/src/java/org/apache/fop/fonts/CustomFontCollection.java +++ b/src/java/org/apache/fop/fonts/CustomFontCollection.java @@ -21,13 +21,16 @@ package org.apache.fop.fonts; import java.util.List; +import org.apache.fop.apps.io.URIResolverWrapper; + /** * Sets up a set of custom (embedded) fonts */ public class CustomFontCollection implements FontCollection { - private FontResolver fontResolver; private final List<EmbedFontInfo> embedFontInfoList; + private final URIResolverWrapper uriResolver; + private final boolean useComplexScripts; /** * Main constructor. @@ -35,14 +38,11 @@ public class CustomFontCollection implements FontCollection { * @param customFonts the list of custom fonts * @param useComplexScriptFeatures true if complex script features enabled */ - public CustomFontCollection(FontResolver fontResolver, - List<EmbedFontInfo> customFonts, boolean useComplexScriptFeatures) { - this.fontResolver = fontResolver; - if (this.fontResolver == null) { - //Ensure that we have minimal font resolution capabilities - this.fontResolver = FontManager.createMinimalFontResolver(useComplexScriptFeatures); - } + public CustomFontCollection(URIResolverWrapper fontResolver, + List<EmbedFontInfo> customFonts, boolean useComplexScriptFeatures) { + this.uriResolver = fontResolver; this.embedFontInfoList = customFonts; + this.useComplexScripts = useComplexScriptFeatures; } /** {@inheritDoc} */ @@ -52,27 +52,19 @@ public class CustomFontCollection implements FontCollection { } String internalName = null; - //FontReader reader = null; for (int i = 0; i < embedFontInfoList.size(); i++) { EmbedFontInfo embedFontInfo = embedFontInfoList.get(i); - //String metricsFile = configFontInfo.getMetricsFile(); internalName = "F" + num; num++; - /* - reader = new FontReader(metricsFile); - reader.useKerning(configFontInfo.getKerning()); - reader.setFontEmbedPath(configFontInfo.getEmbedFile()); - fontInfo.addMetrics(internalName, reader.getFont()); - */ - LazyFont font = new LazyFont(embedFontInfo, this.fontResolver); + LazyFont font = new LazyFont(embedFontInfo, this.uriResolver, useComplexScripts); fontInfo.addMetrics(internalName, font); List<FontTriplet> triplets = embedFontInfo.getFontTriplets(); for (int tripletIndex = 0; tripletIndex < triplets.size(); tripletIndex++) { - FontTriplet triplet = (FontTriplet) triplets.get(tripletIndex); + FontTriplet triplet = triplets.get(tripletIndex); fontInfo.addFontProperties(internalName, triplet); } } diff --git a/src/java/org/apache/fop/fonts/DefaultFontConfig.java b/src/java/org/apache/fop/fonts/DefaultFontConfig.java new file mode 100644 index 000000000..7473e0995 --- /dev/null +++ b/src/java/org/apache/fop/fonts/DefaultFontConfig.java @@ -0,0 +1,335 @@ +/* + * 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.util.ArrayList; +import java.util.Collections; +import java.util.List; + +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.events.EventProducer; +import org.apache.fop.util.LogUtil; + +/** + * The font configuration data for the more generic fonts such as TTF and Type1, that are used by + * most the renderers. + */ +public final class DefaultFontConfig implements FontConfig { + + protected static Log log = LogFactory.getLog(DefaultFontConfig.class); + + private final List<Directory> directories = new ArrayList<Directory>(); + + private final List<Font> fonts = new ArrayList<Font>(); + + private final List<String> referencedFontFamilies = new ArrayList<String>(); + + private final boolean autoDetectFonts; + + private DefaultFontConfig(boolean autoDetectFonts) { + this.autoDetectFonts = autoDetectFonts; + } + + /** + * Parses the morge generic font information. + */ + public static final class DefaultFontConfigParser implements FontConfig.FontConfigParser { + /** + * Parses the font configuration and return the configuration object. + * + * @param cfg the configuration data + * @param strict whether or not to enforce strict validation + * @return the font configuration object + * @throws FOPException if an error occurs when creating the configuration object + */ + public DefaultFontConfig parse(Configuration cfg, boolean strict) throws FOPException { + return new ParserHelper(cfg, strict).instance; + } + + /** {@inheritDoc} */ + public FontConfig parse(Configuration cfg, FontManager fontManager, boolean strict, + EventProducer eventProducer) throws FOPException { + return parse(cfg, strict); + } + } + + private static final class ParserHelper { + + private boolean strict; + + private Configuration fontInfoCfg; + + private DefaultFontConfig instance; + + private ParserHelper(Configuration cfg, boolean strict) throws FOPException { + if (cfg == null || cfg.getChild("fonts", false) == null) { + instance = null; + } else { + this.strict = strict; + this.fontInfoCfg = cfg.getChild("fonts", false); + instance = new DefaultFontConfig(cfg.getChild("auto-detect", false) != null); + parse(); + } + } + + private void parse() throws FOPException { + parseFonts(); + parseReferencedFonts(); + parseDirectories(); + } + + private void parseFonts() throws FOPException { + for (Configuration fontCfg : fontInfoCfg.getChildren("font")) { + String embed = fontCfg.getAttribute("embed-url", null); + if (embed == null) { + LogUtil.handleError(log, "Font configuration without embed-url attribute", + strict); + continue; + } + Font font = new Font(fontCfg.getAttribute("metrics-url", null), embed, + fontCfg.getAttribute("sub-font", null), fontCfg.getAttributeAsBoolean( + "kerning", true), fontCfg.getAttributeAsBoolean("advanced", true), + fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName())); + instance.fonts.add(font); + boolean hasTriplets = false; + for (Configuration tripletCfg : fontCfg.getChildren("font-triplet")) { + FontTriplet fontTriplet = getFontTriplet(tripletCfg, strict); + font.tripletList.add(fontTriplet); + hasTriplets = true; + } + // no font triplet info + if (!hasTriplets) { + LogUtil.handleError(log, "font without font-triplet", strict); + } + } + } + + private void parseReferencedFonts() throws FOPException { + Configuration referencedFontsCfg = fontInfoCfg.getChild("referenced-fonts", false); + if (referencedFontsCfg != null) { + for (Configuration match : referencedFontsCfg.getChildren("match")) { + try { + instance.referencedFontFamilies.add(match.getAttribute("font-family")); + } catch (ConfigurationException ce) { + LogUtil.handleException(log, ce, strict); + continue; + } + } + } + } + + private void parseDirectories() throws FOPException { + for (Configuration directoriesCfg : fontInfoCfg.getChildren("directory")) { + boolean recursive = directoriesCfg.getAttributeAsBoolean("recursive", false); + String directory; + try { + directory = directoriesCfg.getValue(); + } catch (ConfigurationException e) { + LogUtil.handleException(log, e, strict); + continue; + } + if (directory == null) { + LogUtil.handleException(log, + new FOPException("directory defined without value"), strict); + continue; + } + instance.directories.add(new Directory(directory, recursive)); + } + } + + /** + * 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, 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 the list of fonts that were parsed. + * @return a list of fonts + */ + public List<Font> getFonts() { + return Collections.unmodifiableList(fonts); + } + + /** + * Returns a list of directories that were parsed. + * @return a list of directories + */ + public List<Directory> getDirectories() { + return Collections.unmodifiableList(directories); + } + + /** + * Returns a list of referenced font families. + * @return the referenced font families + */ + public List<String> getReferencedFontFamily() { + return Collections.unmodifiableList(referencedFontFamilies); + } + + /** + * Whether or not to enable auto-detecting of fonts in the system. + * @return true to enable auto-detect + */ + public boolean isAutoDetectFonts() { + return autoDetectFonts; + } + + /** + * The directory to find fonts within. + */ + public static final class Directory { + + private final String directory; + + private final boolean recursive; + + private Directory(String directory, boolean recurse) { + this.directory = directory; + this.recursive = recurse; + } + + /** + * Returns a String representing the directory to find fonts within. + * @return the directory + */ + public String getDirectory() { + return directory; + } + + /** + * Returns whether or not to recurse through the directory when finding fonts. + * @return true to recurse through the directory and sub-directories + */ + public boolean isRecursive() { + return recursive; + } + } + + /** + * Represents a font object within the FOP conf. + */ + public static final class Font { + + private final String metrics; + + private final String embedUri; + + private final String subFont; + + private final boolean kerning; + + private final boolean advanced; + + private final String encodingMode; + + public String getEncodingMode() { + return encodingMode; + } + + private final List<FontTriplet> tripletList = new ArrayList<FontTriplet>(); + + public List<FontTriplet> getTripletList() { + return Collections.unmodifiableList(tripletList); + } + + private Font(String metrics, String embed, String subFont, boolean kerning, + boolean advanced, String encodingMode) { + this.metrics = metrics; + this.embedUri = embed; + this.subFont = subFont; + this.kerning = kerning; + this.advanced = advanced; + this.encodingMode = encodingMode; + } + + /** + * Whether or not to allow kerning of glyphs. + * @return true to allow glyph kerning + */ + public boolean isKerning() { + return kerning; + } + + public boolean isAdvanced() { + return advanced; + } + + /** + * Gets the String representing the metrics file. + * @return the metrics file + */ + public String getMetrics() { + return metrics; + } + + /** + * Gets the URI of the font to embed. + * @return the font URI + */ + public String getEmbedURI() { + return embedUri; + } + + /** + * Gets the sub font within, for example, a TTC. + * @return the sub font name + */ + public String getSubFont() { + return subFont; + } + } +} diff --git a/src/java/org/apache/fop/fonts/DefaultFontConfigurator.java b/src/java/org/apache/fop/fonts/DefaultFontConfigurator.java new file mode 100644 index 000000000..88c056d31 --- /dev/null +++ b/src/java/org/apache/fop/fonts/DefaultFontConfigurator.java @@ -0,0 +1,190 @@ +/* + * 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.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.io.URIResolverWrapper; +import org.apache.fop.fonts.DefaultFontConfig.Directory; +import org.apache.fop.fonts.autodetect.FontFileFinder; +import org.apache.fop.fonts.autodetect.FontInfoFinder; +import org.apache.fop.util.LogUtil; + +/** + * The default configurator for fonts. This configurator can configure the more generic fonts used + * by the renderers i.e. TTF, Type1 etc... + */ +public class DefaultFontConfigurator implements FontConfigurator<EmbedFontInfo> { + /** logger instance */ + protected static Log log = LogFactory.getLog(DefaultFontConfigurator.class); + + private final FontManager fontManager; + private final URIResolverWrapper uriResolver; + private final FontEventListener listener; + private final boolean strict; + + /** + * Main constructor + * @param fontInfoConfig the configuration object + * @param fontManager the font manager + * @param listener the font event listener + * @param strict true if an Exception should be thrown if an error is found. + */ + public DefaultFontConfigurator(FontManager fontManager, FontEventListener listener, boolean strict) { + this.fontManager = fontManager; + this.uriResolver = fontManager.getURIResolver(); + this.listener = listener; + this.strict = strict; + } + + /** + * Initializes font info settings from the user configuration + * @throws FOPException if an exception occurs while processing the configuration + */ + public List<EmbedFontInfo> configure(FontConfig fontInfoConfig) + throws FOPException { + List<EmbedFontInfo> fontInfoList = new ArrayList<EmbedFontInfo>(); + DefaultFontConfig adobeFontInfoConfig = (DefaultFontConfig) fontInfoConfig; + if (adobeFontInfoConfig != null) { + long start = 0; + if (log.isDebugEnabled()) { + log.debug("Starting font configuration..."); + start = System.currentTimeMillis(); + } + FontAdder fontAdder = new FontAdder(fontManager, uriResolver, listener); + // native o/s search (autodetect) configuration + fontManager.autoDetectFonts(adobeFontInfoConfig.isAutoDetectFonts(), fontAdder, strict, + listener, fontInfoList); + // Add configured directories to FontInfo list + addDirectories(adobeFontInfoConfig, fontAdder, fontInfoList); + // Add configured fonts to FontInfo + FontCache fontCache = fontManager.getFontCache(); + try { + addFonts(adobeFontInfoConfig, fontCache, fontInfoList); + } catch (URISyntaxException use) { + LogUtil.handleException(log, use, strict); + } + // Update referenced fonts (fonts which are not to be embedded) + fontManager.updateReferencedFonts(fontInfoList); + // Renderer-specific referenced fonts + List<String> referencedFonts = adobeFontInfoConfig.getReferencedFontFamily(); + if (referencedFonts.size() > 0) { + FontTriplet.Matcher matcher = FontManagerConfigurator.createFontsMatcher( + referencedFonts, strict); + fontManager.updateReferencedFonts(fontInfoList, matcher); + } + // Update font cache if it has changed + fontManager.saveCache(); + if (log.isDebugEnabled()) { + log.debug("Finished font configuration in " + + (System.currentTimeMillis() - start) + "ms"); + } + } + return Collections.unmodifiableList(fontInfoList); + } + + private void addDirectories(DefaultFontConfig fontInfoConfig, FontAdder fontAdder, + List<EmbedFontInfo> fontInfoList) throws FOPException { + // directory (multiple font) configuration + List<Directory> directories = fontInfoConfig.getDirectories(); + for (Directory directory : directories) { + // add fonts found in directory + FontFileFinder fontFileFinder = new FontFileFinder(directory.isRecursive() ? -1 : 1, listener); + List<URL> fontURLList; + try { + fontURLList = fontFileFinder.find(directory.getDirectory()); + fontAdder.add(fontURLList, fontInfoList); + } catch (IOException e) { + LogUtil.handleException(log, e, strict); + } catch (URISyntaxException use) { + LogUtil.handleException(log, use, strict); + } + } + } + + private void addFonts(DefaultFontConfig fontInfoConfig, FontCache fontCache, + List<EmbedFontInfo> fontInfoList) throws FOPException, URISyntaxException { + // font file (singular) configuration + List<DefaultFontConfig.Font> fonts = fontInfoConfig.getFonts(); + for (DefaultFontConfig.Font font : fonts) { + EmbedFontInfo embedFontInfo = getFontInfo(font, fontCache); + if (embedFontInfo != null) { + fontInfoList.add(embedFontInfo); + } + } + } + + private EmbedFontInfo getFontInfo(DefaultFontConfig.Font font, FontCache fontCache) + throws FOPException, URISyntaxException { + String embed = font.getEmbedURI(); + String metrics = font.getMetrics(); + String subFont = font.getSubFont(); + URI metricsUri = metrics == null ? null : URIResolverWrapper.cleanURI(metrics); + URI embedUri = URIResolverWrapper.cleanURI(embed); + + List<FontTriplet> tripletList = font.getTripletList(); + + // no font triplet info + if (tripletList.size() == 0) { + //TODO: could be problematic!! + URI fontUri = uriResolver.getBaseURI().resolve(embedUri); + if (fontUri != null) { + FontInfoFinder finder = new FontInfoFinder(); + finder.setEventListener(listener); + EmbedFontInfo[] infos = finder.find(fontUri, uriResolver, fontCache); + return infos[0]; //When subFont is set, only one font is returned + } else { + return null; + } + } + EncodingMode encodingMode = EncodingMode.getEncodingMode(font.getEncodingMode()); + EmbedFontInfo embedFontInfo = new EmbedFontInfo(metricsUri, font.isKerning(), + font.isAdvanced(), tripletList, embedUri, subFont, encodingMode); + if (fontCache != null) { + if (!fontCache.containsFont(embedFontInfo)) { + fontCache.addFont(embedFontInfo, uriResolver); + } + } + + if (log.isDebugEnabled()) { + URI embedFile = embedFontInfo.getEmbedURI(); + log.debug("Adding font " + (embedFile != null ? embedFile + ", " : "") + + "metrics URI " + embedFontInfo.getMetricsURI()); + for (int j = 0; j < tripletList.size(); ++j) { + FontTriplet triplet = tripletList.get(j); + log.debug(" Font triplet " + + triplet.getName() + ", " + + triplet.getStyle() + ", " + + triplet.getWeight()); + } + } + return embedFontInfo; + } +} diff --git a/src/java/org/apache/fop/fonts/EmbedFontInfo.java b/src/java/org/apache/fop/fonts/EmbedFontInfo.java index 8848c0a87..72a5f36ba 100644 --- a/src/java/org/apache/fop/fonts/EmbedFontInfo.java +++ b/src/java/org/apache/fop/fonts/EmbedFontInfo.java @@ -21,6 +21,7 @@ package org.apache.fop.fonts; import java.io.IOException; import java.io.Serializable; +import java.net.URI; import java.util.List; /** @@ -31,60 +32,74 @@ public class EmbedFontInfo implements Serializable { /** Serialization Version UID */ private static final long serialVersionUID = 8755432068669997369L; - /** filename of the metrics file */ - protected String metricsFile; - /** filename of the main font file */ - protected String embedFile; + protected final URI metricsURI; + protected final URI embedURI; /** false, to disable kerning */ - protected boolean kerning; + protected final boolean kerning; /** false, to disable advanced typographic features */ - protected boolean advanced; + protected final boolean advanced; /** the requested encoding mode for the font */ - protected EncodingMode encodingMode = EncodingMode.AUTO; + private final EncodingMode encodingMode; /** the PostScript name of the font */ - protected String postScriptName = null; + protected String postScriptName; /** the sub-fontname of the font (used for TrueType Collections, null otherwise) */ - protected String subFontName = null; + protected String subFontName; /** the list of associated font triplets */ - private List<FontTriplet> fontTriplets = null; + private List<FontTriplet> fontTriplets; private transient boolean embedded = true; /** * Main constructor - * @param metricsFile path to the xml file containing font metrics - * @param kerning true if kerning should be enabled + * @param metricsURI the URI of the XML resource containing font metrics + * @param kerning True if kerning should be enabled * @param advanced true if advanced typography features should be enabled - * @param fontTriplets list of font triplets to associate with this font - * @param embedFile path to the embeddable font file (may be null) + * @param fontTriplets List of font triplets to associate with this font + * @param embedURI Path to the embeddable font file (may be null) * @param subFontName the sub-fontname used for TrueType Collections (null otherwise) + * @param encodingMode the encoding mode to use for this font */ - public EmbedFontInfo(String metricsFile, boolean kerning, boolean advanced, - List<FontTriplet> fontTriplets, String embedFile, String subFontName) { - this.metricsFile = metricsFile; - this.embedFile = embedFile; + public EmbedFontInfo(URI metricsURI, boolean kerning, boolean advanced, + List<FontTriplet> fontTriplets, URI embedURI, String subFontName) { + this.metricsURI = metricsURI; + this.embedURI = embedURI; this.kerning = kerning; this.advanced = advanced; this.fontTriplets = fontTriplets; this.subFontName = subFontName; + this.encodingMode = EncodingMode.AUTO; + } + + public EmbedFontInfo(URI metricsURI, boolean kerning, boolean advanced, + List<FontTriplet> fontTriplets, URI embedURI, String subFontName, + EncodingMode encodingMode) { + this.metricsURI = metricsURI; + this.embedURI = embedURI; + this.kerning = kerning; + this.advanced = advanced; + this.fontTriplets = fontTriplets; + this.subFontName = subFontName; + this.encodingMode = encodingMode; } /** - * Returns the path to the metrics file + * Returns the URI of the metrics XML resource + * * @return the metrics file path */ - public String getMetricsFile() { - return metricsFile; + public URI getMetricsURI() { + return metricsURI; } /** - * Returns the path to the embeddable font file - * @return the font file path + * Returns the URI to the embeddable font resource + * + * @return the font resource URI */ - public String getEmbedFile() { - return embedFile; + public URI getEmbedURI() { + return embedURI; } /** @@ -141,7 +156,7 @@ public class EmbedFontInfo implements Serializable { * @return true if the font is embedded, false if it is referenced. */ public boolean isEmbedded() { - if (metricsFile != null && embedFile == null) { + if (embedURI == null) { return false; } else { return this.embedded; @@ -164,17 +179,6 @@ public class EmbedFontInfo implements Serializable { return this.encodingMode; } - /** - * Sets the requested encoding mode for this font. - * @param mode the new encoding mode - */ - public void setEncodingMode(EncodingMode mode) { - if (mode == null) { - throw new NullPointerException("mode must not be null"); - } - this.encodingMode = mode; - } - private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); @@ -183,7 +187,7 @@ public class EmbedFontInfo implements Serializable { /** {@inheritDoc} */ public String toString() { - return "metrics-url=" + metricsFile + ", embed-url=" + embedFile + return "metrics-uri=" + metricsURI + ", embed-uri=" + embedURI + ", kerning=" + kerning + ", advanced=" + advanced + ", enc-mode=" + encodingMode diff --git a/src/java/org/apache/fop/fonts/FontAdder.java b/src/java/org/apache/fop/fonts/FontAdder.java index c5e2b8b9f..51eff2ffc 100644 --- a/src/java/org/apache/fop/fonts/FontAdder.java +++ b/src/java/org/apache/fop/fonts/FontAdder.java @@ -19,9 +19,11 @@ package org.apache.fop.fonts; +import java.net.URISyntaxException; import java.net.URL; import java.util.List; +import org.apache.fop.apps.io.URIResolverWrapper; import org.apache.fop.fonts.autodetect.FontInfoFinder; /** @@ -29,7 +31,7 @@ import org.apache.fop.fonts.autodetect.FontInfoFinder; */ public class FontAdder { private final FontEventListener listener; - private final FontResolver resolver; + private final URIResolverWrapper resolver; private final FontManager manager; /** @@ -38,7 +40,7 @@ public class FontAdder { * @param resolver a font resolver * @param listener a font event handler */ - public FontAdder(FontManager manager, FontResolver resolver, FontEventListener listener) { + public FontAdder(FontManager manager, URIResolverWrapper resolver, FontEventListener listener) { this.manager = manager; this.resolver = resolver; this.listener = listener; @@ -48,14 +50,16 @@ public class FontAdder { * Iterates over font url list adding to font info list * @param fontURLList font file list * @param fontInfoList a configured font info list + * @throws URISyntaxException if a URI syntax error is found */ - public void add(List<URL> fontURLList, List<EmbedFontInfo> fontInfoList) { + public void add(List<URL> fontURLList, List<EmbedFontInfo> fontInfoList) + throws URISyntaxException { FontCache cache = manager.getFontCache(); FontInfoFinder finder = new FontInfoFinder(); finder.setEventListener(listener); for (URL fontURL : fontURLList) { - EmbedFontInfo[] embedFontInfos = finder.find(fontURL, resolver, cache); + EmbedFontInfo[] embedFontInfos = finder.find(fontURL.toURI(), resolver, cache); if (embedFontInfos == null) { continue; } diff --git a/src/java/org/apache/fop/fonts/FontCache.java b/src/java/org/apache/fop/fonts/FontCache.java index 87298a707..6914421b9 100644 --- a/src/java/org/apache/fop/fonts/FontCache.java +++ b/src/java/org/apache/fop/fonts/FontCache.java @@ -29,6 +29,7 @@ import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.Serializable; import java.net.MalformedURLException; +import java.net.URI; import java.net.URL; import java.net.URLConnection; import java.util.HashMap; @@ -40,6 +41,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.io.URIResolverWrapper; import org.apache.fop.util.LogUtil; /** @@ -234,9 +236,9 @@ public final class FontCache implements Serializable { */ protected static String getCacheKey(EmbedFontInfo fontInfo) { if (fontInfo != null) { - String embedFile = fontInfo.getEmbedFile(); - String metricsFile = fontInfo.getMetricsFile(); - return (embedFile != null) ? embedFile : metricsFile; + URI embedFile = fontInfo.getEmbedURI(); + URI metricsFile = fontInfo.getMetricsURI(); + return (embedFile != null) ? embedFile.toASCIIString() : metricsFile.toASCIIString(); } return null; } @@ -318,7 +320,7 @@ public final class FontCache implements Serializable { * @param fontInfo * font info */ - public void addFont(EmbedFontInfo fontInfo) { + public void addFont(EmbedFontInfo fontInfo, URIResolverWrapper resolver) { String cacheKey = getCacheKey(fontInfo); synchronized (changeLock) { CachedFontFile cachedFontFile; @@ -329,10 +331,10 @@ public final class FontCache implements Serializable { } } else { // try and determine modified date - File fontFile = getFileFromUrls(new String[] { - fontInfo.getEmbedFile(), fontInfo.getMetricsFile() }); - long lastModified = (fontFile != null ? fontFile.lastModified() - : -1); + // TODO: This could be problematic?!!?!?! + URI fontUri = resolver.getBaseURI().resolve(fontInfo.getEmbedURI()); + File fontFile = new File(fontUri); + long lastModified = (fontFile != null ? fontFile.lastModified() : -1); cachedFontFile = new CachedFontFile(lastModified); if (log.isTraceEnabled()) { log.trace("Font added to cache: " + cacheKey); @@ -467,8 +469,9 @@ public final class FontCache implements Serializable { * the URL * @return the last modified date/time */ - public static long getLastModified(URL url) { + public static long getLastModified(URI uri) { try { + URL url = uri.toURL(); URLConnection conn = url.openConnection(); try { return conn.getLastModified(); diff --git a/src/java/org/apache/fop/fonts/FontResolver.java b/src/java/org/apache/fop/fonts/FontCacheManager.java index bd155482e..fb0a0322b 100644 --- a/src/java/org/apache/fop/fonts/FontResolver.java +++ b/src/java/org/apache/fop/fonts/FontCacheManager.java @@ -19,27 +19,35 @@ package org.apache.fop.fonts; -import javax.xml.transform.Source; +import java.io.File; + +import org.apache.fop.apps.FOPException; + /** - * This interface is used to resolve absolute and relative font URIs. + * Fop cache (currently only used for font info caching) */ -public interface FontResolver { +public interface FontCacheManager { + + /** + * Loads the font cache into memory from the given file. + * @param file the serialized font cache + * @return the de-serialized font cache + */ + FontCache load(File file); /** - * Called to resolve an URI to a Source instance. The base URI needed by the URIResolver's - * resolve() method is defined to be implicitly available in this case. If the URI cannot - * be resolved, null is returned and it is assumed that the FontResolver implementation - * already warned the user about the problem. - * @param href An href attribute, which may be relative or absolute. - * @return A Source object, or null if the href could not resolved. + * Serializes the font cache to file. + * @param file the file to serialize the font cache to + * @throws FOPException if an error occurs serializing the font cache */ - Source resolve(String href); + void save(File file) throws FOPException; /** - * Check whether complex script features are enabled. - * @return true if FOP is to use complex script features + * Deletes the font cache from the file-system. + * @param file delete the serialized font cache + * @throws FOPException if an error occurs deleting the font cache */ - boolean isComplexScriptFeaturesEnabled(); + void delete(File file) throws FOPException; } diff --git a/src/java/org/apache/fop/fonts/FontCacheManagerFactory.java b/src/java/org/apache/fop/fonts/FontCacheManagerFactory.java new file mode 100644 index 000000000..0236effce --- /dev/null +++ b/src/java/org/apache/fop/fonts/FontCacheManagerFactory.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.fonts; + +import java.io.File; + +import org.apache.fop.apps.FOPException; + +/** + * A factory that provides the font caching manager mechanism. + * + */ +public final class FontCacheManagerFactory { + + private FontCacheManagerFactory() { + } + + /** + * Create the default font caching mechanism. + * @return the font cache manager + */ + public static FontCacheManager createDefault() { + return new FontCacheManagerImpl(); + } + + /** + * Create a disabled font caching mechanism which by definition does nothing to cache fonts. + * @return a completely restricted font cache manager + */ + public static FontCacheManager createDisabled() { + return new DisabledFontCacheManager(); + } + + private static final class FontCacheManagerImpl implements FontCacheManager { + + private FontCache fontCache; + + public FontCache load(File cacheFile) { + if (fontCache == null) { + fontCache = FontCache.loadFrom(cacheFile); + if (fontCache == null) { + fontCache = new FontCache(); + } + } + return fontCache; + } + + public void save(File cacheFile) throws FOPException { + if (fontCache != null && fontCache.hasChanged()) { + fontCache.saveTo(cacheFile); + } + } + + public void delete(File cacheFile) throws FOPException { + if (!cacheFile.delete()) { + throw new FOPException("Failed to flush the font cache file '" + cacheFile + "'."); + } + } + } + + private static final class DisabledFontCacheManager implements FontCacheManager { + + public FontCache load(File cacheFile) { + return null; + } + + public void save(File cacheFile) throws FOPException { + // nop + } + + public void delete(File cacheFile) throws FOPException { + throw new FOPException("Font Cache disabled"); + } + } +} diff --git a/src/java/org/apache/fop/fonts/FontConfig.java b/src/java/org/apache/fop/fonts/FontConfig.java new file mode 100644 index 000000000..167baf09e --- /dev/null +++ b/src/java/org/apache/fop/fonts/FontConfig.java @@ -0,0 +1,50 @@ +/* + * 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 org.apache.avalon.framework.configuration.Configuration; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.events.EventProducer; + +/** + * An interface for font configuration information. + */ +public interface FontConfig { + + /** + * An interface for parsing font configuration information. + */ + public interface FontConfigParser { + + /** + * Parse the font configuration and return an object containing all the necessary data. + * + * @param cfg the configuration object + * @param fontManager the font manager + * @param strict whether or not to enforce strict validation + * @param eventProducer the event producer for handling font events + * @return the configuration object + * @throws FOPException if an error occurs creating the font configuration object + */ + FontConfig parse(Configuration cfg, FontManager fontManager, boolean strict, + EventProducer eventProducer) throws FOPException; + } +} diff --git a/src/java/org/apache/fop/fonts/FontConfigurator.java b/src/java/org/apache/fop/fonts/FontConfigurator.java new file mode 100644 index 000000000..c1ddb4296 --- /dev/null +++ b/src/java/org/apache/fop/fonts/FontConfigurator.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; + +import java.util.List; + +import org.apache.fop.apps.FOPException; + +/** + * An abstract FontInfo configurator + */ +// TODO: Make T extends some interface to make the font info type explicit +public interface FontConfigurator<T> { + + /** + * Initializes font info settings from the user configuration + * @return a font info list + * @throws FOPException if an exception occurs while processing the configuration + */ + List<T> configure(FontConfig fontInfoConfig) throws FOPException; + +} diff --git a/src/java/org/apache/fop/fonts/FontDetector.java b/src/java/org/apache/fop/fonts/FontDetector.java index 8cfb0da12..71965f4a4 100644 --- a/src/java/org/apache/fop/fonts/FontDetector.java +++ b/src/java/org/apache/fop/fonts/FontDetector.java @@ -17,90 +17,18 @@ /* $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.xmlgraphics.util.ClasspathResource; - import org.apache.fop.apps.FOPException; -import org.apache.fop.fonts.autodetect.FontFileFinder; -import org.apache.fop.util.LogUtil; /** - * Detector of operating system and classpath fonts + * An interface for the font detecting mechanism. */ -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 final FontManager fontManager; - private final FontAdder fontAdder; - private final boolean strict; - private final FontEventListener eventListener; - - /** - * 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. - * @param listener for throwing font related events - */ - public FontDetector(FontManager manager, FontAdder adder, boolean strict, - FontEventListener listener) { - this.fontManager = manager; - this.fontAdder = adder; - this.strict = strict; - this.eventListener = listener; - } - - /** - * 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(eventListener); - 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); - } - } +public interface FontDetector { + void detect(FontManager fontManager, FontAdder fontAdder, boolean strict, + FontEventListener eventListener, List<EmbedFontInfo> fontInfoList) throws FOPException; } diff --git a/src/java/org/apache/fop/fonts/FontDetectorFactory.java b/src/java/org/apache/fop/fonts/FontDetectorFactory.java new file mode 100644 index 000000000..895082a9f --- /dev/null +++ b/src/java/org/apache/fop/fonts/FontDetectorFactory.java @@ -0,0 +1,121 @@ +/* + * 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.URI; +import java.net.URISyntaxException; +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.xmlgraphics.util.ClasspathResource; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.fonts.autodetect.FontFileFinder; +import org.apache.fop.util.LogUtil; + +/** + * A factory that provides the font detecting machanism. + */ +public final class FontDetectorFactory { + private FontDetectorFactory() { + } + + /** + * Creates the default font detector + * @return the default font detector + */ + public static FontDetector createDefault() { + return new DefaultFontDetector(); + } + + /** + * Creates a disabled font detector which, by definition, does nothing to detect fonts. + * @return the completely restricted font detector + */ + public static FontDetector createDisabled() { + return new DisabledFontDetector(); + } + + + private static class DisabledFontDetector implements FontDetector { + public void detect(FontManager fontManager, FontAdder fontAdder, boolean strict, + FontEventListener eventListener, List<EmbedFontInfo> fontInfoList) + throws FOPException { + // nop + } + } + + /** + * Detector of operating system and classpath fonts + */ + private static class DefaultFontDetector implements FontDetector { + private static Log log = LogFactory.getLog(DefaultFontDetector.class); + + private static final String[] FONT_MIMETYPES = { + "application/x-font", "application/x-font-truetype" + }; + + /** + * 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(FontManager fontManager, FontAdder fontAdder, boolean strict, + FontEventListener eventListener, List<EmbedFontInfo> fontInfoList) + throws FOPException { + try { + // search in font base if it is defined and + // is a directory but don't recurse + FontFileFinder fontFileFinder = new FontFileFinder(eventListener); + URI fontBaseURI = fontManager.getURIResolver().getBaseURI(); + if (fontBaseURI != null) { + File fontBase = FileUtils.toFile(fontBaseURI.toURL()); + 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 + } + } + + // native o/s font directory finding + List<URL> systemFontList; + systemFontList = fontFileFinder.find(); + fontAdder.add(systemFontList, fontInfoList); + + // classpath font finding + ClasspathResource resource = ClasspathResource.getInstance(); + for (String mimeTypes : FONT_MIMETYPES) { + fontAdder.add(resource.listResourcesOfMimeType(mimeTypes), fontInfoList); + } + } catch (IOException e) { + LogUtil.handleException(log, e, strict); + } catch (URISyntaxException use) { + LogUtil.handleException(log, use, strict); + } + } + } +} diff --git a/src/java/org/apache/fop/fonts/FontInfoConfigurator.java b/src/java/org/apache/fop/fonts/FontInfoConfigurator.java deleted file mode 100644 index 34b6ed1d0..000000000 --- a/src/java/org/apache/fop/fonts/FontInfoConfigurator.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * 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 final Log log = LogFactory.getLog(FontInfoConfigurator.class); - - private final Configuration cfg; - private final FontManager fontManager; - private final FontResolver fontResolver; - private final FontEventListener listener; - private final 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 { - Configuration fontsCfg = cfg.getChild("fonts", false); - if (fontsCfg != 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 = (fontsCfg.getChild("auto-detect", false) != null); - if (autodetectFonts) { - FontDetector fontDetector = new FontDetector(fontManager, fontAdder, strict, - listener); - fontDetector.detect(fontInfoList); - } - - // Add configured directories to FontInfo list - addDirectories(fontsCfg, fontAdder, fontInfoList); - - // Add fonts from configuration to FontInfo list - addFonts(fontsCfg, fontManager.getFontCache(), fontInfoList); - - // Update referenced fonts (fonts which are not to be embedded) - fontManager.updateReferencedFonts(fontInfoList); - - // Renderer-specific referenced fonts - Configuration referencedFontsCfg = fontsCfg.getChild("referenced-fonts", false); - if (referencedFontsCfg != null) { - FontTriplet.Matcher matcher = FontManagerConfigurator.createFontsMatcher( - referencedFontsCfg, strict); - fontManager.updateReferencedFonts(fontInfoList, matcher); - } - - // Update font cache if it has changed - fontManager.saveCache(); - - if (log.isDebugEnabled()) { - log.debug("Finished font configuration in " - + (System.currentTimeMillis() - start) + "ms"); - } - } - } - - private void addDirectories(Configuration fontsCfg, - FontAdder fontAdder, List<EmbedFontInfo> 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, listener); - 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 = null; - try { - fontURL = fontFile.toURI().toURL(); - } catch (MalformedURLException e) { - LogUtil.handleException(log, e, strict); - } - 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); - boolean useAdvanced = fontCfg.getAttributeAsBoolean("advanced", true); - EncodingMode encodingMode = EncodingMode.getEncodingMode( - fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName())); - EmbedFontInfo embedFontInfo - = new EmbedFontInfo(metricsUrl, useKerning, useAdvanced, tripletList, embedUrl, - subFont); - embedFontInfo.setEncodingMode(encodingMode); - boolean skipCachedFont = false; - if (fontCache != null) { - if (!fontCache.containsFont(embedFontInfo)) { - fontCache.addFont(embedFontInfo); - } else { - skipCachedFont = true; - } - } - - if (log.isDebugEnabled()) { - String embedFile = embedFontInfo.getEmbedFile(); - log.debug( ( skipCachedFont ? "Skipping (cached) font " : "Adding font " ) - + (embedFile != null ? embedFile + ", " : "") - + "metric file " + embedFontInfo.getMetricsFile()); - for (int j = 0; j < tripletList.size(); ++j) { - FontTriplet triplet = 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/FontLoader.java b/src/java/org/apache/fop/fonts/FontLoader.java index 91b763939..96a8738f9 100644 --- a/src/java/org/apache/fop/fonts/FontLoader.java +++ b/src/java/org/apache/fop/fonts/FontLoader.java @@ -19,18 +19,13 @@ package org.apache.fop.fonts; -import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; - -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; +import java.net.URI; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.apps.io.URIResolverWrapper; import org.apache.fop.fonts.truetype.TTFFontLoader; import org.apache.fop.fonts.type1.Type1FontLoader; @@ -43,9 +38,9 @@ public abstract class FontLoader { protected static final Log log = LogFactory.getLog(FontLoader.class); /** URI representing the font file */ - protected String fontFileURI; + protected final URI fontFileURI; /** the FontResolver to use for font URI resolution */ - protected FontResolver resolver; + protected final URIResolverWrapper resolver; /** the loaded font */ protected CustomFont returnFont; @@ -67,8 +62,8 @@ public abstract class FontLoader { * available * @param resolver the font resolver used to resolve URIs */ - public FontLoader(String fontFileURI, boolean embedded, boolean useKerning, - boolean useAdvanced, FontResolver resolver) { + public FontLoader(URI fontFileURI, boolean embedded, boolean useKerning, + boolean useAdvanced, URIResolverWrapper resolver) { this.fontFileURI = fontFileURI; this.embedded = embedded; this.useKerning = useKerning; @@ -76,42 +71,8 @@ public abstract class FontLoader { 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 subFontName the sub-fontname of a font (for TrueType Collections, null otherwise) - * @param embedded indicates whether the font is embedded or referenced - * @param encodingMode the requested encoding mode - * @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, String subFontName, - boolean embedded, EncodingMode encodingMode, FontResolver resolver) throws IOException { - return loadFont(fontFile.toURI().toURL(), subFontName, - embedded, encodingMode, resolver); - } - - /** - * Loads a custom font from an URL. In the case of Type 1 fonts, the PFB file must be specified. - * @param fontUrl the URL representation of the font - * @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise) - * @param embedded indicates whether the font is embedded or referenced - * @param encodingMode the requested encoding mode - * @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(URL fontUrl, String subFontName, - boolean embedded, EncodingMode encodingMode, - FontResolver resolver) throws IOException { - return loadFont(fontUrl.toExternalForm(), subFontName, - embedded, encodingMode, true, true, - resolver); + private static boolean isType1(URI fontURI) { + return fontURI.toASCIIString().toLowerCase().endsWith(".pfb"); } /** @@ -127,10 +88,9 @@ public abstract class FontLoader { * @return the newly loaded font * @throws IOException In case of an I/O error */ - public static CustomFont loadFont(String fontFileURI, String subFontName, + public static CustomFont loadFont(URI fontFileURI, String subFontName, boolean embedded, EncodingMode encodingMode, boolean useKerning, - boolean useAdvanced, FontResolver resolver) throws IOException { - fontFileURI = fontFileURI.trim(); + boolean useAdvanced, URIResolverWrapper resolver) throws IOException { boolean type1 = isType1(fontFileURI); FontLoader loader; if (type1) { @@ -147,41 +107,6 @@ public abstract class FontLoader { } /** - * Opens a font URI 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 - */ - public static InputStream openFontUri(FontResolver resolver, String uri) - throws IOException, MalformedURLException { - InputStream in = null; - if (resolver != null) { - Source source = resolver.resolve(uri); - if (source == null) { - String err = "Cannot load font: failed to create Source for font file " - + uri; - throw new IOException(err); - } - if (source instanceof StreamSource) { - in = ((StreamSource) source).getInputStream(); - } - if (in == null && source.getSystemId() != null) { - in = new java.net.URL(source.getSystemId()).openStream(); - } - if (in == null) { - String err = "Cannot load font: failed to create InputStream from" - + " Source for font file " + uri; - throw new IOException(err); - } - } else { - in = new URL(uri).openStream(); - } - return in; - } - - /** * Reads/parses the font data. * @throws IOException In case of an I/O error */ diff --git a/src/java/org/apache/fop/fonts/FontManager.java b/src/java/org/apache/fop/fonts/FontManager.java index 9285c94be..adf09fb7a 100644 --- a/src/java/org/apache/fop/fonts/FontManager.java +++ b/src/java/org/apache/fop/fonts/FontManager.java @@ -20,13 +20,10 @@ package org.apache.fop.fonts; import java.io.File; -import java.net.MalformedURLException; import java.util.List; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.io.URIResolverWrapper; import org.apache.fop.fonts.FontTriplet.Matcher; import org.apache.fop.fonts.substitute.FontSubstitutions; @@ -38,14 +35,13 @@ import org.apache.fop.fonts.substitute.FontSubstitutions; * font substitution, referenced fonts and similar. */ public class FontManager { - /** Use cache (record previously detected font triplet info) */ - public static final boolean DEFAULT_USE_CACHE = true; /** The base URL for all font URL resolutions. */ - private String fontBase = null; + private URIResolverWrapper uriResolver; + + private final FontDetector fontDetector; - /** Font cache to speed up auto-font configuration (null if disabled) */ - private FontCache fontCache = null; + private FontCacheManager fontCacheManager; /** Font substitutions */ private FontSubstitutions fontSubstitutions = null; @@ -56,33 +52,33 @@ public class FontManager { /** FontTriplet matcher for fonts that shall be referenced rather than embedded. */ private FontTriplet.Matcher referencedFontsMatcher; - /** Enables/disables the use of font caching */ - private boolean useCache = DEFAULT_USE_CACHE; - /** Provides a font cache file path **/ private File cacheFile; /** * Main constructor + * + * @param uriResolver the URI resolver + * @param fontDetector the font detector + * @param fontCacheManager the font cache manager */ - public FontManager() { + public FontManager(URIResolverWrapper uriResolver, FontDetector fontDetector, + FontCacheManager fontCacheManager) { + this.uriResolver = uriResolver; + this.fontDetector = fontDetector; + this.fontCacheManager = fontCacheManager; } /** - * Sets the font base URL. - * @param fontBase font base URL - * @throws MalformedURLException if there's a problem with a URL + * Sets the font URI resolver + * @param uriResolver font base URI */ - public void setFontBaseURL(String fontBase) throws MalformedURLException { - this.fontBase = fontBase; + public void setFontURIResolver(URIResolverWrapper uriResolver) { + this.uriResolver = uriResolver; } - /** - * Returns the font base URL. - * @return the font base URL (or null if none was set) - */ - public String getFontBaseURL() { - return this.fontBase; + public URIResolverWrapper getURIResolver() { + return this.uriResolver; } /** @return true if kerning on base 14 fonts is enabled */ @@ -130,29 +126,22 @@ public class FontManager { * @return the font cache file */ public File getCacheFile() { + return getCacheFile(false); + } + + private File getCacheFile(boolean writable) { if (cacheFile != null) { - return this.cacheFile; + return cacheFile; } - return FontCache.getDefaultCacheFile(false); + return FontCache.getDefaultCacheFile(writable); } /** * Whether or not to cache results of font triplet detection/auto-config * @param useCache use cache or not */ - public void setUseCache(boolean useCache) { - this.useCache = useCache; - if (!useCache) { - this.fontCache = null; - } - } - - /** - * Cache results of font triplet detection/auto-config? - * @return true if this font manager uses the cache - */ - public boolean useCache() { - return useCache; + public void disableFontCache() { + fontCacheManager = FontCacheManagerFactory.createDisabled(); } /** @@ -160,19 +149,7 @@ public class FontManager { * @return the font cache */ public FontCache getFontCache() { - if (fontCache == null) { - if (useCache) { - if (cacheFile != null) { - fontCache = FontCache.loadFrom(cacheFile); - } else { - fontCache = FontCache.load(); - } - if (fontCache == null) { - fontCache = new FontCache(); - } - } - } - return fontCache; + return fontCacheManager.load(getCacheFile()); } /** @@ -181,31 +158,16 @@ public class FontManager { * @throws FOPException fop exception */ public void saveCache() throws FOPException { - if (useCache) { - if (fontCache != null && fontCache.hasChanged()) { - if (cacheFile != null) { - fontCache.saveTo(cacheFile); - } else { - fontCache.save(); - } - } - } + fontCacheManager.save(getCacheFile()); } /** * Deletes the current FontCache file * @return Returns true if the font cache file was successfully deleted. + * @throws FOPException - */ - public boolean deleteCache() { - boolean deleted = false; - if (useCache) { - if (cacheFile != null) { - deleted = cacheFile.delete(); - } else { - deleted = FontCache.getDefaultCacheFile(true).delete(); - } - } - return deleted; + public void deleteCache() throws FOPException { + fontCacheManager.delete(getCacheFile(true)); } /** @@ -225,34 +187,6 @@ public class FontManager { } /** - * Minimum implemenation of FontResolver. - */ - public static class MinimalFontResolver implements FontResolver { - private boolean useComplexScriptFeatures; - MinimalFontResolver(boolean useComplexScriptFeatures) { - this.useComplexScriptFeatures = useComplexScriptFeatures; - } - /** {@inheritDoc} */ - public Source resolve(String href) { - //Minimal functionality here - return new StreamSource(href); - } - /** {@inheritDoc} */ - public boolean isComplexScriptFeaturesEnabled() { - return useComplexScriptFeatures; - } - } - - /** - * Create minimal font resolver. - * @param useComplexScriptFeatures true if complex script features enabled - * @return a new FontResolver to be used by the font subsystem - */ - public static FontResolver createMinimalFontResolver(boolean useComplexScriptFeatures) { - return new MinimalFontResolver ( useComplexScriptFeatures ); - } - - /** * Sets the {@link FontTriplet.Matcher} that can be used to identify the fonts that shall * be referenced rather than embedded. * @param matcher the font triplet matcher @@ -298,4 +232,11 @@ public class FontManager { } } } + + public void autoDetectFonts(boolean autoDetectFonts, FontAdder fontAdder, boolean strict, + FontEventListener listener, List<EmbedFontInfo> fontInfoList) throws FOPException { + if (autoDetectFonts) { + fontDetector.detect(this, fontAdder, strict, listener, fontInfoList); + } + } } diff --git a/src/java/org/apache/fop/fonts/FontManagerConfigurator.java b/src/java/org/apache/fop/fonts/FontManagerConfigurator.java index 1a900fe2f..d046daf62 100644 --- a/src/java/org/apache/fop/fonts/FontManagerConfigurator.java +++ b/src/java/org/apache/fop/fonts/FontManagerConfigurator.java @@ -20,8 +20,8 @@ package org.apache.fop.fonts; import java.io.File; -import java.net.MalformedURLException; import java.net.URI; +import java.net.URISyntaxException; import java.util.List; import java.util.regex.Pattern; @@ -31,6 +31,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.io.ResourceResolver; +import org.apache.fop.apps.io.URIResolverWrapper; import org.apache.fop.fonts.substitute.FontSubstitutions; import org.apache.fop.fonts.substitute.FontSubstitutionsConfigurator; import org.apache.fop.util.LogUtil; @@ -45,24 +47,21 @@ public class FontManagerConfigurator { private final Configuration cfg; - private URI baseURI = null; + private final URI defaultBaseUri; - /** - * Main constructor - * @param cfg the font manager configuration object - */ - public FontManagerConfigurator(Configuration cfg) { - this.cfg = cfg; - } + private final ResourceResolver uriResolver; /** * Main constructor * @param cfg the font manager configuration object - * @param baseURI the base URI of the configuration + * @param defaultBaseUri the default URI base to use for URI resolution + * @param resolver the URI resolver */ - public FontManagerConfigurator(Configuration cfg, URI baseURI) { + public FontManagerConfigurator(Configuration cfg, URI defaultBaseUri, + ResourceResolver resolver) { this.cfg = cfg; - this.baseURI = baseURI; + this.defaultBaseUri = defaultBaseUri; + this.uriResolver = resolver; } /** @@ -75,28 +74,29 @@ public class FontManagerConfigurator { // caching (fonts) if (cfg.getChild("use-cache", false) != null) { try { - fontManager.setUseCache(cfg.getChild("use-cache").getValueAsBoolean()); - } catch (ConfigurationException e) { - LogUtil.handleException(log, e, true); - } - } - if (cfg.getChild("cache-file", false) != null) { - try { - fontManager.setCacheFile(new File(cfg.getChild("cache-file").getValue())); - } catch (ConfigurationException e) { - LogUtil.handleException(log, e, true); + // TODO: Find some way to deal with this!! + if (!cfg.getChild("use-cache").getValueAsBoolean()) { + fontManager.disableFontCache(); + } else { + if (cfg.getChild("cache-file", false) != null) { + fontManager.setCacheFile(new File(cfg.getChild("cache-file").getValue())); + } + } + } catch (ConfigurationException mfue) { + LogUtil.handleException(log, mfue, true); } } if (cfg.getChild("font-base", false) != null) { - String path = cfg.getChild("font-base").getValue(null); - if (baseURI != null) { - path = baseURI.resolve(path).normalize().toString(); - } try { - fontManager.setFontBaseURL(path); - } catch (MalformedURLException mfue) { - LogUtil.handleException(log, mfue, true); + URI fontBase = URIResolverWrapper.getBaseURI(cfg.getChild("font-base").getValue( + null)); + fontManager.setFontURIResolver(new URIResolverWrapper( + defaultBaseUri.resolve(fontBase), uriResolver)); + } catch (URISyntaxException use) { + LogUtil.handleException(log, use, true); } + } else { + fontManager.setFontURIResolver(new URIResolverWrapper(defaultBaseUri, uriResolver)); } // [GA] permit configuration control over base14 kerning; without this, @@ -114,7 +114,6 @@ public class FontManagerConfigurator { // global font configuration Configuration fontsCfg = cfg.getChild("fonts", false); if (fontsCfg != null) { - // font substitution Configuration substitutionsCfg = fontsCfg.getChild("substitutions", false); if (substitutionsCfg != null) { @@ -122,7 +121,6 @@ public class FontManagerConfigurator { new FontSubstitutionsConfigurator(substitutionsCfg).configure(substitutions); fontManager.setFontSubstitutions(substitutions); } - // referenced fonts (fonts which are not to be embedded) Configuration referencedFontsCfg = fontsCfg.getChild("referenced-fonts", false); if (referencedFontsCfg != null) { @@ -130,7 +128,6 @@ public class FontManagerConfigurator { referencedFontsCfg, strict); fontManager.setReferencedFontsMatcher(matcher); } - } } @@ -159,6 +156,24 @@ public class FontManagerConfigurator { return orMatcher; } + /** + * Creates a font triplet matcher from a configuration object. + * @param fontFamilies the list of font families + * @param strict true for strict configuraton error handling + * @return the font matcher + * @throws FOPException if an error occurs while building the matcher + */ + public static FontTriplet.Matcher createFontsMatcher( + List<String> fontFamilies, boolean strict) throws FOPException { + List<FontTriplet.Matcher> matcherList = new java.util.ArrayList<FontTriplet.Matcher>(); + for (String fontFamily : fontFamilies) { + matcherList.add(new FontFamilyRegExFontTripletMatcher(fontFamily)); + } + FontTriplet.Matcher orMatcher = new OrFontTripletMatcher( + matcherList.toArray(new FontTriplet.Matcher[matcherList.size()])); + return orMatcher; + } + private static class OrFontTripletMatcher implements FontTriplet.Matcher { private final FontTriplet.Matcher[] matchers; diff --git a/src/java/org/apache/fop/fonts/FontReader.java b/src/java/org/apache/fop/fonts/FontReader.java index 9d75ad74f..7475161bb 100644 --- a/src/java/org/apache/fop/fonts/FontReader.java +++ b/src/java/org/apache/fop/fonts/FontReader.java @@ -21,6 +21,8 @@ package org.apache.fop.fonts; //Java import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -32,12 +34,12 @@ import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.InputSource; -import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.io.URIResolverWrapper; import org.apache.fop.fonts.apps.TTFReader; /** @@ -52,19 +54,30 @@ import org.apache.fop.fonts.apps.TTFReader; */ public class FontReader extends DefaultHandler { - // private Locator locator = null; // not used at present - private boolean isCID = false; - private CustomFont returnFont = null; - private MultiByteFont multiFont = null; - private SingleByteFont singleFont = null; + private boolean isCID; + private CustomFont returnFont; + private MultiByteFont multiFont; + private SingleByteFont singleFont; + private final URIResolverWrapper resolver; private StringBuffer text = new StringBuffer(); - private List<Integer> cidWidths = null; - private int cidWidthIndex = 0; + private List<Integer> cidWidths; + //private int cidWidthIndex; - private Map<Integer, Integer> currentKerning = null; + private Map<Integer, Integer> currentKerning; - private List<BFEntry> bfranges = null; + private List<BFEntry> bfranges; + + /** + * Construct a FontReader object from a path to a metric.xml file + * and read metric data + * @param source Source of the font metric file + * @throws FOPException if loading the font fails + */ + public FontReader(InputSource source, URIResolverWrapper resolver) throws FOPException { + this.resolver = resolver; + createFont(source); + } private void createFont(InputSource source) throws FOPException { XMLReader parser = null; @@ -81,11 +94,9 @@ public class FontReader extends DefaultHandler { } try { - parser.setFeature("http://xml.org/sax/features/namespace-prefixes", - false); + parser.setFeature("http://xml.org/sax/features/namespace-prefixes", false); } catch (SAXException e) { - throw new FOPException("You need a SAX parser which supports SAX version 2", - e); + throw new FOPException("You need a SAX parser which supports SAX version 2", e); } parser.setContentHandler(this); @@ -104,8 +115,8 @@ public class FontReader extends DefaultHandler { * Sets the path to embed a font. A null value disables font embedding. * @param path URI for the embeddable file */ - public void setFontEmbedPath(String path) { - returnFont.setEmbedFileName(path); + public void setFontEmbedURI(URI path) { + returnFont.setEmbedURI(path); } /** @@ -125,15 +136,6 @@ public class FontReader extends DefaultHandler { } /** - * Sets the font resolver. Needed for URI resolution. - * @param resolver the font resolver - */ - public void setResolver(FontResolver resolver) { - returnFont.setResolver(resolver); - } - - - /** * Get the generated font object * @return the font */ @@ -142,16 +144,6 @@ public class FontReader extends DefaultHandler { } /** - * Construct a FontReader object from a path to a metric.xml file - * and read metric data - * @param source Source of the font metric file - * @throws FOPException if loading the font fails - */ - public FontReader(InputSource source) throws FOPException { - createFont(source); - } - - /** * {@inheritDoc} */ public void startDocument() { @@ -160,65 +152,62 @@ public class FontReader extends DefaultHandler { /** * {@inheritDoc} */ - public void setDocumentLocator(Locator locator) { - // this.locator = locator; // not used at present - } - - /** - * {@inheritDoc} - */ - public void startElement(String uri, String localName, String qName, - Attributes attributes) throws SAXException { + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { if (localName.equals("font-metrics")) { if ("TYPE0".equals(attributes.getValue("type"))) { - multiFont = new MultiByteFont(); + multiFont = new MultiByteFont(resolver); returnFont = multiFont; isCID = true; TTFReader.checkMetricsVersion(attributes); } else if ("TRUETYPE".equals(attributes.getValue("type"))) { - singleFont = new SingleByteFont(); + singleFont = new SingleByteFont(resolver); singleFont.setFontType(FontType.TRUETYPE); returnFont = singleFont; isCID = false; TTFReader.checkMetricsVersion(attributes); } else { - singleFont = new SingleByteFont(); + singleFont = new SingleByteFont(resolver); singleFont.setFontType(FontType.TYPE1); returnFont = singleFont; isCID = false; } } else if ("embed".equals(localName)) { - returnFont.setEmbedFileName(attributes.getValue("file")); + try { + returnFont.setEmbedURI(URIResolverWrapper.cleanURI(attributes.getValue("file"))); + } catch (URISyntaxException e) { + // TODO: dunno what to do here?!?! + } returnFont.setEmbedResourceName(attributes.getValue("class")); } else if ("cid-widths".equals(localName)) { - cidWidthIndex = getInt(attributes.getValue("start-index")); + // This is unused + // cidWidthIndex = getInt(attributes.getValue("start-index")); cidWidths = new ArrayList<Integer>(); } else if ("kerning".equals(localName)) { currentKerning = new HashMap<Integer, Integer>(); - returnFont.putKerningEntry(new Integer(attributes.getValue("kpx1")), - currentKerning); + returnFont.putKerningEntry(getInt(attributes.getValue("kpx1")), + currentKerning); } else if ("bfranges".equals(localName)) { bfranges = new ArrayList<BFEntry>(); } else if ("bf".equals(localName)) { BFEntry entry = new BFEntry(getInt(attributes.getValue("us")), - getInt(attributes.getValue("ue")), - getInt(attributes.getValue("gi"))); + getInt(attributes.getValue("ue")), + getInt(attributes.getValue("gi"))); bfranges.add(entry); } else if ("wx".equals(localName)) { - cidWidths.add(new Integer(attributes.getValue("w"))); - } else if ("widths".equals(localName)) { - //singleFont.width = new int[256]; + cidWidths.add(getInt(attributes.getValue("w"))); + // } else if ("widths".equals(localName)) { + // singleFont.width = new int[256]; } else if ("char".equals(localName)) { try { - singleFont.setWidth(Integer.parseInt(attributes.getValue("idx")), - Integer.parseInt(attributes.getValue("wdt"))); + singleFont.setWidth(getInt(attributes.getValue("idx")), + getInt(attributes.getValue("wdt"))); } catch (NumberFormatException ne) { - throw new SAXException("Malformed width in metric file: " - + ne.getMessage(), ne); + throw new SAXException("Malformed width in metric file: " + ne.getMessage(), ne); } } else if ("pair".equals(localName)) { - currentKerning.put(new Integer(attributes.getValue("kpx2")), - new Integer(attributes.getValue("kern"))); + currentKerning.put(getInt(attributes.getValue("kpx2")), + getInt(attributes.getValue("kern"))); } } @@ -314,5 +303,4 @@ public class FontReader extends DefaultHandler { public void characters(char[] ch, int start, int length) { text.append(ch, start, length); } - } diff --git a/src/java/org/apache/fop/fonts/FontSetup.java b/src/java/org/apache/fop/fonts/FontSetup.java index ba31b2d50..76643d2a4 100644 --- a/src/java/org/apache/fop/fonts/FontSetup.java +++ b/src/java/org/apache/fop/fonts/FontSetup.java @@ -22,9 +22,7 @@ package org.apache.fop.fonts; // FOP (base 14 fonts) import java.util.List; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - +import org.apache.fop.apps.io.URIResolverWrapper; import org.apache.fop.fonts.base14.Courier; import org.apache.fop.fonts.base14.CourierBold; import org.apache.fop.fonts.base14.CourierBoldOblique; @@ -74,8 +72,8 @@ public final class FontSetup { * @param resolver the font resolver * @param base14Kerning true if base14 kerning applies */ - public static void setup(FontInfo fontInfo, List<EmbedFontInfo> embedFontInfoList, - FontResolver resolver, boolean base14Kerning) { + public static void setup(FontInfo fontInfo, List embedFontInfoList, + URIResolverWrapper resolver, boolean base14Kerning) { fontInfo.addMetrics("F1", new Helvetica(base14Kerning)); fontInfo.addMetrics("F2", new HelveticaOblique(base14Kerning)); fontInfo.addMetrics("F3", new HelveticaBold(base14Kerning)); @@ -192,18 +190,12 @@ public final class FontSetup { * @param resolver the font resolver */ private static void addConfiguredFonts(FontInfo fontInfo, - List<EmbedFontInfo> embedFontInfoList, int num, FontResolver resolver, + List<EmbedFontInfo> embedFontInfoList, int num, URIResolverWrapper resolver, boolean base14Kerning) { if (embedFontInfoList == null) { return; //No fonts to process } - - if (resolver == null) { - //Ensure that we have minimal font resolution capabilities - //None of the built-in base14 fonts have advanced typographic data - boolean useAdvanced = false; - resolver = createMinimalFontResolver(useAdvanced); - } + assert resolver != null; String internalName = null; @@ -211,7 +203,7 @@ public final class FontSetup { internalName = "F" + num; num++; - LazyFont font = new LazyFont(embedFontInfo, resolver); + LazyFont font = new LazyFont(embedFontInfo, resolver, false); fontInfo.addMetrics(internalName, font); List<FontTriplet> triplets = embedFontInfo.getFontTriplets(); @@ -221,32 +213,4 @@ public final class FontSetup { } } } - - /** - * Minimum implemenation of FontResolver. - */ - public static class MinimalFontResolver implements FontResolver { - private boolean useComplexScriptFeatures; - MinimalFontResolver(boolean useComplexScriptFeatures) { - this.useComplexScriptFeatures = useComplexScriptFeatures; - } - /** {@inheritDoc} */ - public Source resolve(String href) { - //Minimal functionality here - return new StreamSource(href); - } - /** {@inheritDoc} */ - public boolean isComplexScriptFeaturesEnabled() { - return useComplexScriptFeatures; - } - } - - /** - * Create minimal font resolver. - * @param useComplexScriptFeatures true if complex script features enabled - * @return a new FontResolver to be used by the font subsystem - */ - public static FontResolver createMinimalFontResolver(boolean useComplexScriptFeatures) { - return new MinimalFontResolver ( useComplexScriptFeatures ); - } } diff --git a/src/java/org/apache/fop/fonts/FontTriplet.java b/src/java/org/apache/fop/fonts/FontTriplet.java index c14634460..945739077 100644 --- a/src/java/org/apache/fop/fonts/FontTriplet.java +++ b/src/java/org/apache/fop/fonts/FontTriplet.java @@ -39,14 +39,6 @@ public class FontTriplet implements Comparable<FontTriplet>, Serializable { private transient String key; /** - * Creates a new font triplet (for base14 use). - * @param name font name - */ - public FontTriplet(String name) { - this.name = name; - } - - /** * Creates a new font triplet. * @param name font name * @param style font style (normal, italic etc.) @@ -64,7 +56,7 @@ public class FontTriplet implements Comparable<FontTriplet>, Serializable { * @param priority priority of this triplet/font mapping */ public FontTriplet(String name, String style, int weight, int priority) { - this(name); + this.name = name; this.style = style; this.weight = weight; this.priority = priority; diff --git a/src/java/org/apache/fop/fonts/LazyFont.java b/src/java/org/apache/fop/fonts/LazyFont.java index 7077c53b9..903997593 100644 --- a/src/java/org/apache/fop/fonts/LazyFont.java +++ b/src/java/org/apache/fop/fonts/LazyFont.java @@ -20,23 +20,20 @@ package org.apache.fop.fonts; import java.io.IOException; import java.io.InputStream; -import java.net.URL; +import java.net.URI; import java.util.Map; import java.util.Set; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - import org.xml.sax.InputSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.io.URIResolverWrapper; import org.apache.fop.complexscripts.fonts.Positionable; import org.apache.fop.complexscripts.fonts.Substitutable; - /** * This class is used to defer the loading of a font until it is really used. */ @@ -44,36 +41,35 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable, private static Log log = LogFactory.getLog(LazyFont.class); - private String metricsFileName; - private String fontEmbedPath; - private boolean useKerning; - private boolean useAdvanced; - private EncodingMode encodingMode = EncodingMode.AUTO; - private boolean embedded; - private String subFontName; + private final URI metricsURI; + private final URI fontEmbedURI; + private final boolean useKerning; + private final boolean useAdvanced; + private final EncodingMode encodingMode; + private final boolean embedded; + private final String subFontName; + private final URIResolverWrapper resolver; private boolean isMetricsLoaded; private Typeface realFont; private FontDescriptor realFontDescriptor; - private FontResolver resolver; - /** * Main constructor * @param fontInfo the font info to embed * @param resolver the font resolver to handle font URIs */ - public LazyFont(EmbedFontInfo fontInfo, FontResolver resolver) { - - this.metricsFileName = fontInfo.getMetricsFile(); - this.fontEmbedPath = fontInfo.getEmbedFile(); + public LazyFont(EmbedFontInfo fontInfo, URIResolverWrapper resolver, boolean useComplexScripts) { + this.metricsURI = fontInfo.getMetricsURI(); + this.fontEmbedURI = fontInfo.getEmbedURI(); this.useKerning = fontInfo.getKerning(); - if ( resolver != null ) { - this.useAdvanced = resolver.isComplexScriptFeaturesEnabled(); + if (resolver != null) { + this.useAdvanced = useComplexScripts; } else { this.useAdvanced = fontInfo.getAdvanced(); } - this.encodingMode = fontInfo.getEncodingMode(); + this.encodingMode = fontInfo.getEncodingMode() != null ? fontInfo.getEncodingMode() + : EncodingMode.AUTO; this.subFontName = fontInfo.getSubFontName(); this.embedded = fontInfo.isEmbedded(); this.resolver = resolver; @@ -83,8 +79,8 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable, public String toString() { StringBuffer sbuf = new StringBuffer(super.toString()); sbuf.append('{'); - sbuf.append("metrics-url=" + metricsFileName); - sbuf.append(",embed-url=" + fontEmbedPath); + sbuf.append("metrics-url=" + metricsURI); + sbuf.append(",embed-url=" + fontEmbedURI); sbuf.append(",kerning=" + useKerning); sbuf.append(",advanced=" + useAdvanced); sbuf.append('}'); @@ -94,74 +90,38 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable, private void load(boolean fail) { if (!isMetricsLoaded) { try { - if (metricsFileName != null) { + if (metricsURI != null) { /**@todo Possible thread problem here */ FontReader reader = null; - if (resolver != null) { - Source source = resolver.resolve(metricsFileName); - if (source == null) { - String err - = "Cannot load font: failed to create Source from metrics file " - + metricsFileName; - if (fail) { - throw new RuntimeException(err); - } else { - log.error(err); - } - return; - } - InputStream in = null; - if (source instanceof StreamSource) { - in = ((StreamSource) source).getInputStream(); - } - if (in == null && source.getSystemId() != null) { - in = new java.net.URL(source.getSystemId()).openStream(); - } - if (in == null) { - String err = "Cannot load font: After URI resolution, the returned" - + " Source object does not contain an InputStream" - + " or a valid URL (system identifier) for metrics file: " - + metricsFileName; - if (fail) { - throw new RuntimeException(err); - } else { - log.error(err); - } - return; - } - InputSource src = new InputSource(in); - src.setSystemId(source.getSystemId()); - reader = new FontReader(src); - } else { - reader = new FontReader(new InputSource( - new URL(metricsFileName).openStream())); - } + InputStream in = resolver.resolveIn(metricsURI); + InputSource src = new InputSource(in); + src.setSystemId(metricsURI.toASCIIString()); + reader = new FontReader(src, resolver); reader.setKerningEnabled(useKerning); reader.setAdvancedEnabled(useAdvanced); if (this.embedded) { - reader.setFontEmbedPath(fontEmbedPath); + reader.setFontEmbedURI(fontEmbedURI); } - reader.setResolver(resolver); realFont = reader.getFont(); } else { - if (fontEmbedPath == null) { + if (fontEmbedURI == null) { throw new RuntimeException("Cannot load font. No font URIs available."); } - realFont = FontLoader.loadFont(fontEmbedPath, this.subFontName, + realFont = FontLoader.loadFont(fontEmbedURI, this.subFontName, this.embedded, this.encodingMode, useKerning, useAdvanced, resolver); } if (realFont instanceof FontDescriptor) { realFontDescriptor = (FontDescriptor) realFont; } } catch (FOPException fopex) { - log.error("Failed to read font metrics file " + metricsFileName, fopex); + log.error("Failed to read font metrics file " + metricsURI, fopex); if (fail) { - throw new RuntimeException(fopex.getMessage()); + throw new RuntimeException(fopex); } } catch (IOException ioex) { - log.error("Failed to read font metrics file " + metricsFileName, ioex); + log.error("Failed to read font metrics file " + metricsURI, ioex); if (fail) { - throw new RuntimeException(ioex.getMessage()); + throw new RuntimeException(ioex); } } realFont.setEventListener(this.eventListener); diff --git a/src/java/org/apache/fop/fonts/MultiByteFont.java b/src/java/org/apache/fop/fonts/MultiByteFont.java index 73ef7c228..97de8c780 100644 --- a/src/java/org/apache/fop/fonts/MultiByteFont.java +++ b/src/java/org/apache/fop/fonts/MultiByteFont.java @@ -26,6 +26,7 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.apps.io.URIResolverWrapper; import org.apache.fop.complexscripts.fonts.GlyphDefinitionTable; import org.apache.fop.complexscripts.fonts.GlyphPositioningTable; import org.apache.fop.complexscripts.fonts.GlyphSubstitutionTable; @@ -74,9 +75,10 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl private int lastUnmapped; /** - * Default constructor + * @param resolver the URI resolver for controlling file access */ - public MultiByteFont() { + public MultiByteFont(URIResolverWrapper resolver) { + super(resolver); subset.setupFirstGlyph(); setFontType(FontType.TYPE0); } @@ -125,7 +127,7 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl /** {@inheritDoc} */ public boolean isEmbeddable() { - return !(getEmbedFileName() == null && getEmbedResourceName() == null); + return !(getEmbedFileURI() == null && getEmbedResourceName() == null); } /** {@inheritDoc} */ @@ -561,7 +563,7 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl } } cb.flip(); - return (CharSequence) cb; + return cb; } } diff --git a/src/java/org/apache/fop/fonts/MutableFont.java b/src/java/org/apache/fop/fonts/MutableFont.java index 41c552a0b..4b8a38e51 100644 --- a/src/java/org/apache/fop/fonts/MutableFont.java +++ b/src/java/org/apache/fop/fonts/MutableFont.java @@ -19,6 +19,7 @@ package org.apache.fop.fonts; +import java.net.URI; import java.util.Map; import java.util.Set; @@ -49,10 +50,10 @@ public interface MutableFont { void setFamilyNames(Set<String> names); /** - * Sets the path to the embeddable font file. - * @param path URI to the file + * Sets the URI to the embeddable font. + * @param path URI to the font */ - void setEmbedFileName(String path); + void setEmbedURI(URI path); /** * Sets the resource name of the embeddable font file. diff --git a/src/java/org/apache/fop/fonts/SingleByteFont.java b/src/java/org/apache/fop/fonts/SingleByteFont.java index d5901297f..604778239 100644 --- a/src/java/org/apache/fop/fonts/SingleByteFont.java +++ b/src/java/org/apache/fop/fonts/SingleByteFont.java @@ -31,6 +31,8 @@ import org.apache.commons.logging.LogFactory; import org.apache.xmlgraphics.fonts.Glyphs; +import org.apache.fop.apps.io.URIResolverWrapper; + /** * Generic SingleByte font */ @@ -50,15 +52,16 @@ public class SingleByteFont extends CustomFont { /** - * Main constructor. + * @param resolver the URI resolver for controlling file access */ - public SingleByteFont() { + public SingleByteFont(URIResolverWrapper resolver) { + super(resolver); setEncoding(CodePointMapping.WIN_ANSI_ENCODING); } /** {@inheritDoc} */ public boolean isEmbeddable() { - return (!(getEmbedFileName() == null + return (!(getEmbedFileURI() == 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 6acb490c2..8d06f0e6b 100644 --- a/src/java/org/apache/fop/fonts/apps/TTFReader.java +++ b/src/java/org/apache/fop/fonts/apps/TTFReader.java @@ -19,7 +19,9 @@ package org.apache.fop.fonts.apps; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -220,12 +222,17 @@ public class TTFReader extends AbstractFontReader { public TTFFile loadTTF(String fileName, String fontName, boolean useKerning, boolean useAdvanced) throws IOException { TTFFile ttfFile = new TTFFile(useKerning, useAdvanced); log.info("Reading " + fileName + "..."); - - FontFileReader reader = new FontFileReader(fileName); - boolean supported = ttfFile.readFont(reader, fontName); - if (!supported) { - return null; + InputStream stream = new FileInputStream(fileName); + try { + FontFileReader reader = new FontFileReader(stream); + boolean supported = ttfFile.readFont(reader, fontName); + if (!supported) { + return null; + } + } finally { + stream.close(); } + log.info("Font Family: " + ttfFile.getFamilyNames()); if (ttfFile.isCFF()) { throw new UnsupportedOperationException( @@ -460,9 +467,9 @@ public class TTFReader extends AbstractFontReader { Map h2; if (isCid) { - h2 = (Map)ttf.getKerning().get(kpx1); + h2 = ttf.getKerning().get(kpx1); } else { - h2 = (Map)ttf.getAnsiKerning().get(kpx1); + h2 = ttf.getAnsiKerning().get(kpx1); } Iterator iter2 = h2.keySet().iterator(); diff --git a/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java b/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java index bd0a33cb1..5bd19b88b 100644 --- a/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java +++ b/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java @@ -20,7 +20,7 @@ package org.apache.fop.fonts.autodetect; import java.io.InputStream; -import java.net.URL; +import java.net.URI; import java.util.Collection; import java.util.List; import java.util.Set; @@ -30,6 +30,7 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.apps.io.URIResolverWrapper; import org.apache.fop.fonts.CustomFont; import org.apache.fop.fonts.EmbedFontInfo; import org.apache.fop.fonts.EncodingMode; @@ -37,7 +38,6 @@ import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontCache; import org.apache.fop.fonts.FontEventListener; import org.apache.fop.fonts.FontLoader; -import org.apache.fop.fonts.FontResolver; import org.apache.fop.fonts.FontTriplet; import org.apache.fop.fonts.FontUtil; import org.apache.fop.fonts.MultiByteFont; @@ -133,26 +133,24 @@ public class FontInfoFinder { /** * Attempts to determine FontInfo from a given custom font - * @param fontURL the font URL + * @param fontUri the font URI * @param customFont the custom font * @param fontCache font cache (may be null) * @return FontInfo from the given custom font */ - private EmbedFontInfo getFontInfoFromCustomFont( - URL fontURL, CustomFont customFont, FontCache fontCache) { + private EmbedFontInfo getFontInfoFromCustomFont(URI fontUri, CustomFont customFont, + FontCache fontCache, URIResolverWrapper resolver) { List<FontTriplet> fontTripletList = new java.util.ArrayList<FontTriplet>(); generateTripletsFromFont(customFont, fontTripletList); - String embedUrl; - embedUrl = fontURL.toExternalForm(); String subFontName = null; if (customFont instanceof MultiByteFont) { - subFontName = ((MultiByteFont)customFont).getTTCName(); + subFontName = ((MultiByteFont) customFont).getTTCName(); } EmbedFontInfo fontInfo = new EmbedFontInfo(null, customFont.isKerningEnabled(), - customFont.isAdvancedEnabled(), fontTripletList, embedUrl, subFontName); + customFont.isAdvancedEnabled(), fontTripletList, fontUri, subFontName); fontInfo.setPostScriptName(customFont.getFontName()); if (fontCache != null) { - fontCache.addFont(fontInfo); + fontCache.addFont(fontInfo, resolver); } return fontInfo; } @@ -160,32 +158,31 @@ public class FontInfoFinder { /** * Attempts to determine EmbedFontInfo from a given font file. * - * @param fontURL font URL. Assumed to be local. + * @param fontURI the URI of the font resource * @param resolver font resolver used to resolve font * @param fontCache font cache (may be null) * @return an array of newly created embed font info. Generally, this array * will have only one entry, unless the fontUrl is a TrueType Collection */ - public EmbedFontInfo[] find(URL fontURL, FontResolver resolver, FontCache fontCache) { - String embedURL = null; - embedURL = fontURL.toExternalForm(); + public EmbedFontInfo[] find(URI fontURI, URIResolverWrapper resolver, FontCache fontCache) { + URI embedUri = resolver.getBaseURI().resolve(fontURI); + String embedStr = embedUri.toASCIIString(); boolean useKerning = true; - boolean useAdvanced = ( resolver != null ) - ? resolver.isComplexScriptFeaturesEnabled() : true; + boolean useAdvanced = true; long fileLastModified = -1; if (fontCache != null) { - fileLastModified = FontCache.getLastModified(fontURL); + fileLastModified = FontCache.getLastModified(fontURI); // firstly try and fetch it from cache before loading/parsing the font file - if (fontCache.containsFont(embedURL)) { - EmbedFontInfo[] fontInfos = fontCache.getFontInfos(embedURL, fileLastModified); + if (fontCache.containsFont(embedStr)) { + EmbedFontInfo[] fontInfos = fontCache.getFontInfos(embedStr, fileLastModified); if (fontInfos != null) { return fontInfos; } // is this a previously failed parsed font? - } else if (fontCache.isFailedFont(embedURL, fileLastModified)) { + } else if (fontCache.isFailedFont(embedStr, fileLastModified)) { if (log.isDebugEnabled()) { - log.debug("Skipping font file that failed to load previously: " + embedURL); + log.debug("Skipping font file that failed to load previously: " + embedUri); } return null; } @@ -194,19 +191,19 @@ public class FontInfoFinder { // try to determine triplet information from font file CustomFont customFont = null; - if (fontURL.toExternalForm().toLowerCase().endsWith(".ttc")) { + if (fontURI.toASCIIString().toLowerCase().endsWith(".ttc")) { // Get a list of the TTC Font names List<String> ttcNames = null; - String fontFileURL = fontURL.toExternalForm().trim(); InputStream in = null; try { - in = FontLoader.openFontUri(resolver, fontFileURL); + in = resolver.resolveIn(fontURI); TTFFile ttf = new TTFFile(false, false); FontFileReader reader = new FontFileReader(in); ttcNames = ttf.getTTCnames(reader); } catch (Exception e) { if (this.eventListener != null) { - this.eventListener.fontLoadingErrorAtAutoDetection(this, fontFileURL, e); + this.eventListener.fontLoadingErrorAtAutoDetection(this, + fontURI.toASCIIString(), e); } return null; } finally { @@ -221,23 +218,24 @@ public class FontInfoFinder { log.debug("Loading " + fontName); } try { - TTFFontLoader ttfLoader = new TTFFontLoader( - fontFileURL, fontName, true, EncodingMode.AUTO, - useKerning, useAdvanced, resolver); + TTFFontLoader ttfLoader = new TTFFontLoader(fontURI, fontName, true, + EncodingMode.AUTO, useKerning, useAdvanced, resolver); customFont = ttfLoader.getFont(); if (this.eventListener != null) { customFont.setEventListener(this.eventListener); } } catch (Exception e) { if (fontCache != null) { - fontCache.registerFailedFont(embedURL, fileLastModified); + fontCache.registerFailedFont(embedUri.toASCIIString(), fileLastModified); } if (this.eventListener != null) { - this.eventListener.fontLoadingErrorAtAutoDetection(this, embedURL, e); + this.eventListener.fontLoadingErrorAtAutoDetection(this, + embedUri.toASCIIString(), e); } continue; } - EmbedFontInfo fi = getFontInfoFromCustomFont(fontURL, customFont, fontCache); + EmbedFontInfo fi = getFontInfoFromCustomFont(fontURI, customFont, fontCache, + resolver); if (fi != null) { embedFontInfoList.add(fi); } @@ -247,20 +245,22 @@ public class FontInfoFinder { } else { // The normal case try { - customFont = FontLoader.loadFont(fontURL, null, true, EncodingMode.AUTO, resolver); + customFont = FontLoader.loadFont(fontURI, null, true, EncodingMode.AUTO, + useKerning, useAdvanced, resolver); if (this.eventListener != null) { customFont.setEventListener(this.eventListener); } } catch (Exception e) { if (fontCache != null) { - fontCache.registerFailedFont(embedURL, fileLastModified); + fontCache.registerFailedFont(embedUri.toASCIIString(), fileLastModified); } if (this.eventListener != null) { - this.eventListener.fontLoadingErrorAtAutoDetection(this, embedURL, e); + this.eventListener.fontLoadingErrorAtAutoDetection(this, + embedUri.toASCIIString(), e); } return null; } - EmbedFontInfo fi = getFontInfoFromCustomFont(fontURL, customFont, fontCache); + EmbedFontInfo fi = getFontInfoFromCustomFont(fontURI, customFont, fontCache, resolver); if (fi != null) { return new EmbedFontInfo[] {fi}; } else { diff --git a/src/java/org/apache/fop/fonts/truetype/FontFileReader.java b/src/java/org/apache/fop/fonts/truetype/FontFileReader.java index b97120990..7167d4796 100644 --- a/src/java/org/apache/fop/fonts/truetype/FontFileReader.java +++ b/src/java/org/apache/fop/fonts/truetype/FontFileReader.java @@ -19,7 +19,6 @@ package org.apache.fop.fonts.truetype; -import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -31,38 +30,9 @@ import org.apache.commons.io.IOUtils; */ public class FontFileReader { - private int fsize; // file size + private final int fsize; // file size private int current; // current position in file - private byte[] file; - - /** - * Initializes class and reads stream. Init does not close stream. - * - * @param in InputStream to read from new array with size + inc - * @throws IOException In case of an I/O problem - */ - private void init(InputStream in) throws java.io.IOException { - this.file = IOUtils.toByteArray(in); - this.fsize = this.file.length; - this.current = 0; - } - - /** - * Constructor - * - * @param fileName filename to read - * @throws IOException In case of an I/O problem - */ - public FontFileReader(String fileName) throws IOException { - final File f = new File(fileName); - InputStream in = new java.io.FileInputStream(f); - try { - init(in); - } finally { - in.close(); - } - } - + private final byte[] file; /** * Constructor @@ -71,7 +41,9 @@ public class FontFileReader { * @throws IOException In case of an I/O problem */ public FontFileReader(InputStream in) throws IOException { - init(in); + this.file = IOUtils.toByteArray(in); + this.fsize = this.file.length; + this.current = 0; } diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFile.java b/src/java/org/apache/fop/fonts/truetype/TTFFile.java index 65ab560cf..34daa7a9c 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFile.java @@ -19,13 +19,16 @@ package org.apache.fop.fonts.truetype; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.util.BitSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -1816,12 +1819,14 @@ public class TTFFile { * @param args The command line arguments */ public static void main(String[] args) { + InputStream stream = null; try { boolean useKerning = true; boolean useAdvanced = true; + stream = new FileInputStream(args[0]); TTFFile ttfFile = new TTFFile(useKerning, useAdvanced); - FontFileReader reader = new FontFileReader(args[0]); + FontFileReader reader = new FontFileReader(stream); String name = null; if (args.length >= 2) { @@ -1834,6 +1839,9 @@ public class TTFFile { } catch (IOException ioe) { System.err.println("Problem reading font: " + ioe.toString()); ioe.printStackTrace(System.err); + } finally { + IOUtils.closeQuietly(stream); } + } } diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java index c03f0fb6a..4e4362008 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java @@ -21,6 +21,7 @@ package org.apache.fop.fonts.truetype; import java.io.IOException; import java.io.InputStream; +import java.net.URI; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -30,11 +31,11 @@ import org.apache.commons.io.IOUtils; import org.apache.xmlgraphics.fonts.Glyphs; +import org.apache.fop.apps.io.URIResolverWrapper; import org.apache.fop.fonts.BFEntry; import org.apache.fop.fonts.CIDFontType; import org.apache.fop.fonts.EncodingMode; import org.apache.fop.fonts.FontLoader; -import org.apache.fop.fonts.FontResolver; import org.apache.fop.fonts.FontType; import org.apache.fop.fonts.MultiByteFont; import org.apache.fop.fonts.NamedCharacter; @@ -55,7 +56,7 @@ public class TTFFontLoader extends FontLoader { * @param fontFileURI the URI representing the font file * @param resolver the FontResolver for font URI resolution */ - public TTFFontLoader(String fontFileURI, FontResolver resolver) { + public TTFFontLoader(URI fontFileURI, URIResolverWrapper resolver) { this(fontFileURI, null, true, EncodingMode.AUTO, true, true, resolver); } @@ -70,9 +71,9 @@ public class TTFFontLoader extends FontLoader { * @param useAdvanced true to enable loading advanced info if available, false to disable * @param resolver the FontResolver for font URI resolution */ - public TTFFontLoader(String fontFileURI, String subFontName, + public TTFFontLoader(URI fontFileURI, String subFontName, boolean embedded, EncodingMode encodingMode, boolean useKerning, - boolean useAdvanced, FontResolver resolver) { + boolean useAdvanced, URIResolverWrapper resolver) { super(fontFileURI, embedded, useKerning, useAdvanced, resolver); this.subFontName = subFontName; this.encodingMode = encodingMode; @@ -94,7 +95,7 @@ public class TTFFontLoader extends FontLoader { * @throws IOException if an I/O error occurs */ private void read(String ttcFontName) throws IOException { - InputStream in = openFontUri(resolver, this.fontFileURI); + InputStream in = resolver.resolveIn(this.fontFileURI); try { TTFFile ttf = new TTFFile(useKerning, useAdvanced); FontFileReader reader = new FontFileReader(in); @@ -122,14 +123,13 @@ public class TTFFontLoader extends FontLoader { } if (isCid) { - multiFont = new MultiByteFont(); + multiFont = new MultiByteFont(resolver); returnFont = multiFont; multiFont.setTTCName(ttcFontName); } else { - singleFont = new SingleByteFont(); + singleFont = new SingleByteFont(resolver); returnFont = singleFont; } - returnFont.setResolver(resolver); returnFont.setFontName(ttf.getPostScriptName()); returnFont.setFullName(ttf.getFullName()); @@ -177,7 +177,7 @@ public class TTFFontLoader extends FontLoader { } if (this.embedded) { if (ttf.isEmbeddable()) { - returnFont.setEmbedFileName(this.fontFileURI); + returnFont.setEmbedURI(this.fontFileURI); } else { String msg = "The font " + this.fontFileURI + " is not embeddable due to a" + " licensing restriction."; diff --git a/src/java/org/apache/fop/fonts/type1/PFBParser.java b/src/java/org/apache/fop/fonts/type1/PFBParser.java index b92332b6d..339a9e141 100644 --- a/src/java/org/apache/fop/fonts/type1/PFBParser.java +++ b/src/java/org/apache/fop/fonts/type1/PFBParser.java @@ -48,38 +48,6 @@ public class PFBParser { /** * Parses a PFB file into a PFBData object. - * @param url URL to load the PFB file from - * @return PFBData memory representation of the font - * @throws IOException In case of an I/O problem - */ - public PFBData parsePFB(java.net.URL url) throws IOException { - InputStream in = url.openStream(); - try { - return parsePFB(in); - } finally { - in.close(); - } - } - - - /** - * Parses a PFB file into a PFBData object. - * @param pfbFile File to load the PFB file from - * @return PFBData memory representation of the font - * @throws IOException In case of an I/O problem - */ - public PFBData parsePFB(java.io.File pfbFile) throws IOException { - InputStream in = new java.io.FileInputStream(pfbFile); - try { - return parsePFB(in); - } finally { - in.close(); - } - } - - - /** - * Parses a PFB file into a PFBData object. * @param in InputStream to load the PFB file from * @return PFBData memory representation of the font * @throws IOException In case of an I/O problem @@ -113,7 +81,6 @@ public class PFBParser { private void parsePCFormat(PFBData pfb, DataInputStream din) throws IOException { int segmentHead; int segmentType; - int bytesRead; //Read first segment segmentHead = din.readUnsignedByte(); diff --git a/src/java/org/apache/fop/fonts/type1/PFMFile.java b/src/java/org/apache/fop/fonts/type1/PFMFile.java index d1a3d79ff..3b171e85a 100644 --- a/src/java/org/apache/fop/fonts/type1/PFMFile.java +++ b/src/java/org/apache/fop/fonts/type1/PFMFile.java @@ -23,6 +23,7 @@ package org.apache.fop.fonts.type1; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.HashMap; import java.util.Map; import org.apache.commons.io.IOUtils; @@ -40,7 +41,7 @@ public class PFMFile { private String windowsName; private String postscriptName; private short dfItalic; - private int dfWeight; + //private int dfWeight; private short dfCharSet; private short dfPitchAndFamily; private int dfAvgWidth; @@ -61,7 +62,7 @@ public class PFMFile { // Extent table private int[] extentTable; - private Map kerningTab = new java.util.HashMap(); + private Map<Integer, Map<Integer, Integer>> kerningTab = new HashMap<Integer, Map<Integer, Integer>>(); /** * logging instance @@ -119,7 +120,7 @@ public class PFMFile { inStream.skip(80); dfItalic = inStream.readByte(); inStream.skip(2); - dfWeight = inStream.readShort(); + inStream.readShort(); // dfWeight = dfCharSet = inStream.readByte(); inStream.skip(4); dfPitchAndFamily = inStream.readByte(); @@ -192,10 +193,10 @@ public class PFMFile { log.trace(i + " kerning pairs"); } while (i > 0) { - int g1 = (int)inStream.readByte(); + int g1 = (int) inStream.readByte(); i--; - int g2 = (int)inStream.readByte(); + int g2 = (int) inStream.readByte(); int adj = inStream.readShort(); if (adj > 0x8000) { @@ -209,12 +210,12 @@ public class PFMFile { log.trace("glyphs: " + glyph1 + ", " + glyph2); } - Map adjTab = (Map)kerningTab.get(new Integer(g1)); + Map<Integer, Integer> adjTab = kerningTab.get(Integer.valueOf(g1)); if (adjTab == null) { - adjTab = new java.util.HashMap(); + adjTab = new HashMap<Integer, Integer>(); } - adjTab.put(new Integer(g2), new Integer(adj)); - kerningTab.put(new Integer(g1), adjTab); + adjTab.put(Integer.valueOf(g2), Integer.valueOf(adj)); + kerningTab.put(Integer.valueOf(g1), adjTab); } } @@ -270,7 +271,7 @@ public class PFMFile { * * @return A Map containing the kerning table */ - public Map getKerning() { + public Map<Integer, Map<Integer, Integer>> getKerning() { return kerningTab; } @@ -453,9 +454,9 @@ public class PFMFile { public int getStemV() { // Just guessing.... if (dfItalic != 0) { - return (int)Math.round(dfMinWidth * 0.25); + return (int) Math.round(dfMinWidth * 0.25); } else { - return (int)Math.round(dfMinWidth * 0.6); + return (int) Math.round(dfMinWidth * 0.6); } } diff --git a/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java b/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java index 924f7b0b8..1a3e50752 100644 --- a/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java +++ b/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java @@ -22,15 +22,17 @@ package org.apache.fop.fonts.type1; import java.awt.geom.RectangularShape; import java.io.IOException; import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.io.IOUtils; +import org.apache.fop.apps.io.URIResolverWrapper; import org.apache.fop.fonts.CodePointMapping; import org.apache.fop.fonts.FontLoader; -import org.apache.fop.fonts.FontResolver; import org.apache.fop.fonts.FontType; import org.apache.fop.fonts.SingleByteEncoding; import org.apache.fop.fonts.SingleByteFont; @@ -50,8 +52,8 @@ public class Type1FontLoader extends FontLoader { * @param resolver the font resolver used to resolve URIs * @throws IOException In case of an I/O error */ - public Type1FontLoader(String fontFileURI, boolean embedded, boolean useKerning, - FontResolver resolver) throws IOException { + public Type1FontLoader(URI fontFileURI, boolean embedded, boolean useKerning, + URIResolverWrapper resolver) throws IOException { super(fontFileURI, embedded, useKerning, true, resolver); } @@ -71,17 +73,21 @@ public class Type1FontLoader extends FontLoader { PFMFile pfm = null; InputStream afmIn = null; + String fontFileStr = fontFileURI.toASCIIString(); + String partialAfmUri = fontFileStr.substring(0, fontFileStr.length() - 4); String afmUri = null; for (int i = 0; i < AFM_EXTENSIONS.length; i++) { try { - afmUri = this.fontFileURI.substring(0, this.fontFileURI.length() - 4) - + AFM_EXTENSIONS[i]; - afmIn = openFontUri(resolver, afmUri); + afmUri = partialAfmUri + AFM_EXTENSIONS[i]; + afmIn = resolver.resolveIn(afmUri); if (afmIn != null) { break; } } catch (IOException ioe) { // Ignore, AFM probably not available under the URI + } catch (URISyntaxException e) { + // TODO: Not sure what the best thing to do here is?!? + throw new RuntimeException(e); } } if (afmIn != null) { @@ -93,12 +99,14 @@ public class Type1FontLoader extends FontLoader { } } - String pfmUri = getPFMURI(this.fontFileURI); + String pfmUri = getPFMURI(fontFileStr); InputStream pfmIn = null; try { - pfmIn = openFontUri(resolver, pfmUri); + pfmIn = resolver.resolveIn(pfmUri); } catch (IOException ioe) { // Ignore, PFM probably not available under the URI + } catch (URISyntaxException e) { + // Ignore, PFM probably not available under the URI } if (pfmIn != null) { try { @@ -126,11 +134,10 @@ public class Type1FontLoader extends FontLoader { if (afm == null && pfm == null) { throw new IllegalArgumentException("Need at least an AFM or a PFM!"); } - singleFont = new SingleByteFont(); + singleFont = new SingleByteFont(resolver); singleFont.setFontType(FontType.TYPE1); - singleFont.setResolver(this.resolver); if (this.embedded) { - singleFont.setEmbedFileName(this.fontFileURI); + singleFont.setEmbedURI(this.fontFileURI); } returnFont = singleFont; diff --git a/src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java index a46b74e1a..7cbe33f26 100644 --- a/src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java @@ -91,7 +91,7 @@ public class ExternalDocumentLayoutManager extends AbstractPageSequenceLayoutMan initialize(); FOUserAgent userAgent = pageSeq.getUserAgent(); - ImageManager imageManager = userAgent.getFactory().getImageManager(); + ImageManager imageManager = userAgent.getImageManager(); String uri = URISpecification.getURL(getExternalDocument().getSrc()); Integer firstPageIndex = ImageUtil.getPageIndexFromURI(uri); diff --git a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java index 27958f7e0..0f959022c 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java @@ -1399,8 +1399,8 @@ public class LineLayoutManager extends InlineStackingLayoutManager Hyphenation hyph = Hyphenator.hyphenate(hyphenationProperties.language.getString(), hyphenationProperties.country.getString(), - getFObj().getUserAgent().getFactory().getHyphenationTreeResolver(), - getFObj().getUserAgent().getFactory().getHyphPatNames(), + getFObj().getUserAgent().getHyphenationTreeResolver(), + getFObj().getUserAgent().getHyphPatNames(), sbChars.toString(), hyphenationProperties.hyphenationRemainCharacterCount.getValue(), hyphenationProperties.hyphenationPushCharacterCount.getValue()); diff --git a/src/java/org/apache/fop/pdf/PDFAMode.java b/src/java/org/apache/fop/pdf/PDFAMode.java index b5b764dd4..899f9aa7d 100644 --- a/src/java/org/apache/fop/pdf/PDFAMode.java +++ b/src/java/org/apache/fop/pdf/PDFAMode.java @@ -20,14 +20,14 @@ package org.apache.fop.pdf; /** Enum class for PDF/A modes. */ -public final class PDFAMode { +public enum PDFAMode { /** PDF/A disabled */ - public static final PDFAMode DISABLED = new PDFAMode("PDF/A disabled"); + DISABLED("PDF/A disabled"), /** PDF/A-1a enabled */ - public static final PDFAMode PDFA_1A = new PDFAMode("PDF/A-1a"); + PDFA_1A("PDF/A-1a"), /** PDF/A-1b enabled */ - public static final PDFAMode PDFA_1B = new PDFAMode("PDF/A-1b"); + PDFA_1B("PDF/A-1b"); private String name; @@ -66,7 +66,7 @@ public final class PDFAMode { * @param s the string * @return the PDFAMode enum object (DISABLED will be returned if no match is found) */ - public static PDFAMode valueOf(String s) { + public static PDFAMode getValueOf(String s) { if (PDFA_1A.getName().equalsIgnoreCase(s)) { return PDFA_1A; } else if (PDFA_1B.getName().equalsIgnoreCase(s)) { diff --git a/src/java/org/apache/fop/pdf/PDFEncryptionParams.java b/src/java/org/apache/fop/pdf/PDFEncryptionParams.java index 71dccd867..563c05233 100644 --- a/src/java/org/apache/fop/pdf/PDFEncryptionParams.java +++ b/src/java/org/apache/fop/pdf/PDFEncryptionParams.java @@ -273,4 +273,17 @@ public class PDFEncryptionParams { this.encryptionLengthInBits = encryptionLength; } + public String toString() { + return "userPassword = " + userPassword + "\n" + + "ownerPassword = " + ownerPassword + "\n" + + "allowPrint = " + allowPrint + "\n" + + "allowCopyContent = " + allowCopyContent + "\n" + + "allowEditContent = " + allowEditContent + "\n" + + "allowEditAnnotations = " + allowEditAnnotations + "\n" + + "allowFillInForms = " + allowFillInForms + "\n" + + "allowAccessContent = " + allowAccessContent + "\n" + + "allowAssembleDocument = " + allowAssembleDocument + "\n" + + "allowPrintHq = " + allowPrintHq; + } + } diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java index cc1d93de0..39ddf7262 100644 --- a/src/java/org/apache/fop/pdf/PDFFactory.java +++ b/src/java/org/apache/fop/pdf/PDFFactory.java @@ -23,10 +23,8 @@ package org.apache.fop.pdf; import java.awt.Color; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; @@ -35,9 +33,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.commons.logging.Log; @@ -1636,79 +1631,48 @@ public class PDFFactory { InputStream in = null; try { - Source source = font.getEmbedFileSource(); - if (source == null && font.getEmbedResourceName() != null) { - source = new StreamSource(this.getClass() - .getResourceAsStream(font.getEmbedResourceName())); - } - if (source == null) { - return null; - } - if (source instanceof StreamSource) { - in = ((StreamSource) source).getInputStream(); - } - if (in == null && source.getSystemId() != null) { - try { - in = new java.net.URL(source.getSystemId()).openStream(); - } catch (MalformedURLException e) { - //TODO: Why construct a new exception here, when it is not thrown? - new FileNotFoundException( - "File not found. URL could not be resolved: " - + e.getMessage()); - } - } - if (in == null) { - return null; - } - //Make sure the InputStream is decorated with a BufferedInputStream - if (!(in instanceof java.io.BufferedInputStream)) { - in = new java.io.BufferedInputStream(in); - } + in = font.getInputStream(); if (in == null) { return null; } else { - try { - AbstractPDFStream embeddedFont; - if (desc.getFontType() == FontType.TYPE0) { - MultiByteFont mbfont = (MultiByteFont)font; - FontFileReader reader = new FontFileReader(in); - - TTFSubSetFile subset = new TTFSubSetFile(); - byte[] subsetFont = subset.readFont(reader, - mbfont.getTTCName(), mbfont.getUsedGlyphs()); - // Only TrueType CID fonts are supported now - - embeddedFont = new PDFTTFStream(subsetFont.length); - ((PDFTTFStream)embeddedFont).setData(subsetFont, subsetFont.length); - } else if (desc.getFontType() == FontType.TYPE1) { - PFBParser parser = new PFBParser(); - PFBData pfb = parser.parsePFB(in); - embeddedFont = new PDFT1Stream(); - ((PDFT1Stream)embeddedFont).setData(pfb); - } else { - byte[] file = IOUtils.toByteArray(in); - embeddedFont = new PDFTTFStream(file.length); - ((PDFTTFStream)embeddedFont).setData(file, file.length); - } + AbstractPDFStream embeddedFont; + if (desc.getFontType() == FontType.TYPE0) { + MultiByteFont mbfont = (MultiByteFont) font; + FontFileReader reader = new FontFileReader(in); + + TTFSubSetFile subset = new TTFSubSetFile(); + byte[] subsetFont = subset.readFont(reader, + mbfont.getTTCName(), mbfont.getUsedGlyphs()); + // Only TrueType CID fonts are supported now + + embeddedFont = new PDFTTFStream(subsetFont.length); + ((PDFTTFStream) embeddedFont).setData(subsetFont, subsetFont.length); + } else if (desc.getFontType() == FontType.TYPE1) { + PFBParser parser = new PFBParser(); + PFBData pfb = parser.parsePFB(in); + embeddedFont = new PDFT1Stream(); + ((PDFT1Stream) embeddedFont).setData(pfb); + } else { + byte[] file = IOUtils.toByteArray(in); + embeddedFont = new PDFTTFStream(file.length); + ((PDFTTFStream) embeddedFont).setData(file, file.length); + } - /* - embeddedFont.getFilterList().addFilter("flate"); - if (getDocument().isEncryptionActive()) { - getDocument().applyEncryption(embeddedFont); - } else { - embeddedFont.getFilterList().addFilter("ascii-85"); - }*/ + /* + embeddedFont.getFilterList().addFilter("flate"); + if (getDocument().isEncryptionActive()) { + getDocument().applyEncryption(embeddedFont); + } else { + embeddedFont.getFilterList().addFilter("ascii-85"); + }*/ - return embeddedFont; - } finally { - in.close(); - } + return embeddedFont; } } catch (IOException ioe) { - log.error( - "Failed to embed font [" + desc + "] " - + desc.getEmbedFontName(), ioe); + log.error("Failed to embed font [" + desc + "] " + desc.getEmbedFontName(), ioe); return null; + } finally { + IOUtils.closeQuietly(in); } } diff --git a/src/java/org/apache/fop/pdf/PDFResources.java b/src/java/org/apache/fop/pdf/PDFResources.java index df8647bf4..c625813b0 100644 --- a/src/java/org/apache/fop/pdf/PDFResources.java +++ b/src/java/org/apache/fop/pdf/PDFResources.java @@ -21,9 +21,9 @@ package org.apache.fop.pdf; import java.io.IOException; import java.io.OutputStream; -import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; @@ -46,33 +46,33 @@ public class PDFResources extends PDFDictionary { /** * /Font objects keyed by their internal name */ - protected Map fonts = new HashMap(); + protected Map fonts = new LinkedHashMap(); /** * Set of XObjects */ - protected Set xObjects = new HashSet(); + protected Set xObjects = new LinkedHashSet(); /** * Set of patterns */ - protected Set patterns = new HashSet(); + protected Set patterns = new LinkedHashSet(); /** * Set of shadings */ - protected Set shadings = new HashSet(); + protected Set shadings = new LinkedHashSet(); /** * Set of ExtGStates */ - protected Set gstates = new HashSet(); + protected Set gstates = new LinkedHashSet(); /** Map of color spaces (key: color space name) */ - protected Map colorSpaces = new HashMap(); + protected Map colorSpaces = new LinkedHashMap(); /** Map of ICC color spaces (key: ICC profile description) */ - protected Map iccColorSpaces = new HashMap(); + protected Map iccColorSpaces = new LinkedHashMap(); /** * create a /Resources object. @@ -205,7 +205,7 @@ public class PDFResources extends PDFDictionary { Iterator fontIterator = this.fonts.keySet().iterator(); while (fontIterator.hasNext()) { String fontName = (String)fontIterator.next(); - dict.put(fontName, (PDFFont)this.fonts.get(fontName)); + dict.put(fontName, this.fonts.get(fontName)); } put("Font", dict); } diff --git a/src/java/org/apache/fop/pdf/PDFXMode.java b/src/java/org/apache/fop/pdf/PDFXMode.java index 03813273b..be0312891 100644 --- a/src/java/org/apache/fop/pdf/PDFXMode.java +++ b/src/java/org/apache/fop/pdf/PDFXMode.java @@ -20,12 +20,12 @@ package org.apache.fop.pdf; /** Enum class for PDF/X modes. */ -public final class PDFXMode { +public enum PDFXMode { /** PDF/X disabled */ - public static final PDFXMode DISABLED = new PDFXMode("PDF/X disabled"); + DISABLED("PDF/X disabled"), /** PDF/X-3:2003 enabled */ - public static final PDFXMode PDFX_3_2003 = new PDFXMode("PDF/X-3:2003"); + PDFX_3_2003("PDF/X-3:2003"); private String name; @@ -47,7 +47,7 @@ public final class PDFXMode { * @param s the string * @return the PDFAMode enum object (DISABLED will be returned if no match is found) */ - public static PDFXMode valueOf(String s) { + public static PDFXMode getValueOf(String s) { if (PDFX_3_2003.getName().equalsIgnoreCase(s)) { return PDFX_3_2003; } else { diff --git a/src/java/org/apache/fop/render/AbstractConfigurator.java b/src/java/org/apache/fop/render/AbstractConfigurator.java index c3c6733b0..c890d0830 100644 --- a/src/java/org/apache/fop/render/AbstractConfigurator.java +++ b/src/java/org/apache/fop/render/AbstractConfigurator.java @@ -19,9 +19,6 @@ 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; @@ -49,41 +46,6 @@ public abstract class AbstractConfigurator { } /** - * 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 */ diff --git a/src/java/org/apache/fop/render/AbstractRendererConfigurator.java b/src/java/org/apache/fop/render/AbstractRendererConfigurator.java index e1bc10440..799469353 100644 --- a/src/java/org/apache/fop/render/AbstractRendererConfigurator.java +++ b/src/java/org/apache/fop/render/AbstractRendererConfigurator.java @@ -19,49 +19,30 @@ package org.apache.fop.render; -import org.apache.avalon.framework.configuration.Configuration; - 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 extends AbstractConfigurator { +public abstract class AbstractRendererConfigurator { - private static final String TYPE = "renderer"; + /** fop factory configuration */ + protected final FOUserAgent userAgent; /** * Default constructor * @param userAgent user agent */ public AbstractRendererConfigurator(FOUserAgent userAgent) { - super(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) { - return super.getConfig(renderer.getMimeType()); + 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 + * Returns the configurator type + * @return the configurator type */ - protected Configuration getRendererConfig(String mimeType) { - return super.getConfig(mimeType); + public static String getType() { + return "renderer"; } - - /** - * {@inheritDoc} - */ - public String getType() { - return TYPE; - } - } diff --git a/src/java/org/apache/fop/render/AbstractRendererMaker.java b/src/java/org/apache/fop/render/AbstractRendererMaker.java index fadfda94d..b4a281efa 100644 --- a/src/java/org/apache/fop/render/AbstractRendererMaker.java +++ b/src/java/org/apache/fop/render/AbstractRendererMaker.java @@ -19,6 +19,7 @@ package org.apache.fop.render; +import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; /** @@ -50,9 +51,8 @@ public abstract class AbstractRendererMaker { * @param userAgent user agent * @return a config object that can be used to configure the renderer */ - public RendererConfigurator getConfigurator(FOUserAgent userAgent) { - return null; - } + public abstract void configureRenderer(FOUserAgent userAgent, Renderer renderer) + throws FOPException; /** * Indicates whether a specific MIME type is supported by this renderer. diff --git a/src/java/org/apache/fop/render/PrintRenderer.java b/src/java/org/apache/fop/render/PrintRenderer.java index 96a62cb11..6d1eda905 100644 --- a/src/java/org/apache/fop/render/PrintRenderer.java +++ b/src/java/org/apache/fop/render/PrintRenderer.java @@ -36,10 +36,11 @@ import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontCollection; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontManager; -import org.apache.fop.fonts.FontResolver; import org.apache.fop.fonts.FontTriplet; import org.apache.fop.fonts.base14.Base14FontCollection; +import sun.font.FontResolver; + /** Abstract base class of "Print" type renderers. */ public abstract class PrintRenderer extends AbstractRenderer { @@ -88,11 +89,11 @@ public abstract class PrintRenderer extends AbstractRenderer { /** {@inheritDoc} */ public void setupFontInfo(FontInfo inFontInfo) throws FOPException { this.fontInfo = inFontInfo; - FontManager fontManager = userAgent.getFactory().getFontManager(); + FontManager fontManager = userAgent.getFontManager(); FontCollection[] fontCollections = new FontCollection[] { new Base14FontCollection(fontManager.isBase14KerningEnabled()), - new CustomFontCollection(getFontResolver(), getFontList(), - userAgent.isComplexScriptFeaturesEnabled()) + new CustomFontCollection(fontManager.getURIResolver(), getFontList(), + userAgent.isComplexScriptFeaturesEnabled()) }; fontManager.setup(getFontInfo(), fontCollections); } @@ -180,18 +181,6 @@ public abstract class PrintRenderer extends AbstractRenderer { } /** - * Get FontResolver - * - * @return FontResolver - */ - public FontResolver getFontResolver() { - if (this.fontResolver == null) { - this.fontResolver = new DefaultFontResolver(super.userAgent); - } - return this.fontResolver; - } - - /** * @return the font info */ public FontInfo getFontInfo() { diff --git a/src/java/org/apache/fop/render/PrintRendererConfigurator.java b/src/java/org/apache/fop/render/PrintRendererConfigurator.java index 93678b4f8..aa19b3a3d 100644 --- a/src/java/org/apache/fop/render/PrintRendererConfigurator.java +++ b/src/java/org/apache/fop/render/PrintRendererConfigurator.java @@ -19,46 +19,74 @@ package org.apache.fop.render; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import org.apache.avalon.framework.configuration.Configuration; 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.apps.io.URIResolverWrapper; import org.apache.fop.fonts.CustomFontCollection; +import org.apache.fop.fonts.DefaultFontConfigurator; import org.apache.fop.fonts.EmbedFontInfo; import org.apache.fop.fonts.FontCollection; +import org.apache.fop.fonts.FontConfigurator; 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.base14.Base14FontCollection; +import org.apache.fop.render.RendererConfig.RendererConfigParser; import org.apache.fop.render.intermediate.IFDocumentHandler; import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; /** * Base Print renderer configurator (mostly handles font configuration) */ -public class PrintRendererConfigurator extends AbstractRendererConfigurator - implements RendererConfigurator, IFDocumentHandlerConfigurator { +public abstract class PrintRendererConfigurator extends AbstractRendererConfigurator + implements IFDocumentHandlerConfigurator { /** logger instance */ - protected static final Log log = LogFactory.getLog(PrintRendererConfigurator.class); + private static Log LOG = LogFactory.getLog(PrintRendererConfigurator.class); + + private final RendererConfigParser rendererConfigParser; + + private final FontConfigurator<EmbedFontInfo> fontInfoConfigurator; + + /** + * Default constructor + * @param userAgent user agent + */ + public PrintRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser) { + this(userAgent, rendererConfigParser, + new DefaultFontConfigurator(userAgent.getFontManager(), new FontEventAdapter( + userAgent.getEventBroadcaster()), userAgent.validateUserConfigStrictly())); + } /** * Default constructor * @param userAgent user agent */ - public PrintRendererConfigurator(FOUserAgent userAgent) { + public PrintRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser, + FontConfigurator<EmbedFontInfo> fontInfoConfigurator) { super(userAgent); + this.rendererConfigParser = rendererConfigParser; + this.fontInfoConfigurator = fontInfoConfigurator; } + protected RendererConfig getRendererConfig(IFDocumentHandler documentHandler) throws FOPException { + return getRendererConfig(documentHandler.getMimeType()); + } + + protected RendererConfig getRendererConfig(String mimeType) throws FOPException { + return userAgent.getRendererConfig(mimeType, rendererConfigParser); + } + + protected RendererConfig getRendererConfig(Renderer renderer) throws FOPException { + return getRendererConfig(renderer.getMimeType()); + } + + /** * Builds a list of EmbedFontInfo objects for use with the setup() method. * @@ -66,77 +94,44 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator * @throws FOPException if something's wrong with the config data */ public void configure(Renderer renderer) throws FOPException { - Configuration cfg = getRendererConfig(renderer); - if (cfg == null) { - log.trace("no configuration found for " + renderer); - return; - } - - PrintRenderer printRenderer = (PrintRenderer)renderer; - FontResolver fontResolver = printRenderer.getFontResolver(); - - FontEventListener listener = new FontEventAdapter( - renderer.getUserAgent().getEventBroadcaster()); - List<EmbedFontInfo> embedFontInfoList = buildFontList(cfg, fontResolver, listener); + PrintRenderer printRenderer = (PrintRenderer) renderer; + List<EmbedFontInfo> embedFontInfoList = buildFontList(renderer.getMimeType()); printRenderer.addFontList(embedFontInfoList); } - /** - * Builds the font list from configuration. - * @param cfg the configuration object - * @param fontResolver a font resolver - * @param listener the font event listener - * @return the list of {@link EmbedFontInfo} objects - * @throws FOPException if an error occurs while processing the configuration - */ - protected List<EmbedFontInfo> buildFontList(Configuration cfg, FontResolver fontResolver, - FontEventListener listener) throws FOPException { - FopFactory factory = userAgent.getFactory(); - FontManager fontManager = factory.getFontManager(); - if (fontResolver == null) { - //Ensure that we have minimal font resolution capabilities - fontResolver - = FontManager.createMinimalFontResolver - ( userAgent.isComplexScriptFeaturesEnabled() ); - } - - boolean strict = factory.validateUserConfigStrictly(); - - //Read font configuration - FontInfoConfigurator fontInfoConfigurator - = new FontInfoConfigurator(cfg, fontManager, fontResolver, listener, strict); - List<EmbedFontInfo> fontInfoList = new ArrayList<EmbedFontInfo>(); - fontInfoConfigurator.configure(fontInfoList); - return fontInfoList; - } - - // ---=== IFDocumentHandler configuration ===--- - /** {@inheritDoc} */ public void configure(IFDocumentHandler documentHandler) throws FOPException { //nop } /** {@inheritDoc} */ - public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo) - throws FOPException { - FontManager fontManager = userAgent.getFactory().getFontManager(); - List<FontCollection> fontCollections = new ArrayList<FontCollection>(); - fontCollections.add(new Base14FontCollection(fontManager.isBase14KerningEnabled())); - - Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); - if (cfg != null) { - FontResolver fontResolver = new DefaultFontResolver(userAgent); - FontEventListener listener = new FontEventAdapter( - userAgent.getEventBroadcaster()); - List<EmbedFontInfo> fontList = buildFontList(cfg, fontResolver, listener); - fontCollections.add(new CustomFontCollection(fontResolver, fontList, - userAgent.isComplexScriptFeaturesEnabled())); + public void setupFontInfo(String mimeType, FontInfo fontInfo) throws FOPException { + FontManager fontManager = userAgent.getFontManager(); + List<FontCollection> fontCollections = getDefaultFontCollection(); + fontCollections.add(getCustomFontCollection(fontManager.getURIResolver(), mimeType)); + fontManager.setup(fontInfo, fontCollections.toArray(new FontCollection[fontCollections.size()])); + } + + protected abstract List<FontCollection> getDefaultFontCollection(); + + protected FontCollection getCustomFontCollection(URIResolverWrapper uriResolverWrapper, String mimeType) + throws FOPException { + List<EmbedFontInfo> fontList; + if (rendererConfigParser == null) { + fontList = Collections.<EmbedFontInfo>emptyList(); + } else { + fontList = fontInfoConfigurator.configure(getRendererConfig(mimeType).getFontInfoConfig()); } + return createCollectionFromFontList(uriResolverWrapper, fontList); + } + + protected FontCollection createCollectionFromFontList(URIResolverWrapper uriResolverWrapper, + List<EmbedFontInfo> fontList) { + return new CustomFontCollection(uriResolverWrapper, fontList, + userAgent.isComplexScriptFeaturesEnabled()); + } - fontManager.setup(fontInfo, - (FontCollection[])fontCollections.toArray( - new FontCollection[fontCollections.size()])); - documentHandler.setFontInfo(fontInfo); + private List<EmbedFontInfo> buildFontList(String mimeType) throws FOPException { + return fontInfoConfigurator.configure(getRendererConfig(mimeType).getFontInfoConfig()); } } diff --git a/src/java/org/apache/fop/render/DefaultFontResolver.java b/src/java/org/apache/fop/render/RendererConfig.java index 0642537c4..832f5e83f 100644 --- a/src/java/org/apache/fop/render/DefaultFontResolver.java +++ b/src/java/org/apache/fop/render/RendererConfig.java @@ -19,34 +19,20 @@ package org.apache.fop.render; -import javax.xml.transform.Source; +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.fonts.FontResolver; +import org.apache.fop.fonts.FontConfig; -/** - * Default FontResolver implementation which uses the FOUserAgent to resolve font URIs. - */ -public class DefaultFontResolver implements FontResolver { +public interface RendererConfig { - private FOUserAgent userAgent; + FontConfig getFontInfoConfig(); - /** - * Main constructor. - * @param userAgent the user agent - */ - public DefaultFontResolver(FOUserAgent userAgent) { - this.userAgent = userAgent; - } + public interface RendererConfigParser { - /** {@inheritDoc} */ - public Source resolve(String href) { - return userAgent.resolveURI(href, userAgent.getFactory().getFontManager().getFontBaseURL()); - } + RendererConfig build(FOUserAgent userAgent, Configuration rendererConfiguration) throws FOPException; - /** {@inheritDoc} */ - public boolean isComplexScriptFeaturesEnabled() { - return userAgent.isComplexScriptFeaturesEnabled(); + String getMimeType(); } - } diff --git a/src/java/org/apache/fop/render/RendererConfigurator.java b/src/java/org/apache/fop/render/RendererConfigOptions.java index 6dceeb74d..9a4e73424 100644 --- a/src/java/org/apache/fop/render/RendererConfigurator.java +++ b/src/java/org/apache/fop/render/RendererConfigOptions.java @@ -19,16 +19,6 @@ 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; +public interface RendererConfigOptions { + String getName(); } diff --git a/src/java/org/apache/fop/render/RendererFactory.java b/src/java/org/apache/fop/render/RendererFactory.java index 3ceb27a8e..df5213dad 100644 --- a/src/java/org/apache/fop/render/RendererFactory.java +++ b/src/java/org/apache/fop/render/RendererFactory.java @@ -36,6 +36,7 @@ import org.apache.fop.area.AreaTreeHandler; import org.apache.fop.fo.FOEventHandler; import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker; import org.apache.fop.render.intermediate.EventProducingFilter; +import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFDocumentHandler; import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; import org.apache.fop.render.intermediate.IFRenderer; @@ -52,25 +53,19 @@ public class RendererFactory { private Map eventHandlerMakerMapping = new java.util.HashMap(); private Map documentHandlerMakerMapping = new java.util.HashMap(); - private boolean rendererPreferred = false; + private final boolean rendererPreferred; /** * Main constructor. + * @param rendererPreferred Controls whether a {@link Renderer} is preferred over a + * {@link IFDocumentHandler} if both are available for the same MIME type. True to prefer the + * {@link Renderer}, false to prefer the {@link IFDocumentHandler}. */ - public RendererFactory() { + public RendererFactory(boolean rendererPreferred) { discoverRenderers(); discoverFOEventHandlers(); discoverDocumentHandlers(); - } - - /** - * Controls whether a {@link Renderer} is preferred over a {@link IFDocumentHandler} if - * both are available for the same MIME type. - * @param value true to prefer the {@link Renderer}, - * false to prefer the {@link IFDocumentHandler}. - */ - public void setRendererPreferred(boolean value) { - this.rendererPreferred = value; + this.rendererPreferred = rendererPreferred; } /** @@ -239,7 +234,7 @@ public class RendererFactory { * @param mime the requested output format * @return the requested RendererMaker or null if none is available */ - public AbstractIFDocumentHandlerMaker getDocumentHandlerMaker(String mime) { + private AbstractIFDocumentHandlerMaker getDocumentHandlerMaker(String mime) { AbstractIFDocumentHandlerMaker maker = (AbstractIFDocumentHandlerMaker)documentHandlerMakerMapping.get(mime); return maker; @@ -299,10 +294,7 @@ public class RendererFactory { AbstractRendererMaker maker = getRendererMaker(outputFormat); if (maker != null) { Renderer rend = maker.makeRenderer(userAgent); - RendererConfigurator configurator = maker.getConfigurator(userAgent); - if (configurator != null) { - configurator.configure(rend); - } + maker.configureRenderer(userAgent, rend); return rend; } else { return null; @@ -383,7 +375,10 @@ public class RendererFactory { throw new UnsupportedOperationException( "No IF document handler for the requested format available: " + outputFormat); } - IFDocumentHandler documentHandler = maker.makeIFDocumentHandler(userAgent); + IFDocumentHandler documentHandler = maker.makeIFDocumentHandler(new IFContext(userAgent)); + // TODO: do all the configuration in the makeIfDocumentHandler method, that would beam when + // you ask for a document handler, a configured one is returned to you. Getting it and + // configuring it in two steps doesn't make sense. IFDocumentHandlerConfigurator configurator = documentHandler.getConfigurator(); if (configurator != null) { configurator.configure(documentHandler); @@ -398,15 +393,15 @@ public class RendererFactory { List lst = new java.util.ArrayList(); Iterator iter = this.rendererMakerMapping.keySet().iterator(); while (iter.hasNext()) { - lst.add(((String)iter.next())); + lst.add(iter.next()); } iter = this.eventHandlerMakerMapping.keySet().iterator(); while (iter.hasNext()) { - lst.add(((String)iter.next())); + lst.add(iter.next()); } iter = this.documentHandlerMakerMapping.keySet().iterator(); while (iter.hasNext()) { - lst.add(((String)iter.next())); + lst.add(iter.next()); } Collections.sort(lst); return (String[])lst.toArray(new String[lst.size()]); diff --git a/src/java/org/apache/fop/render/XMLHandlerConfigurator.java b/src/java/org/apache/fop/render/XMLHandlerConfigurator.java index 604fdb672..fbce59a07 100644 --- a/src/java/org/apache/fop/render/XMLHandlerConfigurator.java +++ b/src/java/org/apache/fop/render/XMLHandlerConfigurator.java @@ -83,7 +83,7 @@ public class XMLHandlerConfigurator extends AbstractRendererConfigurator { */ public void configure(RendererContext context, String ns) throws FOPException { //Optional XML handler configuration - Configuration cfg = getRendererConfig(context.getRenderer()); + Configuration cfg = userAgent.getRendererConfiguration(context.getRenderer().getMimeType()); if (cfg != null) { cfg = getHandlerConfig(cfg, ns); if (cfg != null) { diff --git a/src/java/org/apache/fop/render/adobe/AdobeRendererConfigurator.java b/src/java/org/apache/fop/render/adobe/AdobeRendererConfigurator.java new file mode 100644 index 000000000..16a29baf7 --- /dev/null +++ b/src/java/org/apache/fop/render/adobe/AdobeRendererConfigurator.java @@ -0,0 +1,45 @@ +/* + * 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.adobe; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.fonts.FontCollection; +import org.apache.fop.fonts.FontManager; +import org.apache.fop.fonts.base14.Base14FontCollection; +import org.apache.fop.render.PrintRendererConfigurator; +import org.apache.fop.render.RendererConfig.RendererConfigParser; + +public class AdobeRendererConfigurator extends PrintRendererConfigurator { + + public AdobeRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser) { + super(userAgent, rendererConfigParser); + } + + protected List<FontCollection> getDefaultFontCollection() { + FontManager fontManager = userAgent.getFontManager(); + List<FontCollection> fontCollection = new ArrayList<FontCollection>(); + fontCollection.add(new Base14FontCollection(fontManager.isBase14KerningEnabled())); + return fontCollection; + } + +} diff --git a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java index 7823a2ce6..cf40b1c6e 100644 --- a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java +++ b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java @@ -45,6 +45,7 @@ import org.apache.fop.fonts.FontCollection; import org.apache.fop.fonts.FontEventAdapter; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontManager; +import org.apache.fop.render.afp.AFPRendererConfig.AFPRendererConfigParser; import org.apache.fop.render.afp.extensions.AFPElementMapping; import org.apache.fop.render.afp.extensions.AFPIncludeFormMap; import org.apache.fop.render.afp.extensions.AFPInvokeMediumMap; @@ -53,6 +54,8 @@ import org.apache.fop.render.afp.extensions.AFPPageSegmentElement; import org.apache.fop.render.afp.extensions.AFPPageSetup; import org.apache.fop.render.afp.extensions.ExtensionPlacement; import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler; +import org.apache.fop.render.intermediate.IFContext; +import org.apache.fop.render.intermediate.IFDocumentHandler; import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFPainter; @@ -98,7 +101,8 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler /** * Default constructor. */ - public AFPDocumentHandler() { + public AFPDocumentHandler(IFContext context) { + super(context); this.resourceManager = new AFPResourceManager(); this.paintingState = new AFPPaintingState(); this.unitConv = paintingState.getUnitConverter(); @@ -116,13 +120,13 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler /** {@inheritDoc} */ public IFDocumentHandlerConfigurator getConfigurator() { - return new AFPRendererConfigurator(getUserAgent()); + return new AFPRendererConfigurator(getUserAgent(), new AFPRendererConfigParser()); } /** {@inheritDoc} */ @Override public void setDefaultFontInfo(FontInfo fontInfo) { - FontManager fontManager = getUserAgent().getFactory().getFontManager(); + FontManager fontManager = getUserAgent().getFontManager(); FontCollection[] fontCollections = new FontCollection[] { new AFPFontCollection(getUserAgent().getEventBroadcaster(), null) }; @@ -381,7 +385,7 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler } else if (extension instanceof AFPIncludeFormMap) { AFPIncludeFormMap formMap = (AFPIncludeFormMap)extension; ResourceAccessor accessor = new DefaultFOPResourceAccessor( - getUserAgent(), null, null); + getUserAgent().getNewURIResolver()); try { getResourceManager().createIncludedResource(formMap.getName(), formMap.getSrc(), accessor, diff --git a/src/java/org/apache/fop/render/afp/AFPDocumentHandlerMaker.java b/src/java/org/apache/fop/render/afp/AFPDocumentHandlerMaker.java index cbe6d0ca3..f83ede9f7 100644 --- a/src/java/org/apache/fop/render/afp/AFPDocumentHandlerMaker.java +++ b/src/java/org/apache/fop/render/afp/AFPDocumentHandlerMaker.java @@ -19,7 +19,6 @@ package org.apache.fop.render.afp; -import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker; import org.apache.fop.render.intermediate.IFContext; @@ -36,10 +35,8 @@ public class AFPDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { }; /** {@inheritDoc} */ - public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { - AFPDocumentHandler handler = new AFPDocumentHandler(); - handler.setContext(new IFContext(ua)); - return handler; + public IFDocumentHandler makeIFDocumentHandler(IFContext ifContext) { + return new AFPDocumentHandler(ifContext); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/render/afp/AFPFontConfig.java b/src/java/org/apache/fop/render/afp/AFPFontConfig.java new file mode 100644 index 000000000..42c3be54a --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPFontConfig.java @@ -0,0 +1,440 @@ +/* + * 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.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +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.afp.AFPEventProducer; +import org.apache.fop.afp.fonts.AFPFont; +import org.apache.fop.afp.fonts.AFPFontInfo; +import org.apache.fop.afp.fonts.CharacterSet; +import org.apache.fop.afp.fonts.CharacterSetBuilder; +import org.apache.fop.afp.fonts.CharacterSetType; +import org.apache.fop.afp.fonts.DoubleByteFont; +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.io.URIResolverWrapper; +import org.apache.fop.events.EventProducer; +import org.apache.fop.fonts.FontConfig; +import org.apache.fop.fonts.FontManager; +import org.apache.fop.fonts.FontManagerConfigurator; +import org.apache.fop.fonts.FontTriplet; +import org.apache.fop.fonts.FontTriplet.Matcher; +import org.apache.fop.fonts.FontUtil; +import org.apache.fop.fonts.Typeface; + +/** + * The config object for AFP fonts, these differ from the the more generic fonts (TTF and Type1). + */ +public final class AFPFontConfig implements FontConfig { + + private static final Log LOG = LogFactory.getLog(AFPFontConfig.class); + + private final List<AFPFontConfigData> fontsConfig; + + private AFPFontConfig() { + fontsConfig = new ArrayList<AFPFontConfigData>(); + } + + /** + * Returns a list of AFP font configuration data. + * @return the AFP font config data + */ + public List<AFPFontConfigData> getFontConfig() { + return fontsConfig; + } + + /** + * The parser for AFP font data. + */ + static final class AFPFontInfoConfigParser implements FontConfigParser { + + /** {@inheritDoc}} */ + public AFPFontConfig parse(Configuration cfg, FontManager fontManager, boolean strict, + EventProducer eventProducer) throws FOPException { + try { + return new ParserHelper(cfg, fontManager, strict, + (AFPEventProducer) eventProducer).fontConfig; + } catch (ConfigurationException ce) { + throw new FOPException(ce); + } + } + + AFPFontConfig getEmptyConfig() { + return new AFPFontConfig(); + } + } + + private static final class AggregateMatcher implements Matcher { + + private final List<Matcher> matchers; + + private AggregateMatcher(Matcher... matchers) { + this.matchers = new ArrayList<Matcher>(); + for (Matcher matcher : matchers) { + if (matcher != null) { + this.matchers.add(matcher); + } + } + } + + public boolean matches(FontTriplet triplet) { + for (Matcher matcher : matchers) { + if (matcher.matches(triplet)) { + return true; + } + } + return false; + } + + } + + private static final class ParserHelper { + + private static final Log LOG = LogFactory.getLog(ParserHelper.class); + + private final AFPFontConfig fontConfig; + + private final Matcher matcher; + + private ParserHelper(Configuration cfg, FontManager fontManager, boolean strict, + AFPEventProducer eventProducer) throws FOPException, ConfigurationException { + Configuration fonts = cfg.getChild("fonts"); + Matcher localMatcher = null; + Configuration referencedFontsCfg = fonts.getChild("referenced-fonts", false); + if (referencedFontsCfg != null) { + localMatcher = FontManagerConfigurator.createFontsMatcher(referencedFontsCfg, strict); + } + matcher = new AggregateMatcher(fontManager.getReferencedFontsMatcher(), localMatcher); + fontConfig = new AFPFontConfig(); + for (Configuration font : fonts.getChildren("font")) { + buildFont(font, eventProducer); + } + } + + private void buildFont(Configuration fontCfg, AFPEventProducer eventProducer) + throws ConfigurationException { + //FontManager fontManager = this.userAgent.getFontManager(); + Configuration[] triplets = fontCfg.getChildren("font-triplet"); + List<FontTriplet> tripletList = new ArrayList<FontTriplet>(); + if (triplets.length == 0) { + eventProducer.fontConfigMissing(this, "<font-triplet...", fontCfg.getLocation()); + return; + } + for (Configuration triplet : triplets) { + int weight = FontUtil.parseCSS2FontWeight(triplet.getAttribute("weight")); + FontTriplet fontTriplet = new FontTriplet(triplet.getAttribute("name"), + triplet.getAttribute("style"), weight); + tripletList.add(fontTriplet); + } + //build the fonts + Configuration[] config = fontCfg.getChildren("afp-font"); + if (config.length == 0) { + eventProducer.fontConfigMissing(this, "<afp-font...", fontCfg.getLocation()); + return; + } + Configuration afpFontCfg = config[0]; + String uri = afpFontCfg.getAttribute("base-uri", null); + try { + String type = afpFontCfg.getAttribute("type"); + if (type == null) { + eventProducer.fontConfigMissing(this, "type attribute", fontCfg.getLocation()); + return; + } + String codepage = afpFontCfg.getAttribute("codepage"); + if (codepage == null) { + eventProducer.fontConfigMissing(this, "codepage attribute", + fontCfg.getLocation()); + return; + } + String encoding = afpFontCfg.getAttribute("encoding"); + if (encoding == null) { + eventProducer.fontConfigMissing(this, "encoding attribute", + fontCfg.getLocation()); + return; + } + + fontFromType(tripletList, type, codepage, encoding, afpFontCfg, eventProducer, uri); + } catch (ConfigurationException ce) { + eventProducer.invalidConfiguration(this, ce); + } + } + + private void fontFromType(List<FontTriplet> fontTriplets, String type, String codepage, + String encoding, Configuration cfg, AFPEventProducer eventProducer, String embedURI) + throws ConfigurationException { + AFPFontConfigData config = null; + if ("raster".equalsIgnoreCase(type)) { + config = getRasterFont(fontTriplets, type, codepage, encoding, cfg, eventProducer, + embedURI); + } else if ("outline".equalsIgnoreCase(type)) { + config = getOutlineFont(fontTriplets, type, codepage, encoding, cfg, eventProducer, + embedURI); + } else if ("CIDKeyed".equalsIgnoreCase(type)) { + config = getCIDKeyedFont(fontTriplets, type, codepage, encoding, cfg, + eventProducer, + embedURI); + } else { + LOG.error("No or incorrect type attribute: " + type); + } + if (config != null) { + fontConfig.fontsConfig.add(config); + } + } + + private CIDKeyedFontConfig getCIDKeyedFont(List<FontTriplet> fontTriplets, String type, + String codepage, String encoding, Configuration cfg, AFPEventProducer eventProducer, + String uri) throws ConfigurationException { + String characterset = cfg.getAttribute("characterset"); + if (characterset == null) { + eventProducer.fontConfigMissing(this, "characterset attribute", + cfg.getLocation()); + return null; + } + String name = cfg.getAttribute("name", characterset); + CharacterSetType charsetType = cfg.getAttributeAsBoolean("ebcdic-dbcs", false) + ? CharacterSetType.DOUBLE_BYTE_LINE_DATA : CharacterSetType.DOUBLE_BYTE; + return new CIDKeyedFontConfig(fontTriplets, type, codepage, encoding, characterset, + name, charsetType, isEmbbedable(fontTriplets), uri); + } + + private OutlineFontConfig getOutlineFont(List<FontTriplet> fontTriplets, String type, + String codepage, String encoding, Configuration cfg, + AFPEventProducer eventProducer, String uri) throws ConfigurationException { + String characterset = cfg.getAttribute("characterset"); + if (characterset == null) { + eventProducer.fontConfigMissing(this, "characterset attribute", + cfg.getLocation()); + return null; + } + String name = cfg.getAttribute("name", characterset); + String base14 = cfg.getAttribute("base14-font", null); + return new OutlineFontConfig(fontTriplets, type, codepage, encoding, characterset, + name, base14, isEmbbedable(fontTriplets), uri); + } + + private RasterFontConfig getRasterFont(List<FontTriplet> triplets, String type, + String codepage, String encoding, Configuration cfg, + AFPEventProducer eventProducer, String uri) + throws ConfigurationException { + String name = cfg.getAttribute("name", "Unknown"); + // Create a new font object + Configuration[] rasters = cfg.getChildren("afp-raster-font"); + if (rasters.length == 0) { + eventProducer.fontConfigMissing(this, "<afp-raster-font...", + cfg.getLocation()); + return null; + } + List<RasterCharactersetData> charsetData = new ArrayList<RasterCharactersetData>(); + for (Configuration rasterCfg : rasters) { + String characterset = rasterCfg.getAttribute("characterset"); + if (characterset == null) { + eventProducer.fontConfigMissing(this, "characterset attribute", + cfg.getLocation()); + return null; + } + float size = rasterCfg.getAttributeAsFloat("size"); + int sizeMpt = (int) (size * 1000); + String base14 = rasterCfg.getAttribute("base14-font", null); + charsetData.add(new RasterCharactersetData(characterset, sizeMpt, base14)); + } + return new RasterFontConfig(triplets, type, codepage, encoding, null, name, uri, charsetData, + isEmbbedable(triplets)); + } + + private boolean isEmbbedable(List<FontTriplet> triplets) { + for (FontTriplet triplet : triplets) { + if (matcher.matches(triplet)) { + return false; + } + } + return true; + } + + } + + abstract static class AFPFontConfigData { + private final List<FontTriplet> triplets; + private final String codePage; + private final String encoding; + private final String name; + private final boolean embeddable; + private final String uri; + + AFPFontConfigData(List<FontTriplet> triplets, String type, String codePage, + String encoding, String name, boolean embeddable, String uri) { + this.triplets = Collections.unmodifiableList(triplets); + this.codePage = codePage; + this.encoding = encoding; + this.name = name; + this.embeddable = embeddable; + this.uri = uri; + } + + static AFPFontInfo getFontInfo(AFPFont font, AFPFontConfigData config) { + return font != null ? new AFPFontInfo(font, config.triplets) : null; + } + + abstract AFPFontInfo getFontInfo(URIResolverWrapper resolver, AFPEventProducer eventProducer) + throws IOException; + + ResourceAccessor getAccessor(URIResolverWrapper resolver) { + return new DefaultFOPResourceAccessor(resolver, uri); + } + } + + static final class CIDKeyedFontConfig extends AFPFontConfigData { + + private final CharacterSetType charsetType; + + private final String characterset; + + private CIDKeyedFontConfig(List<FontTriplet> triplets, String type, String codePage, + String encoding, String characterset, String name, CharacterSetType charsetType, boolean embeddable, String uri) { + super(triplets, type, codePage, encoding, name, embeddable, uri); + this.characterset = characterset; + this.charsetType = charsetType; + } + + @Override + AFPFontInfo getFontInfo(URIResolverWrapper resolver, AFPEventProducer eventProducer) + throws IOException { + ResourceAccessor accessor = getAccessor(resolver); + CharacterSet characterSet = CharacterSetBuilder.getDoubleByteInstance().buildDBCS( + characterset, super.codePage, super.encoding, charsetType, accessor, eventProducer); + return getFontInfo(new DoubleByteFont(super.codePage, super.embeddable, characterSet), + this); + } + } + + static final class OutlineFontConfig extends AFPFontConfigData { + private final String base14; + private final String characterset; + + private OutlineFontConfig(List<FontTriplet> triplets, String type, String codePage, + String encoding, String characterset, String name, String base14, boolean embeddable, String uri) { + super(triplets, type, codePage, encoding, name, embeddable, uri); + this.characterset = characterset; + this.base14 = base14; + } + + @Override + AFPFontInfo getFontInfo(URIResolverWrapper resolver, AFPEventProducer eventProducer) + throws IOException { + CharacterSet characterSet = null; + if (base14 != null) { + try { + Class<? extends Typeface> clazz = Class.forName( + "org.apache.fop.fonts.base14." + base14).asSubclass(Typeface.class); + try { + Typeface tf = clazz.newInstance(); + characterSet = CharacterSetBuilder.getSingleByteInstance() + .build(characterset, super.codePage, + super.encoding, + tf, eventProducer); + } 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 { + ResourceAccessor accessor = getAccessor(resolver); + characterSet = CharacterSetBuilder.getSingleByteInstance().buildSBCS( + characterset, super.codePage, super.encoding, accessor, eventProducer); + } + return getFontInfo(new OutlineFont(super.name, super.embeddable, characterSet), this); + } + } + + static final class RasterFontConfig extends AFPFontConfigData { + private final List<RasterCharactersetData> charsets; + + private RasterFontConfig(List<FontTriplet> triplets, String type, String codePage, + String encoding, String characterset, String name, String uri, + List<RasterCharactersetData> csetData, boolean embeddable) { + super(triplets, type, codePage, encoding, name, embeddable, uri); + this.charsets = Collections.unmodifiableList(csetData); + } + + @Override + AFPFontInfo getFontInfo(URIResolverWrapper resolver, AFPEventProducer eventProducer) + throws IOException { + RasterFont rasterFont = new RasterFont(super.name, super.embeddable); + for (RasterCharactersetData charset : charsets) { + if (charset.base14 != null) { + try { + Class<? extends Typeface> clazz = Class.forName( + "org.apache.fop.fonts.base14." + charset.base14).asSubclass( + Typeface.class); + try { + Typeface tf = clazz.newInstance(); + rasterFont.addCharacterSet(charset.size, + CharacterSetBuilder.getSingleByteInstance().build( + charset.characterset, super.codePage, super.encoding, + tf, eventProducer)); + } 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 " + charset.characterset + + " could not be found"; + LOG.error(msg); + } + } else { + ResourceAccessor accessor = getAccessor(resolver); + rasterFont.addCharacterSet(charset.size, + CharacterSetBuilder.getSingleByteInstance().buildSBCS(charset.characterset, + super.codePage, super.encoding, accessor, eventProducer)); + } + } + return getFontInfo(rasterFont, this); + } + } + + static final class RasterCharactersetData { + private final String characterset; + private final int size; + private final String base14; + + private RasterCharactersetData(String characterset, int size, String base14) { + this.characterset = characterset; + this.size = size; + this.base14 = base14; + } + } +} diff --git a/src/java/org/apache/fop/render/afp/AFPPainter.java b/src/java/org/apache/fop/render/afp/AFPPainter.java index 8b2f31555..1f60ce440 100644 --- a/src/java/org/apache/fop/render/afp/AFPPainter.java +++ b/src/java/org/apache/fop/render/afp/AFPPainter.java @@ -206,7 +206,7 @@ public class AFPPainter extends AbstractIFPainter { //Do we need to embed an external page segment? if (pageSegment.getURI() != null) { ResourceAccessor accessor = new DefaultFOPResourceAccessor ( - documentHandler.getUserAgent(), null, null); + documentHandler.getUserAgent().getNewURIResolver()); try { URI resourceUri = new URI(pageSegment.getURI()); documentHandler.getResourceManager().createIncludedResourceFromExternal( diff --git a/src/java/org/apache/fop/render/afp/AFPRendererConfig.java b/src/java/org/apache/fop/render/afp/AFPRendererConfig.java new file mode 100644 index 000000000..b7331c5c5 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPRendererConfig.java @@ -0,0 +1,407 @@ +/* + * 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.io.File; +import java.io.IOException; +import java.util.EnumMap; + +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.afp.AFPConstants; +import org.apache.fop.afp.AFPDataObjectInfo; +import org.apache.fop.afp.AFPEventProducer; +import org.apache.fop.afp.AFPResourceLevel; +import org.apache.fop.afp.AFPResourceLevelDefaults; +import org.apache.fop.afp.modca.triplets.MappingOptionTriplet; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.MimeConstants; +import org.apache.fop.fonts.FontManager; +import org.apache.fop.render.RendererConfig; +import org.apache.fop.render.afp.AFPFontConfig.AFPFontInfoConfigParser; +import org.apache.fop.util.LogUtil; + +import static org.apache.fop.render.afp.AFPRendererConfig.ImagesModeOptions.MODE_COLOR; +import static org.apache.fop.render.afp.AFPRendererConfig.ImagesModeOptions.MODE_GRAYSCALE; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.DEFAULT_RESOURCE_LEVELS; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.GOCA; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.GOCA_TEXT; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.IMAGES; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.IMAGES_DITHERING_QUALITY; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.IMAGES_FS45; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.IMAGES_JPEG; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.IMAGES_MAPPING_OPTION; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.IMAGES_MODE; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.IMAGES_NATIVE; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.IMAGES_WRAP_PSEG; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.JPEG_ALLOW_JPEG_EMBEDDING; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.JPEG_BITMAP_ENCODING_QUALITY; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.LINE_WIDTH_CORRECTION; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.RENDERER_RESOLUTION; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.RESOURCE_GROUP_FILE; +import static org.apache.fop.render.afp.AFPRendererConfig.Options.SHADING; + +public final class AFPRendererConfig implements RendererConfig { + + public enum ImagesModeOptions { + + MODE_GRAYSCALE("b+w", "bits-per-pixel"), + MODE_COLOR("color", "cmyk"); + + private final String name; + + private final String modeAttribute; + + private ImagesModeOptions(String name, String modeAttribute) { + this.name = name; + this.modeAttribute = modeAttribute; + } + + public String getName() { + return name; + } + + public String getModeAttribute() { + return modeAttribute; + } + + public static ImagesModeOptions forName(String name) { + for (ImagesModeOptions option : values()) { + if (option.name.equals(name)) { + return option; + } + } + throw new IllegalArgumentException(name); + } + } + + public enum Options { + + DEFAULT_RESOURCE_LEVELS("default-resource-levels", AFPResourceLevelDefaults.class), + IMAGES("images", null), + IMAGES_JPEG("jpeg", null), + IMAGES_DITHERING_QUALITY("dithering-quality", Float.class), + IMAGES_FS45("fs45", Boolean.class), + IMAGES_MAPPING_OPTION("mapping_option", Byte.class), + IMAGES_MODE("mode", Boolean.class), + IMAGES_NATIVE("native", Boolean.class), + IMAGES_WRAP_PSEG("pseg", Boolean.class), + JPEG_ALLOW_JPEG_EMBEDDING("allow-embedding", Boolean.class), + JPEG_BITMAP_ENCODING_QUALITY("bitmap-encoding-quality", Float.class), + RENDERER_RESOLUTION("renderer-resolution", Integer.class), + RESOURCE_GROUP_FILE("resource-group-file", String.class), + SHADING("shading", AFPShadingMode.class), + LINE_WIDTH_CORRECTION("line-width-correction", Float.class), + GOCA("goca", Boolean.class), + GOCA_TEXT("text", Boolean.class); + + private final String name; + + private final Class<?> type; + + private Options(String name, Class<?> type) { + this.name = name; + this.type = type; + } + + public String getName() { + return name; + } + } + + private final EnumMap<Options, Object> params = new EnumMap<Options, Object>(Options.class); + + private final EnumMap<ImagesModeOptions, Object> imageModeParams + = new EnumMap<ImagesModeOptions, Object>(ImagesModeOptions.class); + + private final AFPFontConfig fontConfig; + + private AFPRendererConfig(AFPFontConfig fontConfig) { + this.fontConfig = fontConfig; + } + + public AFPFontConfig getFontInfoConfig() { + return fontConfig; + } + + public Boolean isColorImages() { + return getParam(IMAGES_MODE, Boolean.class); + } + + public Boolean isCmykImagesSupported() { + if (!isColorImages()) { + throw new IllegalStateException(); + } + return Boolean.class.cast(imageModeParams.get(MODE_COLOR)); + } + + public Integer getBitsPerPixel() { + if (isColorImages()) { + throw new IllegalStateException(); + } + return Integer.class.cast(imageModeParams.get(MODE_GRAYSCALE)); + } + + public Float getDitheringQuality() { + return getParam(IMAGES_DITHERING_QUALITY, Float.class); + } + + public Boolean isNativeImagesSupported() { + return getParam(IMAGES_NATIVE, Boolean.class); + } + + public AFPShadingMode getShadingMode() { + return getParam(SHADING, AFPShadingMode.class); + } + + public Integer getResolution() { + return getParam(RENDERER_RESOLUTION, Integer.class); + } + + public String getDefaultResourceGroupFilePath() { + return getParam(RESOURCE_GROUP_FILE, String.class); + } + + public AFPResourceLevelDefaults getResourceLevelDefaults() { + return getParam(DEFAULT_RESOURCE_LEVELS, AFPResourceLevelDefaults.class); + } + + public Boolean isWrapPseg() { + return getParam(IMAGES_WRAP_PSEG, Boolean.class); + } + + public Boolean isFs45() { + return getParam(IMAGES_FS45, Boolean.class); + } + + public Boolean allowJpegEmbedding() { + return getParam(JPEG_ALLOW_JPEG_EMBEDDING, Boolean.class); + } + + public Float getBitmapEncodingQuality() { + return getParam(JPEG_BITMAP_ENCODING_QUALITY, Float.class); + } + + public Float getLineWidthCorrection() { + return getParam(LINE_WIDTH_CORRECTION, Float.class); + } + + public Boolean isGocaEnabled() { + return getParam(GOCA, Boolean.class); + } + + public Boolean isStrokeGocaText() { + return getParam(GOCA_TEXT, Boolean.class); + } + + private <T> T getParam(Options options, Class<T> type) { + assert options.type.equals(type); + return type.cast(params.get(options)); + } + + private <T> void setParam(Options option, T value) { + assert option.type.isInstance(value); + params.put(option, value); + } + + public static final class AFPRendererConfigParser implements RendererConfigParser { + + private static final Log LOG = LogFactory.getLog(AFPRendererConfigParser.class); + + public AFPRendererConfig build(FOUserAgent userAgent, Configuration cfg) throws FOPException { + boolean strict = userAgent != null ? userAgent.validateUserConfigStrictly() : false; + AFPRendererConfig config = null; + AFPEventProducer eventProducer = AFPEventProducer.Provider.get(userAgent.getEventBroadcaster()); + try { + config = new ParserHelper(cfg, userAgent.getFontManager(), strict, eventProducer).config; + } catch (ConfigurationException e) { + LogUtil.handleException(LOG, e, strict); + } + return config; + } + + public String getMimeType() { + return MimeConstants.MIME_AFP; + } + } + + + private static final class ParserHelper { + + private static final Log LOG = LogFactory.getLog(ParserHelper.class); + + private final AFPRendererConfig config; + + private final boolean strict; + + private final Configuration cfg; + + private ParserHelper(Configuration cfg, FontManager fontManager, boolean strict, + AFPEventProducer eventProducer) + throws ConfigurationException, FOPException { + this.cfg = cfg; + this.strict = strict; + if (cfg != null) { + config = new AFPRendererConfig(new AFPFontInfoConfigParser().parse(cfg, + fontManager, strict, eventProducer)); + configure(); + } else { + config = new AFPRendererConfig(new AFPFontInfoConfigParser().getEmptyConfig()); + } + } + + private void configure() throws ConfigurationException, FOPException { + configureImages(); + setParam(SHADING, AFPShadingMode.valueOf( + cfg.getChild(SHADING.getName()).getValue(AFPShadingMode.COLOR.getName()))); + Configuration rendererResolutionCfg = cfg.getChild(RENDERER_RESOLUTION.getName(), false); + setParam(RENDERER_RESOLUTION, rendererResolutionCfg == null ? 240 + : rendererResolutionCfg.getValueAsInteger(240)); + Configuration lineWidthCorrectionCfg = cfg.getChild(LINE_WIDTH_CORRECTION.getName(), + false); + setParam(LINE_WIDTH_CORRECTION, lineWidthCorrectionCfg != null + ? lineWidthCorrectionCfg.getValueAsFloat() + : AFPConstants.LINE_WIDTH_CORRECTION); + Configuration gocaCfg = cfg.getChild(GOCA.getName()); + boolean gocaEnabled = gocaCfg.getAttributeAsBoolean("enabled", true); + setParam(GOCA, gocaEnabled); + String strokeGocaText = gocaCfg.getAttribute(GOCA_TEXT.getName(), "default"); + setParam(GOCA_TEXT, "stroke".equalsIgnoreCase(strokeGocaText) + || "shapes".equalsIgnoreCase(strokeGocaText)); + //TODO remove + createResourceGroupFile(); + createResourceLevel(); + } + + private void setParam(Options option, Object value) { + config.setParam(option, value); + } + + private void configureImages() throws ConfigurationException, FOPException { + Configuration imagesCfg = cfg.getChild(IMAGES.getName()); + ImagesModeOptions imagesMode = ImagesModeOptions.forName(imagesCfg.getAttribute( + IMAGES_MODE.getName(), MODE_GRAYSCALE.getName())); + boolean colorImages = MODE_COLOR == imagesMode; + setParam(IMAGES_MODE, colorImages); + if (colorImages) { + config.imageModeParams.put(MODE_COLOR, imagesCfg + .getAttributeAsBoolean(imagesMode.getModeAttribute(), false)); + } else { + config.imageModeParams.put(MODE_GRAYSCALE, + imagesCfg.getAttributeAsInteger(imagesMode.getModeAttribute(), 8)); + } + String dithering = imagesCfg.getAttribute(Options.IMAGES_DITHERING_QUALITY.getName(), "medium"); + float dq; + if (dithering.startsWith("min")) { + dq = 0.0f; + } else if (dithering.startsWith("max")) { + dq = 1.0f; + } else { + try { + dq = Float.parseFloat(dithering); + } catch (NumberFormatException nfe) { + //Default value + dq = 0.5f; + } + } + setParam(IMAGES_DITHERING_QUALITY, dq); + setParam(IMAGES_NATIVE, imagesCfg.getAttributeAsBoolean(Options.IMAGES_NATIVE.getName(), false)); + setParam(IMAGES_WRAP_PSEG, + imagesCfg.getAttributeAsBoolean(IMAGES_WRAP_PSEG.getName(), false)); + setParam(IMAGES_FS45, imagesCfg.getAttributeAsBoolean(IMAGES_FS45.getName(), false)); + if ("scale-to-fit".equals(imagesCfg.getAttribute(IMAGES_MAPPING_OPTION.getName(), null))) { + setParam(IMAGES_MAPPING_OPTION, MappingOptionTriplet.SCALE_TO_FILL); + } else { + setParam(IMAGES_MAPPING_OPTION, AFPDataObjectInfo.DEFAULT_MAPPING_OPTION); + } + configureJpegImages(imagesCfg); + } + + private void configureJpegImages(Configuration imagesCfg) { + Configuration jpegConfig = imagesCfg.getChild(IMAGES_JPEG.getName()); + float bitmapEncodingQuality = 1.0f; + boolean allowJpegEmbedding = false; + if (jpegConfig != null) { + allowJpegEmbedding = jpegConfig.getAttributeAsBoolean( + JPEG_ALLOW_JPEG_EMBEDDING.getName(), + false); + String bitmapEncodingQualityStr = jpegConfig.getAttribute( + JPEG_BITMAP_ENCODING_QUALITY.getName(), null); + if (bitmapEncodingQualityStr != null) { + try { + bitmapEncodingQuality = Float.parseFloat(bitmapEncodingQualityStr); + } catch (NumberFormatException nfe) { + //ignore and leave the default above + } + } + } + setParam(JPEG_BITMAP_ENCODING_QUALITY, bitmapEncodingQuality); + setParam(JPEG_ALLOW_JPEG_EMBEDDING, allowJpegEmbedding); + } + + private void createResourceGroupFile() throws FOPException { + try { + Configuration resourceGroupFileCfg = cfg.getChild(RESOURCE_GROUP_FILE.getName(), false); + if (resourceGroupFileCfg != null) { + String resourceGroupDest = null; + resourceGroupDest = resourceGroupFileCfg.getValue(); + if (resourceGroupDest != null) { + File resourceGroupFile = new File(resourceGroupDest); + boolean created = resourceGroupFile.createNewFile(); + if (created && resourceGroupFile.canWrite()) { + setParam(RESOURCE_GROUP_FILE, resourceGroupDest); + } else { + LOG.warn("Unable to write to default external resource group file '" + + resourceGroupDest + "'"); + } + } + } + } catch (ConfigurationException e) { + LogUtil.handleException(LOG, e, strict); + } catch (IOException ioe) { + throw new FOPException("Could not create default external resource group file", ioe); + } + } + + private void createResourceLevel() throws FOPException { + Configuration defaultResourceLevelCfg = cfg.getChild(DEFAULT_RESOURCE_LEVELS.getName(), false); + if (defaultResourceLevelCfg != null) { + AFPResourceLevelDefaults defaults = new AFPResourceLevelDefaults(); + String[] types = defaultResourceLevelCfg.getAttributeNames(); + for (int i = 0, c = types.length; i < c; i++) { + String type = types[i]; + try { + String level = defaultResourceLevelCfg.getAttribute(type); + defaults.setDefaultResourceLevel(type, AFPResourceLevel.valueOf(level)); + } catch (IllegalArgumentException iae) { + LogUtil.handleException(LOG, iae, strict); + } catch (ConfigurationException e) { + LogUtil.handleException(LOG, e, strict); + } + } + setParam(DEFAULT_RESOURCE_LEVELS, defaults); + } + } + } +} diff --git a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java index e93d8b6aa..243087d96 100644 --- a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java +++ b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java @@ -19,42 +19,24 @@ package org.apache.fop.render.afp; -import java.io.File; import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; -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.afp.AFPConstants; import org.apache.fop.afp.AFPEventProducer; -import org.apache.fop.afp.AFPResourceLevel; import org.apache.fop.afp.AFPResourceLevelDefaults; -import org.apache.fop.afp.fonts.AFPFont; import org.apache.fop.afp.fonts.AFPFontCollection; import org.apache.fop.afp.fonts.AFPFontInfo; -import org.apache.fop.afp.fonts.CharacterSet; -import org.apache.fop.afp.fonts.CharacterSetBuilder; -import org.apache.fop.afp.fonts.CharacterSetType; -import org.apache.fop.afp.fonts.DoubleByteFont; -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.apps.io.URIResolverWrapper; import org.apache.fop.fonts.FontCollection; -import org.apache.fop.fonts.FontInfo; -import org.apache.fop.fonts.FontManager; -import org.apache.fop.fonts.FontManagerConfigurator; -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.RendererConfig.RendererConfigParser; +import org.apache.fop.render.afp.AFPFontConfig.AFPFontConfigData; import org.apache.fop.render.intermediate.IFDocumentHandler; import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; import org.apache.fop.util.LogUtil; @@ -62,8 +44,9 @@ import org.apache.fop.util.LogUtil; /** * AFP Renderer configurator */ -public class AFPRendererConfigurator extends PrintRendererConfigurator - implements IFDocumentHandlerConfigurator { +public class AFPRendererConfigurator extends PrintRendererConfigurator implements + IFDocumentHandlerConfigurator { + private static Log LOG = LogFactory.getLog(AFPRendererConfigurator.class); private final AFPEventProducer eventProducer; @@ -72,470 +55,105 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator * * @param userAgent user agent */ - public AFPRendererConfigurator(FOUserAgent userAgent) { - super(userAgent); + public AFPRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser) { + super(userAgent, rendererConfigParser); eventProducer = AFPEventProducer.Provider.get(userAgent.getEventBroadcaster()); } - private AFPFontInfo buildFont(Configuration fontCfg, String fontPath) - throws ConfigurationException { - FontManager fontManager = this.userAgent.getFactory().getFontManager(); - Configuration[] triple = fontCfg.getChildren("font-triplet"); - List<FontTriplet> tripletList = new ArrayList<FontTriplet>(); - if (triple.length == 0) { - eventProducer.fontConfigMissing(this, "<font-triplet...", fontCfg.getLocation()); - return null; - } - for (Configuration config : triple) { - int weight = FontUtil.parseCSS2FontWeight(config.getAttribute("weight")); - FontTriplet triplet = new FontTriplet(config.getAttribute("name"), - config.getAttribute("style"), - weight); - tripletList.add(triplet); - } - - //build the fonts - Configuration[] config = fontCfg.getChildren("afp-font"); - if (config.length == 0) { - eventProducer.fontConfigMissing(this, "<afp-font...", fontCfg.getLocation()); - return null; - } - Configuration afpFontCfg = config[0]; - - 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) { - eventProducer.invalidConfiguration(this, e); - return null; - } - } - ResourceAccessor accessor = new DefaultFOPResourceAccessor( - this.userAgent, - fontManager.getFontBaseURL(), - baseURI); - - AFPFont font = null; - try { - String type = afpFontCfg.getAttribute("type"); - if (type == null) { - eventProducer.fontConfigMissing(this, "type attribute", fontCfg.getLocation()); - return null; - } - String codepage = afpFontCfg.getAttribute("codepage"); - if (codepage == null) { - eventProducer.fontConfigMissing(this, "codepage attribute", - fontCfg.getLocation()); - return null; - } - String encoding = afpFontCfg.getAttribute("encoding"); - if (encoding == null) { - eventProducer.fontConfigMissing(this, "encoding attribute", - fontCfg.getLocation()); - return null; - } - - font = fontFromType(type, codepage, encoding, accessor, afpFontCfg); - } catch (ConfigurationException ce) { - eventProducer.invalidConfiguration(this, ce); - } catch (IOException ioe) { - eventProducer.invalidConfiguration(this, ioe); - } catch (IllegalArgumentException iae) { - eventProducer.invalidConfiguration(this, iae); + @Override + public void configure(IFDocumentHandler documentHandler) throws FOPException { + AFPRendererConfig config = (AFPRendererConfig) getRendererConfig(documentHandler); + if (config != null) { + AFPDocumentHandler afpDocumentHandler = (AFPDocumentHandler) documentHandler; + configure(afpDocumentHandler, config); } - - return font != null ? new AFPFontInfo(font, tripletList) : null; } - - /** - * Create the AFPFont based on type and type-dependent configuration. - * - * @param type font type e.g. 'raster', 'outline' - * @param codepage codepage file - * @param encoding character encoding e.g. 'Cp500', 'UnicodeBigUnmarked' - * @param accessor - * @param afpFontCfg - * @return the created AFPFont - * @throws ConfigurationException - */ - private AFPFont fontFromType(String type, String codepage, String encoding, - ResourceAccessor accessor, Configuration afpFontCfg) throws ConfigurationException, - IOException { - - 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) { - eventProducer.fontConfigMissing(this, "<afp-raster-font...", - afpFontCfg.getLocation()); - return null; - } - for (int j = 0; j < rasters.length; j++) { - Configuration rasterCfg = rasters[j]; - - String characterset = rasterCfg.getAttribute("characterset"); - - if (characterset == null) { - eventProducer.fontConfigMissing(this, "characterset attribute", - afpFontCfg.getLocation()); - return null; - } - float size = rasterCfg.getAttributeAsFloat("size"); - int sizeMpt = (int) (size * 1000); - String base14 = rasterCfg.getAttribute("base14-font", null); - - if (base14 != null) { - try { - Class<? extends Typeface> clazz = Class.forName( - "org.apache.fop.fonts.base14." + base14).asSubclass(Typeface.class); - try { - Typeface tf = clazz.newInstance(); - font.addCharacterSet(sizeMpt, - CharacterSetBuilder.getSingleByteInstance() - .build(characterset, codepage, encoding, tf, - eventProducer)); - } 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(sizeMpt, CharacterSetBuilder.getSingleByteInstance() - .buildSBCS(characterset, codepage, encoding, accessor, eventProducer)); - } - } - return font; - - } else if ("outline".equalsIgnoreCase(type)) { - String characterset = afpFontCfg.getAttribute("characterset"); - if (characterset == null) { - eventProducer.fontConfigMissing(this, "characterset attribute", - afpFontCfg.getLocation()); - return null; - } - String name = afpFontCfg.getAttribute("name", characterset); - CharacterSet characterSet = null; - String base14 = afpFontCfg.getAttribute("base14-font", null); - if (base14 != null) { - try { - Class<? extends Typeface> clazz = Class.forName("org.apache.fop.fonts.base14." - + base14).asSubclass(Typeface.class); - try { - Typeface tf = clazz.newInstance(); - characterSet = CharacterSetBuilder.getSingleByteInstance() - .build(characterset, codepage, encoding, tf, eventProducer); - } 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); - } + private void configure(AFPDocumentHandler documentHandler, AFPRendererConfig config) { + Boolean colorImages = config.isColorImages(); + if (colorImages != null) { + documentHandler.setColorImages(colorImages); + if (colorImages) { + documentHandler.setCMYKImagesSupported(config.isCmykImagesSupported()); } else { - characterSet = CharacterSetBuilder.getSingleByteInstance().buildSBCS( - characterset, codepage, encoding, accessor, eventProducer); + documentHandler.setBitsPerPixel(config.getBitsPerPixel()); } - // Return new font object - return new OutlineFont(name, characterSet); - - } else if ("CIDKeyed".equalsIgnoreCase(type)) { - String characterset = afpFontCfg.getAttribute("characterset"); - if (characterset == null) { - eventProducer.fontConfigMissing(this, "characterset attribute", - afpFontCfg.getLocation()); - return null; - } - String name = afpFontCfg.getAttribute("name", characterset); - CharacterSet characterSet = null; - CharacterSetType charsetType = afpFontCfg.getAttributeAsBoolean("ebcdic-dbcs", false) - ? CharacterSetType.DOUBLE_BYTE_LINE_DATA : CharacterSetType.DOUBLE_BYTE; - characterSet = CharacterSetBuilder.getDoubleByteInstance().buildDBCS(characterset, - codepage, encoding, charsetType, accessor, eventProducer); - - // Create a new font object - DoubleByteFont font = new DoubleByteFont(name, characterSet); - return font; - - } else { - log.error("No or incorrect type attribute: " + type); } - - return null; - } - - /** - * Builds a list of AFPFontInfo objects for use with the setup() method. - * - * @param cfg Configuration object - * @param eventProducer for AFP font related events - * @return List the newly created list of fonts - * @throws ConfigurationException if something's wrong with the config data - */ - private List<AFPFontInfo> buildFontListFromConfiguration(Configuration cfg, - AFPEventProducer eventProducer) throws FOPException, ConfigurationException { - - Configuration fonts = cfg.getChild("fonts"); - FontManager fontManager = this.userAgent.getFactory().getFontManager(); - - // General matcher - FontTriplet.Matcher referencedFontsMatcher = fontManager.getReferencedFontsMatcher(); - // Renderer-specific matcher - FontTriplet.Matcher localMatcher = null; - - // Renderer-specific referenced fonts - Configuration referencedFontsCfg = fonts.getChild("referenced-fonts", false); - if (referencedFontsCfg != null) { - localMatcher = FontManagerConfigurator.createFontsMatcher( - referencedFontsCfg, this.userAgent.getFactory().validateUserConfigStrictly()); + if (config.getDitheringQuality() != null) { + documentHandler.setDitheringQuality(config.getDitheringQuality()); } - - List<AFPFontInfo> fontList = new java.util.ArrayList<AFPFontInfo>(); - Configuration[] font = fonts.getChildren("font"); - final String fontPath = null; - for (int i = 0; i < font.length; i++) { - AFPFontInfo afi = buildFont(font[i], fontPath); - if (afi != null) { - if (log.isDebugEnabled()) { - log.debug("Adding font " + afi.getAFPFont().getFontName()); - } - List<FontTriplet> fontTriplets = afi.getFontTriplets(); - for (int j = 0; j < fontTriplets.size(); ++j) { - FontTriplet triplet = fontTriplets.get(j); - if (log.isDebugEnabled()) { - log.debug(" Font triplet " - + triplet.getName() + ", " - + triplet.getStyle() + ", " - + triplet.getWeight()); - } - - if ((referencedFontsMatcher != null && referencedFontsMatcher.matches(triplet)) - || (localMatcher != null && localMatcher.matches(triplet))) { - afi.getAFPFont().setEmbeddable(false); - break; - } - } - - fontList.add(afi); - } + if (config.isNativeImagesSupported() != null) { + documentHandler.setNativeImagesSupported(config.isNativeImagesSupported()); } - return fontList; - } - - /** images are converted to grayscale bitmapped IOCA */ - private static final String IMAGES_MODE_GRAYSCALE = "b+w"; - - /** images are converted to color bitmapped IOCA */ - private static final String IMAGES_MODE_COLOR = "color"; - - /** - * Throws an UnsupportedOperationException. - * - * @param renderer not used - */ - @Override - public void configure(Renderer renderer) { - throw new UnsupportedOperationException(); - } - - private void configure(AFPCustomizable customizable, Configuration cfg) throws FOPException { - - // image information - Configuration imagesCfg = cfg.getChild("images"); - - // default to grayscale images - String imagesMode = imagesCfg.getAttribute("mode", IMAGES_MODE_GRAYSCALE); - if (IMAGES_MODE_COLOR.equals(imagesMode)) { - customizable.setColorImages(true); - - boolean cmyk = imagesCfg.getAttributeAsBoolean("cmyk", false); - customizable.setCMYKImagesSupported(cmyk); - } else { - customizable.setColorImages(false); - // default to 8 bits per pixel - int bitsPerPixel = imagesCfg.getAttributeAsInteger("bits-per-pixel", 8); - customizable.setBitsPerPixel(bitsPerPixel); + if (config.getShadingMode() != null) { + documentHandler.setShadingMode(config.getShadingMode()); } - - String dithering = imagesCfg.getAttribute("dithering-quality", "medium"); - float dq = 0.5f; - if (dithering.startsWith("min")) { - dq = 0.0f; - } else if (dithering.startsWith("max")) { - dq = 1.0f; - } else { - try { - dq = Float.parseFloat(dithering); - } catch (NumberFormatException nfe) { - //ignore and leave the default above - } + if (config.getResolution() != null) { + documentHandler.setResolution(config.getResolution()); } - customizable.setDitheringQuality(dq); - - // native image support - boolean nativeImageSupport = imagesCfg.getAttributeAsBoolean("native", false); - customizable.setNativeImagesSupported(nativeImageSupport); - - Configuration jpegConfig = imagesCfg.getChild("jpeg"); - boolean allowEmbedding = false; - float ieq = 1.0f; - if (jpegConfig != null) { - allowEmbedding = jpegConfig.getAttributeAsBoolean("allow-embedding", false); - String bitmapEncodingQuality = jpegConfig.getAttribute("bitmap-encoding-quality", null); - - if (bitmapEncodingQuality != null) { - try { - ieq = Float.parseFloat(bitmapEncodingQuality); - } catch (NumberFormatException nfe) { - //ignore and leave the default above - } - } + if (config.getDefaultResourceGroupFilePath() != null) { + documentHandler.setDefaultResourceGroupFilePath(config.getDefaultResourceGroupFilePath()); } - customizable.canEmbedJpeg(allowEmbedding); - customizable.setBitmapEncodingQuality(ieq); - - //FS11 and FS45 page segment wrapping - boolean pSeg = imagesCfg.getAttributeAsBoolean("pseg", false); - customizable.setWrapPSeg(pSeg); - - //FS45 image forcing - boolean fs45 = imagesCfg.getAttributeAsBoolean("fs45", false); - customizable.setFS45(fs45); - - // shading (filled rectangles) - Configuration shadingCfg = cfg.getChild("shading"); - AFPShadingMode shadingMode = AFPShadingMode.valueOf( - shadingCfg.getValue(AFPShadingMode.COLOR.getName())); - customizable.setShadingMode(shadingMode); - - // GOCA Support - Configuration gocaCfg = cfg.getChild("goca"); - boolean gocaEnabled = gocaCfg.getAttributeAsBoolean( - "enabled", customizable.isGOCAEnabled()); - customizable.setGOCAEnabled(gocaEnabled); - String gocaText = gocaCfg.getAttribute( - "text", customizable.isStrokeGOCAText() ? "stroke" : "default"); - customizable.setStrokeGOCAText("stroke".equalsIgnoreCase(gocaText) - || "shapes".equalsIgnoreCase(gocaText)); - - // renderer resolution - Configuration rendererResolutionCfg = cfg.getChild("renderer-resolution", false); - if (rendererResolutionCfg != null) { - customizable.setResolution(rendererResolutionCfg.getValueAsInteger(240)); + if (config.isWrapPseg() != null) { + documentHandler.setWrapPSeg(config.isWrapPseg()); } - - // renderer resolution - Configuration lineWidthCorrectionCfg = cfg.getChild("line-width-correction", false); - if (lineWidthCorrectionCfg != null) { - customizable.setLineWidthCorrection(lineWidthCorrectionCfg - .getValueAsFloat(AFPConstants.LINE_WIDTH_CORRECTION)); + if (config.isFs45() != null) { + documentHandler.setFS45(config.isFs45()); } - // a default external resource group file setting - Configuration resourceGroupFileCfg - = cfg.getChild("resource-group-file", false); - if (resourceGroupFileCfg != null) { - String resourceGroupDest = null; - try { - resourceGroupDest = resourceGroupFileCfg.getValue(); - if (resourceGroupDest != null) { - File resourceGroupFile = new File(resourceGroupDest); - boolean created = resourceGroupFile.createNewFile(); - if (created && resourceGroupFile.canWrite()) { - customizable.setDefaultResourceGroupFilePath(resourceGroupDest); - } else { - log.warn("Unable to write to default external resource group file '" - + resourceGroupDest + "'"); - } - } - } catch (ConfigurationException e) { - LogUtil.handleException(log, e, - userAgent.getFactory().validateUserConfigStrictly()); - } catch (IOException ioe) { - throw new FOPException("Could not create default external resource group file" - , ioe); - } + if (config.allowJpegEmbedding() != null) { + documentHandler.canEmbedJpeg(config.allowJpegEmbedding()); } - - Configuration defaultResourceLevelCfg = cfg.getChild("default-resource-levels", false); - if (defaultResourceLevelCfg != null) { - AFPResourceLevelDefaults defaults = new AFPResourceLevelDefaults(); - String[] types = defaultResourceLevelCfg.getAttributeNames(); - for (int i = 0, c = types.length; i < c; i++) { - String type = types[i]; - try { - String level = defaultResourceLevelCfg.getAttribute(type); - defaults.setDefaultResourceLevel(type, AFPResourceLevel.valueOf(level)); - } catch (IllegalArgumentException iae) { - LogUtil.handleException(log, iae, - userAgent.getFactory().validateUserConfigStrictly()); - } catch (ConfigurationException e) { - LogUtil.handleException(log, e, - userAgent.getFactory().validateUserConfigStrictly()); - } - } - customizable.setResourceLevelDefaults(defaults); + if (config.getBitmapEncodingQuality() != null) { + documentHandler.setBitmapEncodingQuality(config.getBitmapEncodingQuality()); + } + if (config.getLineWidthCorrection() != null) { + documentHandler.setLineWidthCorrection(config.getLineWidthCorrection()); + } + if (config.isGocaEnabled() != null) { + documentHandler.setGOCAEnabled(config.isGocaEnabled()); + } + if (config.isStrokeGocaText() != null) { + documentHandler.setStrokeGOCAText(config.isStrokeGocaText()); + } + AFPResourceLevelDefaults resourceLevelDefaults = config.getResourceLevelDefaults(); + if (resourceLevelDefaults != null) { + documentHandler.setResourceLevelDefaults(resourceLevelDefaults); } } - /** {@inheritDoc} */ @Override - public void configure(IFDocumentHandler documentHandler) throws FOPException { - Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); - if (cfg != null) { - AFPDocumentHandler afpDocumentHandler = (AFPDocumentHandler) documentHandler; - configure(afpDocumentHandler, cfg); - } + protected List<FontCollection> getDefaultFontCollection() { + return new ArrayList<FontCollection>(); } - /** {@inheritDoc} */ @Override - public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo) - throws FOPException { - FontManager fontManager = userAgent.getFactory().getFontManager(); - List<AFPFontCollection> fontCollections = new ArrayList<AFPFontCollection>(); - - Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); - if (cfg != null) { + protected FontCollection getCustomFontCollection(URIResolverWrapper uriResolverWrapper, + String mimeType) throws FOPException { + AFPRendererConfig config = (AFPRendererConfig) getRendererConfig(mimeType); + if (config != null) { try { - List<AFPFontInfo> fontList = buildFontListFromConfiguration(cfg, eventProducer); - fontCollections.add(new AFPFontCollection( - userAgent.getEventBroadcaster(), fontList)); - } catch (ConfigurationException e) { + return new AFPFontCollection(userAgent.getEventBroadcaster(), createFontsList( + config.getFontInfoConfig(), mimeType)); + } catch (IOException e) { eventProducer.invalidConfiguration(this, e); - LogUtil.handleException(log, e, - userAgent.getFactory().validateUserConfigStrictly()); + LogUtil.handleException(LOG, e, userAgent.validateUserConfigStrictly()); + } catch (IllegalArgumentException iae) { + eventProducer.invalidConfiguration(this, iae); + LogUtil.handleException(LOG, iae, userAgent.validateUserConfigStrictly()); } - } else { - fontCollections.add(new AFPFontCollection(userAgent.getEventBroadcaster(), null)); } + return new AFPFontCollection(userAgent.getEventBroadcaster(), null); + } - fontManager.setup(fontInfo, - fontCollections.toArray( - new FontCollection[fontCollections.size()])); - documentHandler.setFontInfo(fontInfo); + private List<AFPFontInfo> createFontsList(AFPFontConfig fontConfig, String mimeType) + throws FOPException, IOException { + List<AFPFontInfo> afpFonts = new ArrayList<AFPFontInfo>(); + for (AFPFontConfigData config : fontConfig.getFontConfig()) { + afpFonts.add(config.getFontInfo(userAgent.getFontManager().getURIResolver(), + eventProducer)); + } + return afpFonts; } } diff --git a/src/java/org/apache/fop/render/afp/AFPSVGHandler.java b/src/java/org/apache/fop/render/afp/AFPSVGHandler.java index 48b82bbf3..b73e22d89 100644 --- a/src/java/org/apache/fop/render/afp/AFPSVGHandler.java +++ b/src/java/org/apache/fop/render/afp/AFPSVGHandler.java @@ -195,7 +195,7 @@ public class AFPSVGHandler extends AbstractGenericSVGHandler { * @return a bridge context */ public static BridgeContext createBridgeContext(FOUserAgent userAgent, AFPGraphics2D g2d) { - ImageManager imageManager = userAgent.getFactory().getImageManager(); + ImageManager imageManager = userAgent.getImageManager(); SVGUserAgent svgUserAgent = new SVGUserAgent(userAgent, new AffineTransform()); diff --git a/src/java/org/apache/fop/render/awt/AWTRenderer.java b/src/java/org/apache/fop/render/awt/AWTRenderer.java index 826dde233..0651975fd 100644 --- a/src/java/org/apache/fop/render/awt/AWTRenderer.java +++ b/src/java/org/apache/fop/render/awt/AWTRenderer.java @@ -41,7 +41,7 @@ import org.apache.xmlgraphics.util.UnitConv; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.apps.FopFactoryConfigurator; +import org.apache.fop.apps.FopFactoryConfig; import org.apache.fop.apps.MimeConstants; import org.apache.fop.area.Area; import org.apache.fop.area.PageViewport; @@ -131,13 +131,13 @@ public class AWTRenderer extends Java2DRenderer implements Pageable { pageWidth = (int) Math.round(bounds.getWidth() / 1000f); pageHeight = (int) Math.round(bounds.getHeight() / 1000f); double scaleX = scaleFactor - * (UnitConv.IN2MM / FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION) + * (UnitConv.IN2MM / FopFactoryConfig.DEFAULT_TARGET_RESOLUTION) / userAgent.getTargetPixelUnitToMillimeter(); double scaleY = scaleFactor - * (UnitConv.IN2MM / FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION) + * (UnitConv.IN2MM / FopFactoryConfig.DEFAULT_TARGET_RESOLUTION) / userAgent.getTargetPixelUnitToMillimeter(); if (getPageViewport(pageNum).getForeignAttributes() != null) { - String scale = (String) getPageViewport(pageNum).getForeignAttributes().get( + String scale = getPageViewport(pageNum).getForeignAttributes().get( PageScale.EXT_PAGE_SCALE); Point2D scales = PageScale.getScale(scale); if (scales != null) { diff --git a/src/java/org/apache/fop/render/awt/AWTRendererMaker.java b/src/java/org/apache/fop/render/awt/AWTRendererMaker.java index d65a550d4..5efa49a99 100644 --- a/src/java/org/apache/fop/render/awt/AWTRendererMaker.java +++ b/src/java/org/apache/fop/render/awt/AWTRendererMaker.java @@ -31,20 +31,23 @@ public class AWTRendererMaker extends AbstractRendererMaker { private static final String[] MIMES = new String[] {MimeConstants.MIME_FOP_AWT_PREVIEW}; - - /** {@inheritDoc} */ + @Override public Renderer makeRenderer(FOUserAgent ua) { return new AWTRenderer(ua); } - /** {@inheritDoc} */ + @Override public boolean needsOutputStream() { return false; } - /** {@inheritDoc} */ + @Override public String[] getSupportedMimeTypes() { return MIMES; } + @Override + public void configureRenderer(FOUserAgent userAgent, Renderer renderer) { + // No-Op + } } diff --git a/src/java/org/apache/fop/render/bitmap/AbstractBitmapDocumentHandler.java b/src/java/org/apache/fop/render/bitmap/AbstractBitmapDocumentHandler.java index c98c05a8e..067b19f20 100644 --- a/src/java/org/apache/fop/render/bitmap/AbstractBitmapDocumentHandler.java +++ b/src/java/org/apache/fop/render/bitmap/AbstractBitmapDocumentHandler.java @@ -36,7 +36,7 @@ import org.apache.xmlgraphics.image.writer.ImageWriter; import org.apache.xmlgraphics.image.writer.ImageWriterRegistry; import org.apache.xmlgraphics.image.writer.MultiImageWriter; -import org.apache.fop.apps.FopFactoryConfigurator; +import org.apache.fop.apps.FopFactoryConfig; import org.apache.fop.fonts.FontInfo; import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler; import org.apache.fop.render.intermediate.IFContext; @@ -79,7 +79,14 @@ public abstract class AbstractBitmapDocumentHandler extends AbstractBinaryWritin /** * Default constructor. */ - public AbstractBitmapDocumentHandler() { + public AbstractBitmapDocumentHandler(IFContext context) { + super(context); + //Set target resolution + int dpi = Math.round(context.getUserAgent().getTargetResolution()); + getSettings().getWriterParams().setResolution(dpi); + + Map renderingOptions = getUserAgent().getRendererOptions(); + setTargetBitmapSize((Dimension)renderingOptions.get(TARGET_BITMAP_SIZE)); } /** {@inheritDoc} */ @@ -97,18 +104,6 @@ public abstract class AbstractBitmapDocumentHandler extends AbstractBinaryWritin public abstract String getDefaultExtension(); /** {@inheritDoc} */ - public void setContext(IFContext context) { - super.setContext(context); - - //Set target resolution - int dpi = Math.round(context.getUserAgent().getTargetResolution()); - getSettings().getWriterParams().setResolution(dpi); - - Map renderingOptions = getUserAgent().getRendererOptions(); - setTargetBitmapSize((Dimension)renderingOptions.get(TARGET_BITMAP_SIZE)); - } - - /** {@inheritDoc} */ public abstract IFDocumentHandlerConfigurator getConfigurator(); /** @@ -227,7 +222,7 @@ public abstract class AbstractBitmapDocumentHandler extends AbstractBinaryWritin //Normal case: just scale according to the target resolution scale = scaleFactor * getUserAgent().getTargetResolution() - / FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION; + / FopFactoryConfig.DEFAULT_TARGET_RESOLUTION; bitmapWidth = (int) ((this.currentPageDimensions.width * scale / 1000f) + 0.5f); bitmapHeight = (int) ((this.currentPageDimensions.height * scale / 1000f) + 0.5f); } diff --git a/src/java/org/apache/fop/render/bitmap/BitmapRendererConfig.java b/src/java/org/apache/fop/render/bitmap/BitmapRendererConfig.java new file mode 100644 index 000000000..0efb2b930 --- /dev/null +++ b/src/java/org/apache/fop/render/bitmap/BitmapRendererConfig.java @@ -0,0 +1,172 @@ +/* + * 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.Color; +import java.awt.image.BufferedImage; +import java.util.EnumMap; + +import org.apache.avalon.framework.configuration.Configuration; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.fonts.DefaultFontConfig; +import org.apache.fop.fonts.DefaultFontConfig.DefaultFontConfigParser; +import org.apache.fop.render.RendererConfig; +import org.apache.fop.render.java2d.Java2DRendererConfig; +import org.apache.fop.render.java2d.Java2DRendererConfig.Java2DRendererConfigParser; +import org.apache.fop.util.ColorUtil; + +import static org.apache.fop.render.bitmap.BitmapRendererConfigOptions.ANTI_ALIASING; +import static org.apache.fop.render.bitmap.BitmapRendererConfigOptions.BACKGROUND_COLOR; +import static org.apache.fop.render.bitmap.BitmapRendererConfigOptions.COLOR_MODE; +import static org.apache.fop.render.bitmap.BitmapRendererConfigOptions.JAVA2D_TRANSPARENT_PAGE_BACKGROUND; +import static org.apache.fop.render.bitmap.BitmapRendererConfigOptions.RENDERING_QUALITY; +import static org.apache.fop.render.bitmap.BitmapRendererConfigOptions.RENDERING_QUALITY_ELEMENT; +import static org.apache.fop.render.bitmap.BitmapRendererConfigOptions.RENDERING_SPEED; + +public class BitmapRendererConfig implements RendererConfig { + + private final EnumMap<BitmapRendererConfigOptions, Object> params + = new EnumMap<BitmapRendererConfigOptions, Object>(BitmapRendererConfigOptions.class); + + private final DefaultFontConfig fontConfig; + + BitmapRendererConfig(DefaultFontConfig fontConfig) { + this.fontConfig = fontConfig; + } + + public DefaultFontConfig getFontInfoConfig() { + return fontConfig; + } + + public Color getBackgroundColor() { + return (Color) get(BACKGROUND_COLOR); + } + + public Boolean hasAntiAliasing() { + return (Boolean) get(ANTI_ALIASING); + } + + public Boolean isRenderHighQuality() { + return (Boolean) get(RENDERING_QUALITY); + } + + public Integer getColorMode() { + return (Integer) get(COLOR_MODE); + } + + public boolean hasTransparentBackround() { + Object result = get(JAVA2D_TRANSPARENT_PAGE_BACKGROUND); + return (Boolean) (result != null ? result + : JAVA2D_TRANSPARENT_PAGE_BACKGROUND.getDefaultValue()); + } + + private Object get(BitmapRendererConfigOptions option) { + return params.get(option); + } + + public static class BitmapRendererConfigParser implements RendererConfigParser { + + private final String mimeType; + + public BitmapRendererConfigParser(String mimeType) { + this.mimeType = mimeType; + } + + private void setParam(BitmapRendererConfig config, BitmapRendererConfigOptions option, + Object value) { + config.params.put(option, value != null ? value : option.getDefaultValue()); + } + + protected void build(BitmapRendererConfig config, FOUserAgent userAgent, + Configuration cfg) throws FOPException { + if (cfg != null) { + Java2DRendererConfig j2dConfig = new Java2DRendererConfigParser(null).build( + userAgent, cfg); + Boolean isTransparent = j2dConfig.isPageBackgroundTransparent(); + isTransparent = isTransparent == null + ? (Boolean) JAVA2D_TRANSPARENT_PAGE_BACKGROUND.getDefaultValue() + : isTransparent; + setParam(config, JAVA2D_TRANSPARENT_PAGE_BACKGROUND, isTransparent); + + String background = getValue(cfg, BACKGROUND_COLOR); + if (isTransparent) { + // We don't use setParam here because we want to force a null value + config.params.put(BACKGROUND_COLOR, null); + } else { + setParam(config, BACKGROUND_COLOR, + ColorUtil.parseColorString(userAgent, background)); + } + + setParam(config, BitmapRendererConfigOptions.ANTI_ALIASING, + getChild(cfg, ANTI_ALIASING).getValueAsBoolean( + (Boolean) ANTI_ALIASING.getDefaultValue())); + + String optimization = getValue(cfg, RENDERING_QUALITY_ELEMENT); + setParam(config, RENDERING_QUALITY, + !(BitmapRendererConfigOptions.getValue(optimization) == RENDERING_SPEED)); + + String color = getValue(cfg, COLOR_MODE); + setParam(config, COLOR_MODE, + getBufferedImageIntegerFromColor(BitmapRendererConfigOptions.getValue(color))); + } + } + + public BitmapRendererConfig build(FOUserAgent userAgent, Configuration cfg) + throws FOPException { + BitmapRendererConfig config = new BitmapRendererConfig(new DefaultFontConfigParser() + .parse(cfg, userAgent.validateStrictly())); + build(config, userAgent, cfg); + return config; + } + + private Integer getBufferedImageIntegerFromColor(BitmapRendererConfigOptions option) { + if (option == null) { + return null; + } + switch (option) { + case COLOR_MODE_RGBA: + return BufferedImage.TYPE_INT_ARGB; + case COLOR_MODE_RGB: + return BufferedImage.TYPE_INT_RGB; + case COLOR_MODE_GRAY: + return BufferedImage.TYPE_BYTE_GRAY; + case COLOR_MODE_BINARY: + case COLOR_MODE_BILEVEL: + return BufferedImage.TYPE_BYTE_BINARY; + default: + return null; + } + } + + private Configuration getChild(Configuration cfg, BitmapRendererConfigOptions option) { + return cfg.getChild(option.getName()); + } + + private String getValue(Configuration cfg, BitmapRendererConfigOptions option) { + return cfg.getChild(option.getName()).getValue(null); + } + + public String getMimeType() { + return mimeType; + } + } +} diff --git a/src/java/org/apache/fop/render/bitmap/BitmapRendererConfigOptions.java b/src/java/org/apache/fop/render/bitmap/BitmapRendererConfigOptions.java new file mode 100644 index 000000000..2fe0109c6 --- /dev/null +++ b/src/java/org/apache/fop/render/bitmap/BitmapRendererConfigOptions.java @@ -0,0 +1,69 @@ +/* + * 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.Color; +import java.awt.image.BufferedImage; + +import org.apache.fop.render.RendererConfigOptions; + +public enum BitmapRendererConfigOptions implements RendererConfigOptions { + JAVA2D_TRANSPARENT_PAGE_BACKGROUND("transparent-page-background", false), + BACKGROUND_COLOR("background-color", Color.WHITE), + ANTI_ALIASING("anti-aliasing", true), + RENDERING_QUALITY_ELEMENT("rendering"), + RENDERING_QUALITY("quality", true), + RENDERING_SPEED("speed"), + COLOR_MODE("color-mode", BufferedImage.TYPE_INT_ARGB), + COLOR_MODE_RGBA("rgba"), + COLOR_MODE_RGB("rgb"), + COLOR_MODE_GRAY("gray"), + COLOR_MODE_BINARY("binary"), + COLOR_MODE_BILEVEL("bi-level"); + + private final String name; + private final Object defaultValue; + + private BitmapRendererConfigOptions(String name, Object defaultValue) { + this.name = name; + this.defaultValue = defaultValue; + } + + private BitmapRendererConfigOptions(String name) { + this(name, null); + } + + public String getName() { + return name; + } + + public Object getDefaultValue() { + return defaultValue; + } + + public static BitmapRendererConfigOptions getValue(String str) { + for (BitmapRendererConfigOptions opt : BitmapRendererConfigOptions.values()) { + if (opt.getName().equalsIgnoreCase(str)) { + return opt; + } + } + return null; + } +} diff --git a/src/java/org/apache/fop/render/bitmap/BitmapRendererConfigurator.java b/src/java/org/apache/fop/render/bitmap/BitmapRendererConfigurator.java index 2ca0a172b..efdd88081 100644 --- a/src/java/org/apache/fop/render/bitmap/BitmapRendererConfigurator.java +++ b/src/java/org/apache/fop/render/bitmap/BitmapRendererConfigurator.java @@ -19,123 +19,82 @@ package org.apache.fop.render.bitmap; -import java.awt.image.BufferedImage; +import java.util.ArrayList; import java.util.List; -import org.apache.avalon.framework.configuration.Configuration; - import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; 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.FontManager; -import org.apache.fop.fonts.FontResolver; -import org.apache.fop.render.DefaultFontResolver; +import org.apache.fop.render.RendererConfig.RendererConfigParser; +import org.apache.fop.render.bitmap.BitmapRendererConfig.BitmapRendererConfigParser; import org.apache.fop.render.intermediate.IFDocumentHandler; -import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; import org.apache.fop.render.java2d.Base14FontCollection; -import org.apache.fop.render.java2d.ConfiguredFontCollection; import org.apache.fop.render.java2d.InstalledFontCollection; import org.apache.fop.render.java2d.Java2DFontMetrics; -import org.apache.fop.render.java2d.Java2DRenderer; import org.apache.fop.render.java2d.Java2DRendererConfigurator; -import org.apache.fop.util.ColorUtil; /** * Configurator for bitmap output. */ -public class BitmapRendererConfigurator extends Java2DRendererConfigurator - implements IFDocumentHandlerConfigurator { +public class BitmapRendererConfigurator extends Java2DRendererConfigurator { + + /** + * Default constructor + * @param userAgent user agent + */ + public BitmapRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser) { + super(userAgent, rendererConfigParser); + } /** * Default constructor * @param userAgent user agent */ public BitmapRendererConfigurator(FOUserAgent userAgent) { - super(userAgent); + super(userAgent, null); } // ---=== IFDocumentHandler configuration ===--- /** {@inheritDoc} */ public void configure(IFDocumentHandler documentHandler) throws FOPException { - super.configure(documentHandler); - Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); - if (cfg != null) { - AbstractBitmapDocumentHandler bitmapHandler - = (AbstractBitmapDocumentHandler)documentHandler; - BitmapRenderingSettings settings = bitmapHandler.getSettings(); - - boolean transparent = cfg.getChild( - Java2DRenderer.JAVA2D_TRANSPARENT_PAGE_BACKGROUND).getValueAsBoolean( - settings.hasTransparentPageBackground()); - if (transparent) { - settings.setPageBackgroundColor(null); - } else { - String background = cfg.getChild("background-color").getValue(null); - if (background != null) { - settings.setPageBackgroundColor( - ColorUtil.parseColorString(this.userAgent, background)); - } - } - - boolean antiAliasing = cfg.getChild("anti-aliasing").getValueAsBoolean( - settings.isAntiAliasingEnabled()); - settings.setAntiAliasing(antiAliasing); - - String optimization = cfg.getChild("rendering").getValue(null); - if ("quality".equalsIgnoreCase(optimization)) { - settings.setQualityRendering(true); - } else if ("speed".equalsIgnoreCase(optimization)) { - settings.setQualityRendering(false); - } + AbstractBitmapDocumentHandler bitmapHandler = (AbstractBitmapDocumentHandler) documentHandler; + BitmapRenderingSettings settings = bitmapHandler.getSettings(); + // TODO: magic strings! + configure(documentHandler, settings, new BitmapRendererConfigParser("image/bitmap")); + } - String color = cfg.getChild("color-mode").getValue(null); - if (color != null) { - if ("rgba".equalsIgnoreCase(color)) { - settings.setBufferedImageType(BufferedImage.TYPE_INT_ARGB); - } else if ("rgb".equalsIgnoreCase(color)) { - settings.setBufferedImageType(BufferedImage.TYPE_INT_RGB); - } else if ("gray".equalsIgnoreCase(color)) { - settings.setBufferedImageType(BufferedImage.TYPE_BYTE_GRAY); - } else if ("binary".equalsIgnoreCase(color)) { - settings.setBufferedImageType(BufferedImage.TYPE_BYTE_BINARY); - } else if ("bi-level".equalsIgnoreCase(color)) { - settings.setBufferedImageType(BufferedImage.TYPE_BYTE_BINARY); - } else { - throw new FOPException("Invalid value for color-mode: " + color); - } - } - } + void configure(IFDocumentHandler documentHandler, BitmapRenderingSettings settings, + BitmapRendererConfigParser parser) throws FOPException { + BitmapRendererConfig config = (BitmapRendererConfig) userAgent.getRendererConfig( + documentHandler.getMimeType(), parser); + configure(config, settings); } - /** {@inheritDoc} */ - public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo) + private void configure(BitmapRendererConfig config, BitmapRenderingSettings settings) throws FOPException { - final FontManager fontManager = userAgent.getFactory().getFontManager(); - - final Java2DFontMetrics java2DFontMetrics = new Java2DFontMetrics(); - - final List fontCollections = new java.util.ArrayList(); - fontCollections.add(new Base14FontCollection(java2DFontMetrics)); - fontCollections.add(new InstalledFontCollection(java2DFontMetrics)); - - Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); - if (cfg != null) { - FontResolver fontResolver = new DefaultFontResolver(userAgent); - FontEventListener listener = new FontEventAdapter( - userAgent.getEventBroadcaster()); - List fontList = buildFontList(cfg, fontResolver, listener); - fontCollections.add(new ConfiguredFontCollection(fontResolver, fontList, - userAgent.isComplexScriptFeaturesEnabled())); + if (config.hasTransparentBackround()) { + settings.setPageBackgroundColor(null); + } else if (config.getBackgroundColor() != null) { + settings.setPageBackgroundColor(config.getBackgroundColor()); + } + if (config.hasAntiAliasing() != null) { + settings.setAntiAliasing(config.hasAntiAliasing()); + } + if (config.isRenderHighQuality() != null) { + settings.setQualityRendering(config.isRenderHighQuality()); + } + if (config.getColorMode() != null) { + settings.setBufferedImageType(config.getColorMode()); } - - fontManager.setup(fontInfo, - (FontCollection[])fontCollections.toArray( - new FontCollection[fontCollections.size()])); - documentHandler.setFontInfo(fontInfo); } + @Override + protected List<FontCollection> getDefaultFontCollection() { + final Java2DFontMetrics java2DFontMetrics = new Java2DFontMetrics(); + final List<FontCollection> fontCollection = new ArrayList<FontCollection>(); + fontCollection.add(new Base14FontCollection(java2DFontMetrics)); + fontCollection.add(new InstalledFontCollection(java2DFontMetrics)); + return fontCollection; + } } diff --git a/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java b/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java index 278cd6c48..8c9a68b02 100644 --- a/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java +++ b/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java @@ -19,28 +19,30 @@ package org.apache.fop.render.bitmap; -import java.awt.image.BufferedImage; - import org.apache.xmlgraphics.image.writer.ImageWriterParams; import org.apache.fop.render.java2d.Java2DRenderingSettings; +import static org.apache.fop.render.bitmap.BitmapRendererConfigOptions.ANTI_ALIASING; +import static org.apache.fop.render.bitmap.BitmapRendererConfigOptions.COLOR_MODE; +import static org.apache.fop.render.bitmap.BitmapRendererConfigOptions.RENDERING_QUALITY; + /** * This class holds settings used when rendering to bitmaps. */ -public class BitmapRenderingSettings extends Java2DRenderingSettings implements TIFFConstants { +public class BitmapRenderingSettings extends Java2DRenderingSettings { /** ImageWriter parameters */ private ImageWriterParams writerParams; /** Image Type as parameter for the BufferedImage constructor (see BufferedImage.TYPE_*) */ - private int bufferedImageType = BufferedImage.TYPE_INT_ARGB; + private int bufferedImageType = (Integer) COLOR_MODE.getDefaultValue(); /** true if anti-aliasing is set */ - private boolean antialiasing = true; + private boolean antialiasing = (Boolean) ANTI_ALIASING.getDefaultValue(); /** true if qualityRendering is set */ - private boolean qualityRendering = true; + private boolean qualityRendering = (Boolean) RENDERING_QUALITY.getDefaultValue(); /** * Default constructor. Initializes the settings to their default values. diff --git a/src/java/org/apache/fop/render/bitmap/PNGDocumentHandler.java b/src/java/org/apache/fop/render/bitmap/PNGDocumentHandler.java index 05c44a1a6..77c6c8932 100644 --- a/src/java/org/apache/fop/render/bitmap/PNGDocumentHandler.java +++ b/src/java/org/apache/fop/render/bitmap/PNGDocumentHandler.java @@ -20,6 +20,8 @@ package org.apache.fop.render.bitmap; import org.apache.fop.apps.MimeConstants; +import org.apache.fop.render.intermediate.IFContext; +import org.apache.fop.render.intermediate.IFDocumentHandler; import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; /** @@ -27,6 +29,11 @@ import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; */ public class PNGDocumentHandler extends AbstractBitmapDocumentHandler { + + PNGDocumentHandler(IFContext context) { + super(context); + } + /** {@inheritDoc} */ public String getMimeType() { return MimeConstants.MIME_PNG; @@ -39,6 +46,7 @@ public class PNGDocumentHandler extends AbstractBitmapDocumentHandler { /** {@inheritDoc} */ public IFDocumentHandlerConfigurator getConfigurator() { + // TODO what constructir params? return new BitmapRendererConfigurator(getUserAgent()); } diff --git a/src/java/org/apache/fop/render/bitmap/PNGDocumentHandlerMaker.java b/src/java/org/apache/fop/render/bitmap/PNGDocumentHandlerMaker.java index d5a299528..7f820f71e 100644 --- a/src/java/org/apache/fop/render/bitmap/PNGDocumentHandlerMaker.java +++ b/src/java/org/apache/fop/render/bitmap/PNGDocumentHandlerMaker.java @@ -19,7 +19,6 @@ package org.apache.fop.render.bitmap; -import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker; import org.apache.fop.render.intermediate.IFContext; @@ -33,10 +32,8 @@ public class PNGDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { private static final String[] MIMES = new String[] {MimeConstants.MIME_PNG}; /** {@inheritDoc} */ - public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { - PNGDocumentHandler handler = new PNGDocumentHandler(); - handler.setContext(new IFContext(ua)); - return handler; + public IFDocumentHandler makeIFDocumentHandler(IFContext ifContext) { + return new PNGDocumentHandler(ifContext); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/render/bitmap/PNGRendererMaker.java b/src/java/org/apache/fop/render/bitmap/PNGRendererMaker.java index da19b2986..12bd8aa1e 100644 --- a/src/java/org/apache/fop/render/bitmap/PNGRendererMaker.java +++ b/src/java/org/apache/fop/render/bitmap/PNGRendererMaker.java @@ -19,11 +19,11 @@ package org.apache.fop.render.bitmap; +import org.apache.fop.apps.FOPException; 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; import org.apache.fop.render.java2d.Java2DRendererConfigurator; /** @@ -33,23 +33,23 @@ public class PNGRendererMaker extends AbstractRendererMaker { private static final String[] MIMES = new String[] {MimeConstants.MIME_PNG}; - - /** {@inheritDoc} */ + @Override public Renderer makeRenderer(FOUserAgent ua) { return new PNGRenderer(ua); } - /** {@inheritDoc} */ - public RendererConfigurator getConfigurator(FOUserAgent userAgent) { - return new Java2DRendererConfigurator(userAgent); + @Override + public void configureRenderer(FOUserAgent userAgent, Renderer renderer) throws FOPException { + // TODO what constructir params? + new Java2DRendererConfigurator(userAgent, null).configure(renderer); } - /** {@inheritDoc} */ + @Override public boolean needsOutputStream() { return true; } - /** {@inheritDoc} */ + @Override public String[] getSupportedMimeTypes() { return MIMES; } diff --git a/src/java/org/apache/fop/render/bitmap/TIFFConstants.java b/src/java/org/apache/fop/render/bitmap/TIFFCompressionValues.java index 437cf536a..71649022e 100644 --- a/src/java/org/apache/fop/render/bitmap/TIFFConstants.java +++ b/src/java/org/apache/fop/render/bitmap/TIFFCompressionValues.java @@ -19,31 +19,43 @@ package org.apache.fop.render.bitmap; -import org.apache.fop.apps.MimeConstants; - /** * Constants for TIFF output. */ -public interface TIFFConstants { - - /** The MIME type for tiff-Rendering */ - String MIME_TYPE = MimeConstants.MIME_TIFF; - +public enum TIFFCompressionValues { /** No compression */ - String COMPRESSION_NONE = "NONE"; + NONE("NONE"), /** JPEG compression */ - String COMPRESSION_JPEG = "JPEG"; + JPEG("JPEG"), /** Packbits (RLE) compression */ - String COMPRESSION_PACKBITS = "PackBits"; + PACKBITS("PackBits"), /** Deflate compression */ - String COMPRESSION_DEFLATE = "Deflate"; + DEFLATE("Deflate"), /** LZW compression */ - String COMPRESSION_LZW = "LZW"; + LZW("LZW"), /** ZLib compression */ - String COMPRESSION_ZLIB = "ZLib"; + ZLIB("ZLib"), /** CCITT Group 4 (T.6) compression */ - String COMPRESSION_CCITT_T6 = "CCITT T.6"; //CCITT Group 4 + CCITT_T6("CCITT T.6"), //CCITT Group 4 /** CCITT Group 3 (T.4) compression */ - String COMPRESSION_CCITT_T4 = "CCITT T.4"; //CCITT Group 3 + CCITT_T4("CCITT T.4"); //CCITT Group 3 + + private final String name; + + private TIFFCompressionValues(String name) { + this.name = name; + } + + public String getName() { + return name; + } + public static TIFFCompressionValues getValue(String name) { + for (TIFFCompressionValues tiffConst : TIFFCompressionValues.values()) { + if (tiffConst.name.equalsIgnoreCase(name)) { + return tiffConst; + } + } + return null; + } } diff --git a/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java b/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java index 4b7fa3c2d..eac087d39 100644 --- a/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java +++ b/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java @@ -20,6 +20,9 @@ package org.apache.fop.render.bitmap; import org.apache.fop.apps.MimeConstants; +import org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererConfigParser; +import org.apache.fop.render.intermediate.IFContext; +import org.apache.fop.render.intermediate.IFDocumentHandler; import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; /** @@ -27,11 +30,17 @@ import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; */ public class TIFFDocumentHandler extends AbstractBitmapDocumentHandler { + + TIFFDocumentHandler(IFContext context) { + super(context); + } + /** {@inheritDoc} */ public String getMimeType() { return MimeConstants.MIME_TIFF; } + /** {@inheritDoc} */ public String getDefaultExtension() { return "tif"; @@ -39,7 +48,7 @@ public class TIFFDocumentHandler extends AbstractBitmapDocumentHandler { /** {@inheritDoc} */ public IFDocumentHandlerConfigurator getConfigurator() { - return new TIFFRendererConfigurator(getUserAgent()); + return new TIFFRendererConfigurator(getUserAgent(), new TIFFRendererConfigParser()); } } diff --git a/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandlerMaker.java b/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandlerMaker.java index b14ba3c18..ab8c7306a 100644 --- a/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandlerMaker.java +++ b/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandlerMaker.java @@ -19,7 +19,6 @@ package org.apache.fop.render.bitmap; -import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker; import org.apache.fop.render.intermediate.IFContext; @@ -33,10 +32,8 @@ public class TIFFDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { private static final String[] MIMES = new String[] {MimeConstants.MIME_TIFF}; /** {@inheritDoc} */ - public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { - TIFFDocumentHandler handler = new TIFFDocumentHandler(); - handler.setContext(new IFContext(ua)); - return handler; + public IFDocumentHandler makeIFDocumentHandler(IFContext ifContext) { + return new TIFFDocumentHandler(ifContext); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java b/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java index 3cdcf2cdc..5b75a372c 100644 --- a/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java +++ b/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java @@ -44,8 +44,13 @@ import org.apache.xmlgraphics.image.writer.MultiImageWriter; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.MimeConstants; import org.apache.fop.render.java2d.Java2DRenderer; +import static org.apache.fop.render.bitmap.TIFFCompressionValues.CCITT_T4; +import static org.apache.fop.render.bitmap.TIFFCompressionValues.CCITT_T6; +import static org.apache.fop.render.bitmap.TIFFCompressionValues.PACKBITS; + /** * <p> * This class represents renderer to TIFF (Tagged Image File Format) format. It @@ -67,7 +72,7 @@ import org.apache.fop.render.java2d.Java2DRenderer; * <code>org.apache.fop.render.java2D.Java2DRenderer</code> and just encode * rendering results into TIFF format using Batik's image codec */ -public class TIFFRenderer extends Java2DRenderer implements TIFFConstants { +public class TIFFRenderer extends Java2DRenderer { /** ImageWriter parameters */ private ImageWriterParams writerParams; @@ -79,7 +84,7 @@ public class TIFFRenderer extends Java2DRenderer implements TIFFConstants { /** {@inheritDoc} */ public String getMimeType() { - return MIME_TYPE; + return MimeConstants.MIME_TIFF; } /** @@ -90,7 +95,7 @@ public class TIFFRenderer extends Java2DRenderer implements TIFFConstants { public TIFFRenderer(FOUserAgent userAgent) { super(userAgent); writerParams = new ImageWriterParams(); - writerParams.setCompressionMethod(COMPRESSION_PACKBITS); + writerParams.setCompressionMethod(PACKBITS.getName()); int dpi = Math.round(userAgent.getTargetResolution()); writerParams.setResolution(dpi); @@ -190,8 +195,8 @@ public class TIFFRenderer extends Java2DRenderer implements TIFFConstants { throw new NoSuchElementException(e.getMessage()); } - if (COMPRESSION_CCITT_T4.equalsIgnoreCase(writerParams.getCompressionMethod()) - || COMPRESSION_CCITT_T6.equalsIgnoreCase(writerParams.getCompressionMethod())) { + TIFFCompressionValues compression = TIFFCompressionValues.getValue(writerParams.getCompressionMethod()); + if (compression == CCITT_T4 || compression == CCITT_T6) { return pageImage; } else { //Decorate the image with a packed sample model for encoding by the codec diff --git a/src/java/org/apache/fop/render/bitmap/TIFFRendererConfig.java b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfig.java new file mode 100644 index 000000000..68401d9bc --- /dev/null +++ b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfig.java @@ -0,0 +1,95 @@ +/* + * 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.util.EnumMap; + +import org.apache.avalon.framework.configuration.Configuration; + +import org.apache.xmlgraphics.util.MimeConstants; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.fonts.DefaultFontConfig; +import org.apache.fop.fonts.DefaultFontConfig.DefaultFontConfigParser; +import org.apache.fop.render.RendererConfigOptions; + +public final class TIFFRendererConfig extends BitmapRendererConfig { + + public enum TIFFRendererConfigOptions implements RendererConfigOptions { + COMPRESSION("compression", TIFFCompressionValues.PACKBITS); + + private final String name; + private final Object defaultValue; + + private TIFFRendererConfigOptions(String name, Object defaultValue) { + this.name = name; + this.defaultValue = defaultValue; + } + + public String getName() { + return name; + } + + public Object getDefaultValue() { + return defaultValue; + } + } + + private final EnumMap<TIFFRendererConfigOptions, Object> params + = new EnumMap<TIFFRendererConfigOptions, Object>(TIFFRendererConfigOptions.class); + + private TIFFRendererConfig(DefaultFontConfig fontConfig) { + super(fontConfig); + } + + public TIFFCompressionValues getCompressionType() { + return (TIFFCompressionValues) params.get(TIFFRendererConfigOptions.COMPRESSION); + } + + public static final class TIFFRendererConfigParser extends BitmapRendererConfigParser { + + public TIFFRendererConfigParser() { + super(MimeConstants.MIME_TIFF); + } + + private TIFFRendererConfig config; + + private void setParam(TIFFRendererConfigOptions option, Object value) { + config.params.put(option, value != null ? value : option.getDefaultValue()); + } + + private String getValue(Configuration cfg, TIFFRendererConfigOptions option) { + return cfg.getChild(option.getName()).getValue(null); + } + + public TIFFRendererConfig build(FOUserAgent userAgent, Configuration cfg) throws FOPException { + config = new TIFFRendererConfig(new DefaultFontConfigParser() + .parse(cfg, userAgent.validateStrictly())); + super.build(config, userAgent, cfg); + if (cfg != null) { + setParam(TIFFRendererConfigOptions.COMPRESSION, + TIFFCompressionValues.getValue(getValue(cfg, + TIFFRendererConfigOptions.COMPRESSION))); + } + return config; + } + } +} diff --git a/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java index f78605a15..b10f2a381 100644 --- a/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java +++ b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java @@ -21,24 +21,34 @@ package org.apache.fop.render.bitmap; import java.awt.image.BufferedImage; -import org.apache.avalon.framework.configuration.Configuration; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.xmlgraphics.image.writer.ImageWriterParams; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.render.Renderer; +import org.apache.fop.render.RendererConfig.RendererConfigParser; +import org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererConfigParser; import org.apache.fop.render.intermediate.IFDocumentHandler; +import static org.apache.fop.render.bitmap.TIFFCompressionValues.CCITT_T4; +import static org.apache.fop.render.bitmap.TIFFCompressionValues.CCITT_T6; +import static org.apache.fop.render.bitmap.TIFFCompressionValues.NONE; + /** * TIFF Renderer configurator */ public class TIFFRendererConfigurator extends BitmapRendererConfigurator { + private static final Log LOG = LogFactory.getLog(TIFFRendererConfigurator.class); /** * Default constructor * @param userAgent user agent */ - public TIFFRendererConfigurator(FOUserAgent userAgent) { - super(userAgent); + public TIFFRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser) { + super(userAgent, rendererConfigParser); } /** @@ -49,58 +59,46 @@ public class TIFFRendererConfigurator extends BitmapRendererConfigurator { * {@inheritDoc} */ public void configure(Renderer renderer) throws FOPException { - Configuration cfg = super.getRendererConfig(renderer); - if (cfg != null) { - TIFFRenderer tiffRenderer = (TIFFRenderer)renderer; + final TIFFRendererConfig config = (TIFFRendererConfig) getRendererConfig(renderer); + if (config != null) { + TIFFRenderer tiffRenderer = (TIFFRenderer) renderer; //set compression - String name = cfg.getChild("compression").getValue(TIFFConstants.COMPRESSION_PACKBITS); - //Some compression formats need a special image format: - tiffRenderer.setBufferedImageType(getBufferedImageTypeFor(name)); - if (!"NONE".equalsIgnoreCase(name)) { - tiffRenderer.getWriterParams().setCompressionMethod(name); + tiffRenderer.setBufferedImageType(getCompressionType(config, tiffRenderer.getWriterParams())); + } + super.configure(renderer); + } + + private int getCompressionType(TIFFRendererConfig config, ImageWriterParams writerParms) + throws FOPException { + //Some compression formats need a special image format: + TIFFCompressionValues compression = config.getCompressionType(); + if (compression != null) { + if (compression != NONE) { + writerParms.setCompressionMethod(compression.getName()); } - if (log.isInfoEnabled()) { - log.info("TIFF compression set to " + name); + if (LOG.isInfoEnabled()) { + LOG.info("TIFF compression set to " + compression.getName()); } } - super.configure(renderer); + return getBufferedImageTypeFor(compression); } - /** - * Determines the type value for the BufferedImage to be produced for rendering - * the bitmap image. - * @param compressionName the compression name - * @return a value from the {@link BufferedImage}.TYPE_* constants - */ - private int getBufferedImageTypeFor(String compressionName) { - if (compressionName.equalsIgnoreCase(TIFFConstants.COMPRESSION_CCITT_T6)) { - return BufferedImage.TYPE_BYTE_BINARY; - } else if (compressionName.equalsIgnoreCase(TIFFConstants.COMPRESSION_CCITT_T4)) { + private int getBufferedImageTypeFor(TIFFCompressionValues compressionType) { + if (compressionType == CCITT_T6 || compressionType == CCITT_T4) { return BufferedImage.TYPE_BYTE_BINARY; } else { return BufferedImage.TYPE_INT_ARGB; } } - // ---=== IFDocumentHandler configuration ===--- - /** {@inheritDoc} */ public void configure(IFDocumentHandler documentHandler) throws FOPException { - super.configure(documentHandler); - Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); - if (cfg != null) { - TIFFDocumentHandler tiffHandler = (TIFFDocumentHandler)documentHandler; + final TIFFRendererConfig tiffConfig = (TIFFRendererConfig) getRendererConfig(documentHandler); + if (tiffConfig != null) { + TIFFDocumentHandler tiffHandler = (TIFFDocumentHandler) documentHandler; BitmapRenderingSettings settings = tiffHandler.getSettings(); - //set compression - String name = cfg.getChild("compression").getValue(TIFFConstants.COMPRESSION_PACKBITS); - //Some compression formats need a special image format: - settings.setBufferedImageType(getBufferedImageTypeFor(name)); - if (!"NONE".equalsIgnoreCase(name)) { - settings.getWriterParams().setCompressionMethod(name); - } - if (log.isInfoEnabled()) { - log.info("TIFF compression set to " + name); - } + configure(documentHandler, settings, new TIFFRendererConfigParser()); + settings.setBufferedImageType(getCompressionType(tiffConfig, settings.getWriterParams())); } } diff --git a/src/java/org/apache/fop/render/bitmap/TIFFRendererMaker.java b/src/java/org/apache/fop/render/bitmap/TIFFRendererMaker.java index 852e6ba04..f4cb78285 100644 --- a/src/java/org/apache/fop/render/bitmap/TIFFRendererMaker.java +++ b/src/java/org/apache/fop/render/bitmap/TIFFRendererMaker.java @@ -19,11 +19,12 @@ package org.apache.fop.render.bitmap; +import org.apache.fop.apps.FOPException; 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; +import org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererConfigParser; /** * RendererMaker for the TIFF Renderer. @@ -32,24 +33,24 @@ public class TIFFRendererMaker extends AbstractRendererMaker { private static final String[] MIMES = new String[] {MimeConstants.MIME_TIFF}; - /** {@inheritDoc} */ + @Override public Renderer makeRenderer(FOUserAgent userAgent) { return new TIFFRenderer(userAgent); } - /** {@inheritDoc} */ - public RendererConfigurator getConfigurator(FOUserAgent userAgent) { - return new TIFFRendererConfigurator(userAgent); - } - - /** {@inheritDoc} */ + @Override public boolean needsOutputStream() { return true; } - /** {@inheritDoc} */ + @Override public String[] getSupportedMimeTypes() { return MIMES; } + @Override + public void configureRenderer(FOUserAgent userAgent, Renderer renderer) throws FOPException { + new TIFFRendererConfigurator(userAgent, new TIFFRendererConfigParser()).configure(renderer); + } + } diff --git a/src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFDocumentHandler.java b/src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFDocumentHandler.java index cc5406acf..0a5324384 100644 --- a/src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFDocumentHandler.java +++ b/src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFDocumentHandler.java @@ -49,6 +49,10 @@ public abstract class AbstractBinaryWritingIFDocumentHandler extends AbstractIFD /** Font configuration */ protected FontInfo fontInfo; + public AbstractBinaryWritingIFDocumentHandler(IFContext ifContext) { + super(ifContext); + } + /** {@inheritDoc} */ public void setResult(Result result) throws IFException { if (result instanceof StreamResult) { @@ -95,7 +99,7 @@ public abstract class AbstractBinaryWritingIFDocumentHandler extends AbstractIFD /** {@inheritDoc} */ public void setDefaultFontInfo(FontInfo fontInfo) { - FontManager fontManager = getUserAgent().getFactory().getFontManager(); + FontManager fontManager = getUserAgent().getFontManager(); FontCollection[] fontCollections = new FontCollection[] { new Base14FontCollection(fontManager.isBase14KerningEnabled()) }; diff --git a/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java b/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java index 2b90e4a7b..72ff9a1ac 100644 --- a/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java +++ b/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java @@ -21,6 +21,9 @@ package org.apache.fop.render.intermediate; import java.util.Locale; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import org.apache.fop.accessibility.DummyStructureTreeEventHandler; import org.apache.fop.accessibility.StructureTreeEventHandler; import org.apache.fop.apps.FOUserAgent; @@ -30,19 +33,19 @@ import org.apache.fop.apps.FOUserAgent; */ public abstract class AbstractIFDocumentHandler implements IFDocumentHandler { - private IFContext ifContext; + /** logging instance */ + private static Log log = LogFactory.getLog(AbstractIFDocumentHandler.class); + + private final IFContext ifContext; /** * Default constructor. */ - public AbstractIFDocumentHandler() { - } - - /** {@inheritDoc} */ - public void setContext(IFContext context) { + protected AbstractIFDocumentHandler(IFContext context) { this.ifContext = context; } + /** {@inheritDoc} */ public IFContext getContext() { return this.ifContext; diff --git a/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandlerMaker.java b/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandlerMaker.java index 204faad00..610f522c2 100644 --- a/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandlerMaker.java +++ b/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandlerMaker.java @@ -19,7 +19,6 @@ package org.apache.fop.render.intermediate; -import org.apache.fop.apps.FOUserAgent; /** * Base class for factory classes which instantiate {@link IFDocumentHandler}s and provide @@ -29,10 +28,10 @@ public abstract class AbstractIFDocumentHandlerMaker { /** * Instantiates a new {@link IFDocumentHandler}. - * @param userAgent the user agent + * @param ifContext the user agent * @return the newly instantiated document handler */ - public abstract IFDocumentHandler makeIFDocumentHandler(FOUserAgent userAgent); + public abstract IFDocumentHandler makeIFDocumentHandler(IFContext ifContext); /** * @return Indicates whether this document handler requires an OutputStream to work with. diff --git a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java index c696e552d..e86cc435f 100644 --- a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java +++ b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java @@ -45,7 +45,6 @@ import org.apache.xmlgraphics.image.loader.util.ImageUtil; import org.apache.fop.ResourceEventProducer; import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.apps.FopFactory; import org.apache.fop.fo.Constants; import org.apache.fop.render.ImageHandler; import org.apache.fop.render.ImageHandlerRegistry; @@ -89,14 +88,6 @@ public abstract class AbstractIFPainter implements IFPainter { return getContext().getUserAgent(); } - /** - * Returns the FOP factory. - * @return the FOP factory. - */ - protected FopFactory getFopFactory() { - return getUserAgent().getFactory(); - } - private AffineTransform combine(AffineTransform[] transforms) { AffineTransform at = new AffineTransform(); for (int i = 0, c = transforms.length; i < c; i++) { @@ -131,9 +122,9 @@ public abstract class AbstractIFPainter implements IFPainter { */ protected void drawImageUsingImageHandler(ImageInfo info, Rectangle rect) throws ImageException, IOException { - ImageManager manager = getFopFactory().getImageManager(); + ImageManager manager = getUserAgent().getImageManager(); ImageSessionContext sessionContext = getUserAgent().getImageSessionContext(); - ImageHandlerRegistry imageHandlerRegistry = getFopFactory().getImageHandlerRegistry(); + ImageHandlerRegistry imageHandlerRegistry = getUserAgent().getImageHandlerRegistry(); //Load and convert the image to a supported format RenderingContext context = createRenderingContext(); @@ -197,8 +188,8 @@ public abstract class AbstractIFPainter implements IFPainter { protected void drawImage(Image image, Rectangle rect, RenderingContext context, boolean convert, Map additionalHints) throws IOException, ImageException { - ImageManager manager = getFopFactory().getImageManager(); - ImageHandlerRegistry imageHandlerRegistry = getFopFactory().getImageHandlerRegistry(); + ImageManager manager = getUserAgent().getImageManager(); + ImageHandlerRegistry imageHandlerRegistry = getUserAgent().getImageHandlerRegistry(); Image effImage; context.putHints(additionalHints); @@ -236,7 +227,7 @@ public abstract class AbstractIFPainter implements IFPainter { * @return the ImageInfo instance or null if there has been an error. */ protected ImageInfo getImageInfo(String uri) { - ImageManager manager = getFopFactory().getImageManager(); + ImageManager manager = getUserAgent().getImageManager(); try { ImageSessionContext sessionContext = getUserAgent().getImageSessionContext(); return manager.getImageInfo(uri, sessionContext); @@ -262,7 +253,7 @@ public abstract class AbstractIFPainter implements IFPainter { * @param rect the rectangle in which to paint the image */ protected void drawImageUsingURI(String uri, Rectangle rect) { - ImageManager manager = getFopFactory().getImageManager(); + ImageManager manager = getUserAgent().getImageManager(); ImageInfo info = null; try { ImageSessionContext sessionContext = getUserAgent().getImageSessionContext(); @@ -290,7 +281,7 @@ public abstract class AbstractIFPainter implements IFPainter { * @param rect the rectangle in which to paint the image */ protected void drawImageUsingDocument(Document doc, Rectangle rect) { - ImageManager manager = getFopFactory().getImageManager(); + ImageManager manager = getUserAgent().getImageManager(); ImageInfo info = null; try { info = manager.preloadImage(null, new DOMSource(doc)); diff --git a/src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFDocumentHandler.java b/src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFDocumentHandler.java index be65e1317..fcf8554a6 100644 --- a/src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFDocumentHandler.java +++ b/src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFDocumentHandler.java @@ -45,6 +45,10 @@ public abstract class AbstractXMLWritingIFDocumentHandler extends AbstractIFDocu /** Main SAX ContentHandler to receive the generated SAX events. */ protected GenerationHelperContentHandler handler; + protected AbstractXMLWritingIFDocumentHandler(IFContext context) { + super(context); + } + /** {@inheritDoc} */ public void setResult(Result result) throws IFException { if (result instanceof SAXResult) { diff --git a/src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java b/src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java index 6cb8f2795..5342f09aa 100644 --- a/src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java +++ b/src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java @@ -78,12 +78,6 @@ import org.apache.fop.fonts.FontInfo; public interface IFDocumentHandler { /** - * Sets the intermediate format context object. - * @param context the context object - */ - void setContext(IFContext context); - - /** * Returns the associated intermediate format context object. * @return the context object */ @@ -274,4 +268,5 @@ public interface IFDocumentHandler { * @throws IFException if an error occurs while handling this event */ void handleExtensionObject(Object extension) throws IFException; + } diff --git a/src/java/org/apache/fop/render/intermediate/IFDocumentHandlerConfigurator.java b/src/java/org/apache/fop/render/intermediate/IFDocumentHandlerConfigurator.java index 3a42918f3..c00ebe29e 100644 --- a/src/java/org/apache/fop/render/intermediate/IFDocumentHandlerConfigurator.java +++ b/src/java/org/apache/fop/render/intermediate/IFDocumentHandlerConfigurator.java @@ -40,6 +40,6 @@ public interface IFDocumentHandlerConfigurator { * @param fontInfo the font info object to set up * @throws FOPException if an error occurs while configuring the object */ - void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo) throws FOPException; + void setupFontInfo(String mimeType, FontInfo fontInfo) throws FOPException; } diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java index 827eec820..d1fa50737 100644 --- a/src/java/org/apache/fop/render/intermediate/IFParser.java +++ b/src/java/org/apache/fop/render/intermediate/IFParser.java @@ -130,7 +130,7 @@ public class IFParser implements IFConstants { public ContentHandler getContentHandler(IFDocumentHandler documentHandler, FOUserAgent userAgent) { ElementMappingRegistry elementMappingRegistry - = userAgent.getFactory().getElementMappingRegistry(); + = userAgent.getElementMappingRegistry(); return new Handler(documentHandler, userAgent, elementMappingRegistry); } @@ -306,7 +306,7 @@ public class IFParser implements IFConstants { delegate.startElement(uri, localName, qName, attributes); } else { ContentHandlerFactoryRegistry registry - = userAgent.getFactory().getContentHandlerFactoryRegistry(); + = userAgent.getContentHandlerFactoryRegistry(); ContentHandlerFactory factory = registry.getFactory(uri); if (factory == null) { DOMImplementation domImplementation diff --git a/src/java/org/apache/fop/render/intermediate/IFRenderer.java b/src/java/org/apache/fop/render/intermediate/IFRenderer.java index e5c1f98c7..57f13ac07 100644 --- a/src/java/org/apache/fop/render/intermediate/IFRenderer.java +++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java @@ -232,9 +232,8 @@ public class IFRenderer extends AbstractPathOrientedRenderer { * @return the default IFDocumentHandler */ protected IFDocumentHandler createDefaultDocumentHandler() { - IFSerializer serializer = new IFSerializer(); FOUserAgent userAgent = getUserAgent(); - serializer.setContext(new IFContext(userAgent)); + IFSerializer serializer = new IFSerializer(new IFContext(userAgent)); if (userAgent.isAccessibilityEnabled()) { userAgent.setStructureTreeEventHandler(serializer.getStructureTreeEventHandler()); } diff --git a/src/java/org/apache/fop/render/intermediate/IFRendererConfig.java b/src/java/org/apache/fop/render/intermediate/IFRendererConfig.java new file mode 100644 index 000000000..27d9d6eaa --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/IFRendererConfig.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.render.intermediate; + +import org.apache.avalon.framework.configuration.Configuration; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.fonts.DefaultFontConfig; +import org.apache.fop.fonts.DefaultFontConfig.DefaultFontConfigParser; +import org.apache.fop.fonts.FontConfig; +import org.apache.fop.render.RendererConfig; + +public final class IFRendererConfig implements RendererConfig { + + private final DefaultFontConfig fontConfig; + + private IFRendererConfig(DefaultFontConfig fontConfig) { + this.fontConfig = fontConfig; + } + + public FontConfig getFontInfoConfig() { + return fontConfig; + } + + public static final class IFRendererConfigParser implements RendererConfigParser { + + public RendererConfig build(FOUserAgent userAgent, Configuration cfg) + throws FOPException { + return new IFRendererConfig(new DefaultFontConfigParser().parse(cfg, + userAgent.validateStrictly())); + } + + public String getMimeType() { + return "application/X-fop-intermediate-format"; + } + } +} diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java index 7114f51e3..3d20440f5 100644 --- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java +++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java @@ -40,8 +40,9 @@ import org.apache.xmlgraphics.util.XMLizable; import org.apache.fop.accessibility.StructureTreeEventHandler; import org.apache.fop.fo.extensions.InternalElementMapping; import org.apache.fop.fonts.FontInfo; -import org.apache.fop.render.PrintRendererConfigurator; import org.apache.fop.render.RenderingContext; +import org.apache.fop.render.adobe.AdobeRendererConfigurator; +import org.apache.fop.render.intermediate.IFRendererConfig.IFRendererConfigParser; import org.apache.fop.render.intermediate.IFStructureTreeBuilder.IFStructureTreeElement; import org.apache.fop.render.intermediate.extensions.AbstractAction; import org.apache.fop.render.intermediate.extensions.Bookmark; @@ -62,7 +63,7 @@ import org.apache.fop.util.XMLUtil; * IFPainter implementation that serializes the intermediate format to XML. */ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler - implements IFConstants, IFPainter, IFDocumentNavigationHandler { +implements IFConstants, IFPainter, IFDocumentNavigationHandler { /** * Intermediate Format (IF) version, used to express an @version attribute @@ -83,6 +84,10 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler private IFStructureTreeBuilder structureTreeBuilder; + public IFSerializer(IFContext context) { + super(context); + } + /** {@inheritDoc} */ @Override protected String getMainNamespace() { @@ -106,7 +111,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler if (this.mimicHandler != null) { return getMimickedDocumentHandler().getConfigurator(); } else { - return new PrintRendererConfigurator(getUserAgent()); + return new AdobeRendererConfigurator(getUserAgent(), new IFRendererConfigParser()); } } @@ -284,7 +289,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler /** {@inheritDoc} */ public void startPage(int index, String name, String pageMasterName, Dimension size) - throws IFException { + throws IFException { try { AttributesImpl atts = new AttributesImpl(); addAttribute(atts, "index", Integer.toString(index)); @@ -386,7 +391,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler } private void startViewport(String transform, Dimension size, Rectangle clipRect) - throws IFException { + throws IFException { try { AttributesImpl atts = new AttributesImpl(); if (transform != null && transform.length() > 0) { @@ -684,7 +689,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler } else { throw new UnsupportedOperationException( "Extension must implement XMLizable: " - + extension + " (" + extension.getClass().getName() + ")"); + + extension + " (" + extension.getClass().getName() + ")"); } } diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializerMaker.java b/src/java/org/apache/fop/render/intermediate/IFSerializerMaker.java index c0060ab8e..fa375fb94 100644 --- a/src/java/org/apache/fop/render/intermediate/IFSerializerMaker.java +++ b/src/java/org/apache/fop/render/intermediate/IFSerializerMaker.java @@ -28,9 +28,9 @@ import org.apache.fop.apps.MimeConstants; public class IFSerializerMaker extends AbstractIFDocumentHandlerMaker { /** {@inheritDoc} */ - public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { - IFSerializer handler = new IFSerializer(); - handler.setContext(new IFContext(ua)); + public IFDocumentHandler makeIFDocumentHandler(IFContext ifContext) { + IFSerializer handler = new IFSerializer(ifContext); + FOUserAgent ua = ifContext.getUserAgent(); if (ua.isAccessibilityEnabled()) { ua.setStructureTreeEventHandler(handler.getStructureTreeEventHandler()); } diff --git a/src/java/org/apache/fop/render/intermediate/IFUtil.java b/src/java/org/apache/fop/render/intermediate/IFUtil.java index e8651a3df..bbf1c2209 100644 --- a/src/java/org/apache/fop/render/intermediate/IFUtil.java +++ b/src/java/org/apache/fop/render/intermediate/IFUtil.java @@ -167,7 +167,8 @@ public final class IFUtil { } IFDocumentHandlerConfigurator configurator = documentHandler.getConfigurator(); if (configurator != null) { - configurator.setupFontInfo(documentHandler, fontInfo); + configurator.setupFontInfo(documentHandler.getMimeType(), fontInfo); + documentHandler.setFontInfo(fontInfo); } else { documentHandler.setDefaultFontInfo(fontInfo); } diff --git a/src/java/org/apache/fop/render/intermediate/util/IFDocumentHandlerProxy.java b/src/java/org/apache/fop/render/intermediate/util/IFDocumentHandlerProxy.java index dde744180..b88e75206 100644 --- a/src/java/org/apache/fop/render/intermediate/util/IFDocumentHandlerProxy.java +++ b/src/java/org/apache/fop/render/intermediate/util/IFDocumentHandlerProxy.java @@ -61,11 +61,6 @@ public class IFDocumentHandlerProxy implements IFDocumentHandler { } /** {@inheritDoc} */ - public void setContext(IFContext context) { - this.delegate.setContext(context); - } - - /** {@inheritDoc} */ public IFContext getContext() { return this.delegate.getContext(); } diff --git a/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java b/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java index 7ac350d5d..de2d85cfb 100644 --- a/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java +++ b/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java @@ -19,21 +19,20 @@ package org.apache.fop.render.java2d; +import java.io.InputStream; +import java.net.URI; import java.util.List; -import javax.xml.transform.Source; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.apps.io.URIResolverWrapper; import org.apache.fop.fonts.CustomFont; import org.apache.fop.fonts.EmbedFontInfo; import org.apache.fop.fonts.EncodingMode; import org.apache.fop.fonts.FontCollection; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontLoader; -import org.apache.fop.fonts.FontManager; -import org.apache.fop.fonts.FontResolver; import org.apache.fop.fonts.FontTriplet; import org.apache.fop.fonts.LazyFont; @@ -44,23 +43,21 @@ public class ConfiguredFontCollection implements FontCollection { private static Log log = LogFactory.getLog(ConfiguredFontCollection.class); - private FontResolver fontResolver; - private List/*<EmbedFontInfo>*/ embedFontInfoList; + private final URIResolverWrapper uriResolver; + private final List<EmbedFontInfo> embedFontInfoList; + private final boolean useComplexScripts; /** * Main constructor - * @param fontResolver a font resolver + * @param uriResolver a font resolver * @param customFonts the list of custom fonts * @param useComplexScriptFeatures true if complex script features enabled */ - public ConfiguredFontCollection(FontResolver fontResolver, - List/*<EmbedFontInfo>*/ customFonts, boolean useComplexScriptFeatures) { - this.fontResolver = fontResolver; - if (this.fontResolver == null) { - //Ensure that we have minimal font resolution capabilities - this.fontResolver = FontManager.createMinimalFontResolver(useComplexScriptFeatures); - } + public ConfiguredFontCollection(URIResolverWrapper uriResolver, + List<EmbedFontInfo> customFonts, boolean useComplexScriptFeatures) { + this.uriResolver = uriResolver; this.embedFontInfoList = customFonts; + this.useComplexScripts = useComplexScriptFeatures; } /** {@inheritDoc} */ @@ -72,42 +69,37 @@ public class ConfiguredFontCollection implements FontCollection { } String internalName = null; - for (int i = 0; i < embedFontInfoList.size(); i++) { - - EmbedFontInfo configFontInfo = (EmbedFontInfo) embedFontInfoList.get(i); - String fontFile = configFontInfo.getEmbedFile(); - internalName = "F" + num; - num++; + for (EmbedFontInfo configFontInfo : embedFontInfoList) { + internalName = "F" + num++; try { + URI fontURI = configFontInfo.getEmbedURI(); FontMetricsMapper font = null; - String metricsUrl = configFontInfo.getMetricsFile(); + URI metricsURI = configFontInfo.getMetricsURI(); // If the user specified an XML-based metrics file, we'll use it // Otherwise, calculate metrics directly from the font file. - if (metricsUrl != null) { - LazyFont fontMetrics = new LazyFont(configFontInfo, fontResolver); - Source fontSource = fontResolver.resolve(configFontInfo.getEmbedFile()); + if (metricsURI != null) { + LazyFont fontMetrics = new LazyFont(configFontInfo, uriResolver, useComplexScripts); + InputStream fontSource = uriResolver.resolveIn(fontURI); font = new CustomFontMetricsMapper(fontMetrics, fontSource); } else { CustomFont fontMetrics = FontLoader.loadFont( - fontFile, null, true, EncodingMode.AUTO, + fontURI, null, true, EncodingMode.AUTO, configFontInfo.getKerning(), - configFontInfo.getAdvanced(), fontResolver); + configFontInfo.getAdvanced(), uriResolver); font = new CustomFontMetricsMapper(fontMetrics); } fontInfo.addMetrics(internalName, font); - List<FontTriplet> triplets = configFontInfo.getFontTriplets(); - for (int c = 0; c < triplets.size(); c++) { - FontTriplet triplet = (FontTriplet) triplets.get(c); - + for (FontTriplet triplet : configFontInfo.getFontTriplets()) { if (log.isDebugEnabled()) { log.debug("Registering: " + triplet + " under " + internalName); } fontInfo.addFontProperties(internalName, triplet); } } catch (Exception e) { - log.warn("Unable to load custom font from file '" + fontFile + "'", e); + log.warn("Unable to load custom font from file '" + configFontInfo.getEmbedURI() + + "'", e); } } return num; diff --git a/src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java b/src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java index 5d964cbbf..a6dea505f 100644 --- a/src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java +++ b/src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java @@ -26,9 +26,6 @@ import java.io.InputStream; import java.util.Map; import java.util.Set; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - import org.apache.fop.fonts.CustomFont; import org.apache.fop.fonts.FontType; import org.apache.fop.fonts.LazyFont; @@ -67,7 +64,7 @@ public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapp public CustomFontMetricsMapper(final CustomFont fontMetrics) throws FontFormatException, IOException { this.typeface = fontMetrics; - initialize(fontMetrics.getEmbedFileSource()); + initialize(fontMetrics.getInputStream()); } /** @@ -78,7 +75,7 @@ public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapp * @throws FontFormatException if a bad font is loaded * @throws IOException if an I/O error occurs */ - public CustomFontMetricsMapper(final LazyFont fontMetrics, final Source fontSource) + public CustomFontMetricsMapper(final LazyFont fontMetrics, final InputStream fontSource) throws FontFormatException, IOException { this.typeface = fontMetrics; initialize(fontSource); @@ -88,29 +85,18 @@ public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapp /** * Loads the java.awt.Font - * @param source + * @param inStream * @throws FontFormatException * @throws IOException */ - private void initialize(final Source source) + private void initialize(final InputStream inStream) throws FontFormatException, IOException { int type = Font.TRUETYPE_FONT; if (FontType.TYPE1.equals(typeface.getFontType())) { type = TYPE1_FONT; //Font.TYPE1_FONT; only available in Java 1.5 } - - InputStream is = null; - if (source instanceof StreamSource) { - is = ((StreamSource) source).getInputStream(); - } else if (source.getSystemId() != null) { - is = new java.net.URL(source.getSystemId()).openStream(); - } else { - throw new IllegalArgumentException("No font source provided."); - } - - this.font = Font.createFont(type, is); - is.close(); - + this.font = Font.createFont(type, inStream); + inStream.close(); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java index 8b60df746..5315c8a9d 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java +++ b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java @@ -58,7 +58,7 @@ import org.apache.xmlgraphics.util.UnitConv; import org.apache.fop.ResourceEventProducer; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.apps.FopFactoryConfigurator; +import org.apache.fop.apps.FopFactoryConfig; import org.apache.fop.area.CTM; import org.apache.fop.area.PageViewport; import org.apache.fop.area.Trait; @@ -73,6 +73,7 @@ import org.apache.fop.fo.Constants; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontCollection; import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontManager; import org.apache.fop.fonts.Typeface; import org.apache.fop.render.AbstractPathOrientedRenderer; import org.apache.fop.render.Graphics2DAdapter; @@ -83,6 +84,8 @@ import org.apache.fop.render.pdf.CTMHelper; import org.apache.fop.util.CharUtilities; import org.apache.fop.util.ColorUtil; +import static org.apache.fop.render.java2d.Java2DRendererOptions.JAVA2D_TRANSPARENT_PAGE_BACKGROUND; + /** * The <code>Java2DRenderer</code> class provides the abstract technical * foundation for all rendering with the Java2D API. Renderers like @@ -109,9 +112,6 @@ import org.apache.fop.util.ColorUtil; */ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implements Printable { - /** Rendering Options key for the controlling the transparent page background option. */ - public static final String JAVA2D_TRANSPARENT_PAGE_BACKGROUND = "transparent-page-background"; - /** The scale factor for the image size, values: ]0 ; 1] */ protected double scaleFactor = 1; @@ -157,7 +157,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem // MH: necessary? the caller has access to FOUserAgent userAgent.setRendererOverride(this); // for document regeneration - String s = (String) userAgent.getRendererOptions().get(JAVA2D_TRANSPARENT_PAGE_BACKGROUND); + String s = (String) userAgent.getRendererOption(JAVA2D_TRANSPARENT_PAGE_BACKGROUND); if (s != null) { this.transparentPageBackground = "true".equalsIgnoreCase(s); } @@ -175,14 +175,15 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem this.fontInfo = inFontInfo; final Java2DFontMetrics java2DFontMetrics = new Java2DFontMetrics(); + FontManager fontManager = userAgent.getFontManager(); + FontCollection[] fontCollections = new FontCollection[] { new Base14FontCollection(java2DFontMetrics), new InstalledFontCollection(java2DFontMetrics), - new ConfiguredFontCollection(getFontResolver(), getFontList(), - userAgent.isComplexScriptFeaturesEnabled()) + new ConfiguredFontCollection(fontManager.getURIResolver(), getFontList(), + userAgent.isComplexScriptFeaturesEnabled()) }; - userAgent.getFactory().getFontManager().setup( - getFontInfo(), fontCollections); + fontManager.setup(getFontInfo(), fontCollections); } /** {@inheritDoc} */ @@ -317,7 +318,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem // set scale factor double scaleX = scaleFactor; double scaleY = scaleFactor; - String scale = (String) currentPageViewport.getForeignAttributes().get( + String scale = currentPageViewport.getForeignAttributes().get( PageScale.EXT_PAGE_SCALE); Point2D scales = PageScale.getScale(scale); if (scales != null) { @@ -326,10 +327,10 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem } scaleX = scaleX - * (UnitConv.IN2MM / FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION) + * (UnitConv.IN2MM / FopFactoryConfig.DEFAULT_TARGET_RESOLUTION) / userAgent.getTargetPixelUnitToMillimeter(); scaleY = scaleY - * (UnitConv.IN2MM / FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION) + * (UnitConv.IN2MM / FopFactoryConfig.DEFAULT_TARGET_RESOLUTION) / userAgent.getTargetPixelUnitToMillimeter(); int bitmapWidth = (int) ((pageWidth * scaleX) + 0.5); int bitmapHeight = (int) ((pageHeight * scaleY) + 0.5); @@ -737,7 +738,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem //super.renderText(text); // rendering text decorations - Typeface tf = (Typeface) fontInfo.getFonts().get(font.getFontName()); + Typeface tf = fontInfo.getFonts().get(font.getFontName()); int fontsize = text.getTraitAsInteger(Trait.FONT_SIZE); renderTextDecoration(tf, fontsize, text, bl, rx); } @@ -918,7 +919,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem int y = currentBPPosition + (int)Math.round(pos.getY()); uri = URISpecification.getURL(uri); - ImageManager manager = getUserAgent().getFactory().getImageManager(); + ImageManager manager = getUserAgent().getImageManager(); ImageInfo info = null; try { ImageSessionContext sessionContext = getUserAgent().getImageSessionContext(); diff --git a/src/java/org/apache/fop/render/java2d/Java2DRendererConfig.java b/src/java/org/apache/fop/render/java2d/Java2DRendererConfig.java new file mode 100644 index 000000000..139d05916 --- /dev/null +++ b/src/java/org/apache/fop/render/java2d/Java2DRendererConfig.java @@ -0,0 +1,75 @@ +/* + * 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 java.util.EnumMap; + +import org.apache.avalon.framework.configuration.Configuration; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.fonts.DefaultFontConfig; +import org.apache.fop.fonts.DefaultFontConfig.DefaultFontConfigParser; +import org.apache.fop.render.RendererConfig; + +import static org.apache.fop.render.java2d.Java2DRendererOptions.JAVA2D_TRANSPARENT_PAGE_BACKGROUND; + +public final class Java2DRendererConfig implements RendererConfig { + + private final EnumMap<Java2DRendererOptions, Object> params + = new EnumMap<Java2DRendererOptions, Object>(Java2DRendererOptions.class); + + private final DefaultFontConfig fontConfig; + + private Java2DRendererConfig(DefaultFontConfig fontConfig) { + this.fontConfig = fontConfig; + } + + public DefaultFontConfig getFontInfoConfig() { + return fontConfig; + } + + public Boolean isPageBackgroundTransparent() { + return Boolean.class.cast(params.get(JAVA2D_TRANSPARENT_PAGE_BACKGROUND)); + } + + public static class Java2DRendererConfigParser implements RendererConfigParser { + + private final String mimeType; + + public Java2DRendererConfigParser(String mimeType) { + this.mimeType = mimeType; + } + + public Java2DRendererConfig build(FOUserAgent userAgent, Configuration cfg) + throws FOPException { + Java2DRendererConfig config = new Java2DRendererConfig(new DefaultFontConfigParser() + .parse(cfg, userAgent.validateStrictly())); + boolean value = cfg.getChild( + JAVA2D_TRANSPARENT_PAGE_BACKGROUND.getName(), true).getValueAsBoolean(false); + config.params.put(JAVA2D_TRANSPARENT_PAGE_BACKGROUND, value); + return config; + } + + public String getMimeType() { + return mimeType; + } + } +} diff --git a/src/java/org/apache/fop/render/java2d/Java2DRendererConfigurator.java b/src/java/org/apache/fop/render/java2d/Java2DRendererConfigurator.java index a12cb3898..6b09ff740 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DRendererConfigurator.java +++ b/src/java/org/apache/fop/render/java2d/Java2DRendererConfigurator.java @@ -19,24 +19,23 @@ 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; +import org.apache.fop.render.RendererConfig.RendererConfigParser; +import org.apache.fop.render.adobe.AdobeRendererConfigurator; /** * Configurerer for Java 2D renderer */ -public class Java2DRendererConfigurator extends PrintRendererConfigurator { +public class Java2DRendererConfigurator extends AdobeRendererConfigurator { /** * Default constructor * @param userAgent user agent */ - public Java2DRendererConfigurator(FOUserAgent userAgent) { - super(userAgent); + public Java2DRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser) { + super(userAgent, rendererConfigParser); } /** @@ -45,15 +44,14 @@ public class Java2DRendererConfigurator extends PrintRendererConfigurator { * @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)); + Java2DRendererConfig config = (Java2DRendererConfig) getRendererConfig(renderer); + if (config != null) { + Java2DRenderer java2dRenderer = (Java2DRenderer) renderer; + // new Java2DRendererConfigParser(renderer.getMimeType())); + if (config.isPageBackgroundTransparent() != null) { + java2dRenderer.setTransparentPageBackground(config.isPageBackgroundTransparent()); } + super.configure(renderer); } - super.configure(renderer); } } diff --git a/src/java/org/apache/fop/render/java2d/Java2DRendererOptions.java b/src/java/org/apache/fop/render/java2d/Java2DRendererOptions.java new file mode 100644 index 000000000..c531aa771 --- /dev/null +++ b/src/java/org/apache/fop/render/java2d/Java2DRendererOptions.java @@ -0,0 +1,37 @@ +/* + * 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.fop.render.RendererConfigOptions; + +public enum Java2DRendererOptions implements RendererConfigOptions { + /** Rendering Options key for the controlling the transparent page background option. */ + JAVA2D_TRANSPARENT_PAGE_BACKGROUND("transparent-page-background"); + + private final String name; + + private Java2DRendererOptions(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/src/java/org/apache/fop/render/java2d/Java2DRenderingSettings.java b/src/java/org/apache/fop/render/java2d/Java2DRenderingSettings.java index f7bad64a7..06ea8a3cf 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DRenderingSettings.java +++ b/src/java/org/apache/fop/render/java2d/Java2DRenderingSettings.java @@ -53,6 +53,4 @@ public class Java2DRenderingSettings { public boolean hasTransparentPageBackground() { return this.pageBackgroundColor == null; } - - } diff --git a/src/java/org/apache/fop/render/java2d/Java2DUtil.java b/src/java/org/apache/fop/render/java2d/Java2DUtil.java index 924460bd8..c17ad2994 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DUtil.java +++ b/src/java/org/apache/fop/render/java2d/Java2DUtil.java @@ -44,7 +44,7 @@ public final class Java2DUtil { FontInfo fontInfo, FOUserAgent userAgent) { Java2DFontMetrics java2DFontMetrics = new Java2DFontMetrics(); - FontManager fontManager = userAgent.getFactory().getFontManager(); + FontManager fontManager = userAgent.getFontManager(); FontCollection[] fontCollections = new FontCollection[] { new org.apache.fop.render.java2d.Base14FontCollection(java2DFontMetrics), new InstalledFontCollection(java2DFontMetrics) diff --git a/src/java/org/apache/fop/render/pcl/PCLDocumentHandler.java b/src/java/org/apache/fop/render/pcl/PCLDocumentHandler.java index 52e522c7a..1cd76e455 100644 --- a/src/java/org/apache/fop/render/pcl/PCLDocumentHandler.java +++ b/src/java/org/apache/fop/render/pcl/PCLDocumentHandler.java @@ -32,18 +32,21 @@ import org.apache.commons.logging.LogFactory; import org.apache.xmlgraphics.util.UnitConv; -import org.apache.fop.apps.FopFactoryConfigurator; +import org.apache.fop.apps.FopFactoryConfig; import org.apache.fop.apps.MimeConstants; import org.apache.fop.fonts.FontInfo; import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler; import org.apache.fop.render.intermediate.IFContext; +import org.apache.fop.render.intermediate.IFDocumentHandler; import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFPainter; import org.apache.fop.render.java2d.Java2DPainter; import org.apache.fop.render.java2d.Java2DUtil; +import org.apache.fop.render.pcl.PCLRendererConfig.PCLRendererConfigParser; import org.apache.fop.render.pcl.extensions.PCLElementMapping; + /** * {@link IFDocumentHandler} implementation that produces PCL 5. */ @@ -73,7 +76,9 @@ public class PCLDocumentHandler extends AbstractBinaryWritingIFDocumentHandler /** * Default constructor. */ - public PCLDocumentHandler() { + public PCLDocumentHandler(IFContext context) { + super(context); + this.pclUtil = new PCLRenderingUtil(context.getUserAgent()); } /** {@inheritDoc} */ @@ -87,15 +92,8 @@ public class PCLDocumentHandler extends AbstractBinaryWritingIFDocumentHandler } /** {@inheritDoc} */ - @Override - public void setContext(IFContext context) { - super.setContext(context); - this.pclUtil = new PCLRenderingUtil(context.getUserAgent()); - } - - /** {@inheritDoc} */ public IFDocumentHandlerConfigurator getConfigurator() { - return new PCLRendererConfigurator(getUserAgent()); + return new PCLRendererConfigurator(getUserAgent(), new PCLRendererConfigParser()); } /** {@inheritDoc} */ @@ -226,7 +224,7 @@ public class PCLDocumentHandler extends AbstractBinaryWritingIFDocumentHandler private IFPainter createAllBitmapPainter() { double scale = gen.getMaximumBitmapResolution() - / FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION; + / FopFactoryConfig.DEFAULT_TARGET_RESOLUTION; Rectangle printArea = this.currentPageDefinition.getLogicalPageRect(); int bitmapWidth = (int)Math.ceil( UnitConv.mpt2px(printArea.width, gen.getMaximumBitmapResolution())); diff --git a/src/java/org/apache/fop/render/pcl/PCLDocumentHandlerMaker.java b/src/java/org/apache/fop/render/pcl/PCLDocumentHandlerMaker.java index 85653e423..affe2abae 100644 --- a/src/java/org/apache/fop/render/pcl/PCLDocumentHandlerMaker.java +++ b/src/java/org/apache/fop/render/pcl/PCLDocumentHandlerMaker.java @@ -19,7 +19,6 @@ package org.apache.fop.render.pcl; -import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker; import org.apache.fop.render.intermediate.IFContext; @@ -36,10 +35,8 @@ public class PCLDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { }; /** {@inheritDoc} */ - public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { - PCLDocumentHandler handler = new PCLDocumentHandler(); - handler.setContext(new IFContext(ua)); - return handler; + public IFDocumentHandler makeIFDocumentHandler(IFContext ifContext) { + return new PCLDocumentHandler(ifContext); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/render/pcl/PCLImageHandlerGraphics2D.java b/src/java/org/apache/fop/render/pcl/PCLImageHandlerGraphics2D.java index 25249caf6..014bc47a1 100644 --- a/src/java/org/apache/fop/render/pcl/PCLImageHandlerGraphics2D.java +++ b/src/java/org/apache/fop/render/pcl/PCLImageHandlerGraphics2D.java @@ -127,7 +127,7 @@ public class PCLImageHandlerGraphics2D implements ImageHandler { if (!painted) { //Fallback solution: Paint to a BufferedImage FOUserAgent ua = context.getUserAgent(); - ImageManager imageManager = ua.getFactory().getImageManager(); + ImageManager imageManager = ua.getImageManager(); ImageRendered imgRend; try { imgRend = (ImageRendered)imageManager.convertImage( diff --git a/src/java/org/apache/fop/render/pcl/PCLPainter.java b/src/java/org/apache/fop/render/pcl/PCLPainter.java index 9fc575456..fa25bb5b5 100644 --- a/src/java/org/apache/fop/render/pcl/PCLPainter.java +++ b/src/java/org/apache/fop/render/pcl/PCLPainter.java @@ -440,8 +440,13 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { final Font font = parent.getFontInfo().getFontInstance(triplet, state.getFontSize()); //for cursive fonts, so the text isn't clipped - final FontMetricsMapper mapper = (FontMetricsMapper)parent.getFontInfo().getMetricsFor( + FontMetricsMapper mapper; + try { + mapper = (FontMetricsMapper)parent.getFontInfo().getMetricsFor( font.getFontName()); + } catch (Exception t) { + throw new RuntimeException(t); + } final int maxAscent = mapper.getMaxAscent(font.getFontSize()) / 1000; final int ascent = mapper.getAscender(font.getFontSize()) / 1000; final int descent = mapper.getDescender(font.getFontSize()) / 1000; diff --git a/src/java/org/apache/fop/render/pcl/PCLRendererConfig.java b/src/java/org/apache/fop/render/pcl/PCLRendererConfig.java new file mode 100644 index 000000000..c46bd9e0b --- /dev/null +++ b/src/java/org/apache/fop/render/pcl/PCLRendererConfig.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.pcl; + +import java.util.EnumMap; +import java.util.Map; + +import org.apache.avalon.framework.configuration.Configuration; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.MimeConstants; +import org.apache.fop.fonts.DefaultFontConfig; +import org.apache.fop.fonts.DefaultFontConfig.DefaultFontConfigParser; +import org.apache.fop.render.RendererConfig; + +import static org.apache.fop.render.pcl.PCLRendererConfig.Options.DISABLE_PJL; +import static org.apache.fop.render.pcl.PCLRendererConfig.Options.RENDERING_MODE; +import static org.apache.fop.render.pcl.PCLRendererConfig.Options.TEXT_RENDERING; + +public final class PCLRendererConfig implements RendererConfig { + + public enum Options { + + RENDERING_MODE("rendering", PCLRenderingMode.class), + TEXT_RENDERING("text-rendering", Boolean.class), + DISABLE_PJL("disable-pjl", Boolean.class); + + private final String name; + + private final Class<?> type; + + private Options(String name, Class<?> type) { + this.name = name; + this.type = type; + } + + public String getName() { + return name; + } + } + + private final Map<Options, Object> params = new EnumMap<Options, Object>(Options.class); + + private final DefaultFontConfig fontConfig; + + private PCLRendererConfig(DefaultFontConfig fontConfig) { + this.fontConfig = fontConfig; + } + + public DefaultFontConfig getFontInfoConfig() { + return fontConfig; + } + + public PCLRenderingMode getRenderingMode() { + return getParam(RENDERING_MODE, PCLRenderingMode.class); + } + + public Boolean isTextRendering() { + return getParam(TEXT_RENDERING, Boolean.class); + } + + public Boolean isDisablePjl() { + return getParam(DISABLE_PJL, Boolean.class); + } + + private <T> T getParam(Options option, Class<T> type) { + assert option.type.equals(type); + return type.cast(params.get(option)); + } + + private <T> void setParam(Options option, T value) { + assert option.type.isInstance(value); + params.put(option, value); + } + + public static final class PCLRendererConfigParser implements RendererConfigParser { + + public PCLRendererConfig build(FOUserAgent userAgent, Configuration cfg) throws FOPException { + PCLRendererConfig config = new PCLRendererConfig(new DefaultFontConfigParser() + .parse(cfg, userAgent.validateStrictly())); + configure(cfg, config); + return config; + } + + private void configure(Configuration cfg, PCLRendererConfig config) throws FOPException { + if (cfg != null) { + String rendering = cfg.getChild(RENDERING_MODE.getName()).getValue(null); + if (rendering != null) { + try { + config.setParam(RENDERING_MODE, PCLRenderingMode.getValueOf(rendering)); + } catch (IllegalArgumentException e) { + throw new FOPException("Valid values for 'rendering' are 'quality', 'speed' and 'bitmap'." + + " Value found: " + rendering); + } + } + String textRendering = cfg.getChild(TEXT_RENDERING.getName()).getValue(null); + if ("bitmap".equalsIgnoreCase(textRendering)) { + config.setParam(TEXT_RENDERING, true); + } else if (textRendering == null || "auto".equalsIgnoreCase(textRendering)) { + config.setParam(TEXT_RENDERING, false); + } else { + throw new FOPException( + "Valid values for 'text-rendering' are 'auto' and 'bitmap'. Value found: " + + textRendering); + } + config.setParam(DISABLE_PJL, + cfg.getChild(DISABLE_PJL.getName()).getValueAsBoolean(false)); + } + } + + public String getMimeType() { + return MimeConstants.MIME_PCL; + } + } + +} diff --git a/src/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java b/src/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java index bc4cdc567..47b58aa16 100644 --- a/src/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java +++ b/src/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java @@ -21,19 +21,13 @@ package org.apache.fop.render.pcl; import java.util.List; -import org.apache.avalon.framework.configuration.Configuration; - import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.io.URIResolverWrapper; +import org.apache.fop.fonts.EmbedFontInfo; 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.FontManager; -import org.apache.fop.fonts.FontResolver; -import org.apache.fop.render.DefaultFontResolver; import org.apache.fop.render.PrintRendererConfigurator; -import org.apache.fop.render.Renderer; +import org.apache.fop.render.RendererConfig.RendererConfigParser; import org.apache.fop.render.intermediate.IFDocumentHandler; import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; import org.apache.fop.render.java2d.Base14FontCollection; @@ -45,88 +39,52 @@ import org.apache.fop.render.java2d.Java2DFontMetrics; * PCL Renderer configurator */ public class PCLRendererConfigurator extends PrintRendererConfigurator - implements IFDocumentHandlerConfigurator { + implements IFDocumentHandlerConfigurator { /** * Default constructor * @param userAgent user agent */ - public PCLRendererConfigurator(FOUserAgent userAgent) { - super(userAgent); - } - - /** - * Throws an UnsupportedOperationException. - * - * @param renderer not used - */ - public void configure(Renderer renderer) { - throw new UnsupportedOperationException(); - } - - private void configure(Configuration cfg, PCLRenderingUtil pclUtil) throws FOPException { - String rendering = cfg.getChild("rendering").getValue(null); - if (rendering != null) { - try { - pclUtil.setRenderingMode(PCLRenderingMode.valueOf(rendering)); - } catch (IllegalArgumentException e) { - throw new FOPException( - "Valid values for 'rendering' are 'quality', 'speed' and 'bitmap'." - + " Value found: " + rendering); - } - } - - String textRendering = cfg.getChild("text-rendering").getValue(null); - if ("bitmap".equalsIgnoreCase(textRendering)) { - pclUtil.setAllTextAsBitmaps(true); - } else if ("auto".equalsIgnoreCase(textRendering)) { - pclUtil.setAllTextAsBitmaps(false); - } else if (textRendering != null) { - throw new FOPException( - "Valid values for 'text-rendering' are 'auto' and 'bitmap'. Value found: " - + textRendering); - } - - pclUtil.setPJLDisabled(cfg.getChild("disable-pjl").getValueAsBoolean(false)); + public PCLRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser) { + super(userAgent, rendererConfigParser); } - // ---=== IFDocumentHandler configuration ===--- - /** {@inheritDoc} */ public void configure(IFDocumentHandler documentHandler) throws FOPException { - Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); - if (cfg != null) { - PCLDocumentHandler pclDocumentHandler = (PCLDocumentHandler)documentHandler; + PCLRendererConfig pdfConfig = (PCLRendererConfig) getRendererConfig(documentHandler); + if (pdfConfig != null) { + PCLDocumentHandler pclDocumentHandler = (PCLDocumentHandler) documentHandler; PCLRenderingUtil pclUtil = pclDocumentHandler.getPCLUtil(); - configure(cfg, pclUtil); + configure(pdfConfig, pclUtil); } } - /** {@inheritDoc} */ - public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo) - throws FOPException { - FontManager fontManager = userAgent.getFactory().getFontManager(); + private void configure(PCLRendererConfig config, PCLRenderingUtil pclUtil) throws FOPException { + if (config.getRenderingMode() != null) { + pclUtil.setRenderingMode(config.getRenderingMode()); + } + if (config.isDisablePjl() != null) { + pclUtil.setPJLDisabled(config.isDisablePjl()); + } + if (config.isTextRendering() != null) { + pclUtil.setAllTextAsBitmaps(config.isTextRendering()); + } + } + @Override + protected List<FontCollection> getDefaultFontCollection() { + final List<FontCollection> fontCollections = new java.util.ArrayList<FontCollection>(); final Java2DFontMetrics java2DFontMetrics = new Java2DFontMetrics(); - final List fontCollections = new java.util.ArrayList(); fontCollections.add(new Base14FontCollection(java2DFontMetrics)); fontCollections.add(new InstalledFontCollection(java2DFontMetrics)); - - Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); - if (cfg != null) { - FontResolver fontResolver = new DefaultFontResolver(userAgent); - FontEventListener listener = new FontEventAdapter( - userAgent.getEventBroadcaster()); - List fontList = buildFontList(cfg, fontResolver, listener); - fontCollections.add(new ConfiguredFontCollection(fontResolver, fontList, - userAgent.isComplexScriptFeaturesEnabled())); - } - - fontManager.setup(fontInfo, - (FontCollection[])fontCollections.toArray( - new FontCollection[fontCollections.size()])); - documentHandler.setFontInfo(fontInfo); + return fontCollections; } + @Override + protected FontCollection createCollectionFromFontList(URIResolverWrapper uriResolverWrapper, + List<EmbedFontInfo> fontList) { + return new ConfiguredFontCollection(uriResolverWrapper, fontList, + userAgent.isComplexScriptFeaturesEnabled()); + } } diff --git a/src/java/org/apache/fop/render/pcl/PCLRenderingMode.java b/src/java/org/apache/fop/render/pcl/PCLRenderingMode.java index 6201197cf..9b8213948 100644 --- a/src/java/org/apache/fop/render/pcl/PCLRenderingMode.java +++ b/src/java/org/apache/fop/render/pcl/PCLRenderingMode.java @@ -25,20 +25,18 @@ import java.io.Serializable; /** * Enumeration class for PCL rendering modes. */ -public final class PCLRenderingMode implements Serializable { - - private static final long serialVersionUID = 6359884255324755026L; - +public enum PCLRenderingMode implements Serializable { /** "Quality" rendering (mixed native and bitmap for improved quality) */ - public static final PCLRenderingMode QUALITY = new PCLRenderingMode("quality", 1.0f); + QUALITY("quality", 1.0f), /** "Speed" rendering (maximum speed with native rendering, reduced visual quality) */ - public static final PCLRenderingMode SPEED = new PCLRenderingMode("speed", 0.25f); + SPEED("speed", 0.25f), /** * "Bitmap" rendering (pages are painted entirely as bitmaps, maximum quality, * reduced performance) */ - public static final PCLRenderingMode BITMAP = new PCLRenderingMode("bitmap", 1.0f); + BITMAP("bitmap", 1.0f); + private static final long serialVersionUID = 6359884255324755026L; private String name; private float defaultDitheringQuality; @@ -70,20 +68,17 @@ public final class PCLRenderingMode implements Serializable { * @param name the name of the enumeration value * @return the enumeration object */ - public static PCLRenderingMode valueOf(String name) { - if (QUALITY.getName().equalsIgnoreCase(name)) { - return QUALITY; - } else if (SPEED.getName().equalsIgnoreCase(name)) { - return SPEED; - } else if (BITMAP.getName().equalsIgnoreCase(name)) { - return BITMAP; - } else { - throw new IllegalArgumentException("Illegal value for enumeration: " + name); + public static PCLRenderingMode getValueOf(String name) { + for (PCLRenderingMode mode : PCLRenderingMode.values()) { + if (mode.getName().equalsIgnoreCase(name)) { + return mode; + } } + throw new IllegalArgumentException("Illegal value for enumeration: " + name); } private Object readResolve() throws ObjectStreamException { - return valueOf(getName()); + return getValueOf(getName()); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java b/src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java deleted file mode 100644 index 4a8a03b27..000000000 --- a/src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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; - -/** - * Constants used for configuring PDF output. - */ -public interface PDFConfigurationConstants { - - /** PDF encryption parameter: all parameters as object, datatype: PDFEncryptionParams */ - String ENCRYPTION_PARAMS = "encryption-params"; - /** PDF encryption parameter: user password, datatype: String */ - String USER_PASSWORD = "user-password"; - /** PDF encryption parameter: owner password, datatype: String */ - String OWNER_PASSWORD = "owner-password"; - /** PDF encryption parameter: Forbids printing, datatype: Boolean or "true"/"false" */ - String NO_PRINT = "noprint"; - /** PDF encryption parameter: Forbids copying content, datatype: Boolean or "true"/"false" */ - String NO_COPY_CONTENT = "nocopy"; - /** PDF encryption parameter: Forbids editing content, datatype: Boolean or "true"/"false" */ - String NO_EDIT_CONTENT = "noedit"; - /** PDF encryption parameter: Forbids annotations, datatype: Boolean or "true"/"false" */ - String NO_ANNOTATIONS = "noannotations"; - - /** - * PDF encryption parameter: Forbids filling in existing interactive forms, datatype: - * Boolean or "true"/"false" - */ - String NO_FILLINFORMS = "nofillinforms"; - - /** - * PDF encryption parameter: Forbids extracting text and graphics, datatype: Boolean - * or "true"/"false" - */ - String NO_ACCESSCONTENT = "noaccesscontent"; - - /** - * PDF encryption parameter: Forbids assembling document, datatype: Boolean or - * "true"/"false" - */ - String NO_ASSEMBLEDOC = "noassembledoc"; - - /** - * PDF encryption parameter: Forbids printing to high quality, datatype: Boolean or - * "true"/"false" - */ - String NO_PRINTHQ = "noprinthq"; - - /** - * PDF encryption length parameter: must be a multiple of 8 between 40 and 128, - * default value 40, datatype: int. - */ - String ENCRYPTION_LENGTH = "encryption-length"; - /** Rendering Options key for the PDF/A mode. */ - String PDF_A_MODE = "pdf-a-mode"; - /** Rendering Options key for the PDF/X mode. */ - String PDF_X_MODE = "pdf-x-mode"; - /** Rendering Options key for the ICC profile for the output intent. */ - String KEY_OUTPUT_PROFILE = "output-profile"; - /** PDF version entry: specify the version of the PDF document created, datatype: String */ - String PDF_VERSION = "version"; - /** - * Rendering Options key for disabling the sRGB color space (only possible if no PDF/A or - * PDF/X profile is active). - */ - String KEY_DISABLE_SRGB_COLORSPACE = "disable-srgb-colorspace"; -} diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java index 5be8c3001..a8f7df66b 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java @@ -50,6 +50,7 @@ import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; import org.apache.fop.render.intermediate.IFDocumentNavigationHandler; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFPainter; +import org.apache.fop.render.pdf.PDFRendererConfig.PDFRendererConfigParser; import org.apache.fop.render.pdf.extensions.PDFEmbeddedFileExtensionAttachment; /** @@ -73,7 +74,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { * Utility class which enables all sorts of features that are not directly connected to the * normal rendering process. */ - protected PDFRenderingUtil pdfUtil; + protected final PDFRenderingUtil pdfUtil; /** the /Resources object of the PDF document being created */ protected PDFResources pdfResources; @@ -99,7 +100,9 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { /** * Default constructor. */ - public PDFDocumentHandler() { + public PDFDocumentHandler(IFContext context) { + super(context); + this.pdfUtil = new PDFRenderingUtil(context.getUserAgent()); } /** {@inheritDoc} */ @@ -113,14 +116,8 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { } /** {@inheritDoc} */ - public void setContext(IFContext context) { - super.setContext(context); - this.pdfUtil = new PDFRenderingUtil(context.getUserAgent()); - } - - /** {@inheritDoc} */ public IFDocumentHandlerConfigurator getConfigurator() { - return new PDFRendererConfigurator(getUserAgent()); + return new PDFRendererConfigurator(getUserAgent(), new PDFRendererConfigParser()); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentHandlerMaker.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandlerMaker.java index 1186db3ae..ceab6f54a 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentHandlerMaker.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandlerMaker.java @@ -32,10 +32,10 @@ public class PDFDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { private static final String[] MIMES = new String[] {MimeConstants.MIME_PDF}; - /** {@inheritDoc} */ - public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { - PDFDocumentHandler handler = new PDFDocumentHandler(); - handler.setContext(new IFContext(ua)); + @Override + public IFDocumentHandler makeIFDocumentHandler(IFContext ifContext) { + PDFDocumentHandler handler = new PDFDocumentHandler(ifContext); + FOUserAgent ua = ifContext.getUserAgent(); if (ua.isAccessibilityEnabled()) { ua.setStructureTreeEventHandler(handler.getStructureTreeEventHandler()); } diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java index bc3b66ece..8eaac923c 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java @@ -86,7 +86,7 @@ public class PDFImageHandlerSVG implements ImageHandler { BridgeContext ctx = new PDFBridgeContext(ua, (strokeText ? null : pdfContext.getFontInfo()), - userAgent.getFactory().getImageManager(), + userAgent.getImageManager(), userAgent.getImageSessionContext(), new AffineTransform()); diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererConfig.java b/src/java/org/apache/fop/render/pdf/PDFRendererConfig.java new file mode 100644 index 000000000..1fb61a380 --- /dev/null +++ b/src/java/org/apache/fop/render/pdf/PDFRendererConfig.java @@ -0,0 +1,252 @@ +/* + * 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.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +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.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.MimeConstants; +import org.apache.fop.fonts.DefaultFontConfig; +import org.apache.fop.fonts.DefaultFontConfig.DefaultFontConfigParser; +import org.apache.fop.pdf.PDFAMode; +import org.apache.fop.pdf.PDFEncryptionParams; +import org.apache.fop.pdf.PDFFilterList; +import org.apache.fop.pdf.PDFXMode; +import org.apache.fop.pdf.Version; +import org.apache.fop.render.RendererConfig; +import org.apache.fop.util.LogUtil; + +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.DISABLE_SRGB_COLORSPACE; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.ENCRYPTION_LENGTH; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.ENCRYPTION_PARAMS; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.FILTER_LIST; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.NO_ACCESSCONTENT; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.NO_ANNOTATIONS; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.NO_ASSEMBLEDOC; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.NO_COPY_CONTENT; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.NO_EDIT_CONTENT; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.NO_FILLINFORMS; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.NO_PRINT; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.NO_PRINTHQ; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.OUTPUT_PROFILE; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.OWNER_PASSWORD; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.PDF_A_MODE; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.PDF_X_MODE; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.USER_PASSWORD; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.VERSION; + + +public final class PDFRendererConfig implements RendererConfig { + + private static final Log LOG = LogFactory.getLog(PDFRendererConfig.class); + + private final Map<PDFRendererConfigOptions, Object> configOptions + = new EnumMap<PDFRendererConfigOptions, Object>(PDFRendererConfigOptions.class); + + private final DefaultFontConfig fontConfig; + + private PDFRendererConfig(DefaultFontConfig fontConfig) { + this.fontConfig = fontConfig; + } + + public DefaultFontConfig getFontInfoConfig() { + return fontConfig; + } + + public Map<String, List<String>> getFilterMap() { + return (Map<String, List<String>>) configOptions.get(FILTER_LIST); + } + + public PDFAMode getPDFAMode() { + return (PDFAMode) configOptions.get(PDF_A_MODE); + } + + public PDFXMode getPDFXMode() { + return (PDFXMode) configOptions.get(PDF_X_MODE); + } + + public PDFEncryptionParams getEncryptionParameters() { + return (PDFEncryptionParams) configOptions.get(ENCRYPTION_PARAMS); + } + + public String getOutputProfileURI() { + return (String) configOptions.get(OUTPUT_PROFILE); + } + + public Boolean getDisableSRGBColorSpace() { + return (Boolean) configOptions.get(DISABLE_SRGB_COLORSPACE); + } + + public Version getPDFVersion() { + String pdfVersion = (String) configOptions.get(VERSION); + return pdfVersion == null ? null : Version.getValueOf(pdfVersion); + } + + public static final class PDFRendererConfigParser implements RendererConfigParser { + + public PDFRendererConfig build(FOUserAgent userAgent, Configuration cfg) throws FOPException { + boolean strict = userAgent != null ? userAgent.validateUserConfigStrictly() : false; + return new ParserHelper(cfg, userAgent, strict).pdfConfig; + } + + public String getMimeType() { + return MimeConstants.MIME_PDF; + } + } + + private static final class ParserHelper { + + private PDFRendererConfig pdfConfig; + + private ParserHelper(Configuration cfg, FOUserAgent userAgent, boolean strict) throws FOPException { + pdfConfig = new PDFRendererConfig(new DefaultFontConfigParser().parse(cfg, strict)); + if (cfg != null) { + configure(cfg, userAgent, strict); + } + } + + private void put(PDFRendererConfigOptions option, Object value) { + if (value != null && !value.equals(option.getDefaultValue())) { + pdfConfig.configOptions.put(option, value); + } + } + + private void configure(Configuration cfg, FOUserAgent userAgent, boolean strict) + throws FOPException { + try { + buildFilterMapFromConfiguration(cfg); + put(PDF_A_MODE, PDFAMode.getValueOf(parseConfig(cfg, PDF_A_MODE))); + put(PDF_X_MODE, PDFXMode.getValueOf(parseConfig(cfg, PDF_X_MODE))); + Configuration encryptCfg = cfg.getChild(ENCRYPTION_PARAMS.getName(), false); + if (encryptCfg != null) { + PDFEncryptionParams encryptionConfig = new PDFEncryptionParams(); + encryptionConfig.setOwnerPassword(parseConfig(encryptCfg, OWNER_PASSWORD)); + encryptionConfig.setUserPassword(parseConfig(encryptCfg, USER_PASSWORD)); + encryptionConfig.setAllowPrint(!doesValueExist(encryptCfg, NO_PRINT)); + encryptionConfig.setAllowCopyContent(!doesValueExist(encryptCfg, NO_COPY_CONTENT)); + encryptionConfig.setAllowEditContent(!doesValueExist(encryptCfg, NO_EDIT_CONTENT)); + encryptionConfig.setAllowEditAnnotations(!doesValueExist(encryptCfg, NO_ANNOTATIONS)); + encryptionConfig.setAllowFillInForms(!doesValueExist(encryptCfg, NO_FILLINFORMS)); + encryptionConfig.setAllowAccessContent(!doesValueExist(encryptCfg, NO_ACCESSCONTENT)); + encryptionConfig.setAllowAssembleDocument(!doesValueExist(encryptCfg, + NO_ASSEMBLEDOC)); + encryptionConfig.setAllowPrintHq(!doesValueExist(encryptCfg, NO_PRINTHQ)); + String encryptionLength = parseConfig(encryptCfg, ENCRYPTION_LENGTH); + if (encryptionLength != null) { + int validatedLength = checkEncryptionLength(Integer.parseInt(encryptionLength), + userAgent); + encryptionConfig.setEncryptionLengthInBits(validatedLength); + } + put(ENCRYPTION_PARAMS, encryptionConfig); + } + // TODO: Check this, I'm pretty sure the getChild(Str, bool) should be false!!! + put(OUTPUT_PROFILE, parseConfig(cfg, OUTPUT_PROFILE)); + put(DISABLE_SRGB_COLORSPACE, Boolean.valueOf(parseConfig(cfg, DISABLE_SRGB_COLORSPACE))); + put(VERSION, getPDFDocVersion(cfg)); + } catch (ConfigurationException e) { + LogUtil.handleException(LOG, e, strict); + } + } + + private void buildFilterMapFromConfiguration(Configuration cfg) + throws ConfigurationException, FOPException { + Configuration[] filterLists = cfg.getChildren(FILTER_LIST.getName()); + Map<String, List<String>> filterMap = new HashMap<String, List<String>>(); + for (Configuration filters : filterLists) { + String type = filters.getAttribute("type", PDFFilterList.DEFAULT_FILTER); + List<String> filterList = new ArrayList<String>(); + for (Configuration nameCfg : filters.getChildren("value")) { + filterList.add(nameCfg.getValue()); + } + 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)); + } + LogUtil.handleError(LOG, debug.toString(), true); + } + + if (filterMap.get(type) != null) { + throw new ConfigurationException("A filterList of type '" + + type + "' has already been defined"); + } + filterMap.put(type, filterList); + } + put(FILTER_LIST, filterMap); + } + + private String parseConfig(Configuration cfg, PDFRendererConfigOptions option) { + Configuration child = cfg.getChild(option.getName()); + return child.getValue(null); + } + + private boolean doesValueExist(Configuration cfg, PDFRendererConfigOptions option) { + return cfg.getChild(option.getName(), false) != null; + } + + private String getPDFDocVersion(Configuration cfg) throws FOPException { + Configuration pdfVersion = cfg.getChild(VERSION.getName(), false); + if (pdfVersion != null) { + String version = pdfVersion.getValue(null); + if (version != null && version.length() != 0) { + return version; + } else { + throw new FOPException("The PDF version has not been set."); + } + } + return null; + } + + private int checkEncryptionLength(int encryptionLength, FOUserAgent userAgent) { + int correctEncryptionLength = encryptionLength; + if (encryptionLength < 40) { + correctEncryptionLength = 40; + } else if (encryptionLength > 128) { + correctEncryptionLength = 128; + } else if (encryptionLength % 8 != 0) { + correctEncryptionLength = Math.round(encryptionLength / 8.0f) * 8; + } + if (correctEncryptionLength != encryptionLength && userAgent != null) { + PDFEventProducer.Provider.get(userAgent.getEventBroadcaster()) + .incorrectEncryptionLength(this, encryptionLength, + correctEncryptionLength); + } + return correctEncryptionLength; + } + } + +} diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererConfigOptions.java b/src/java/org/apache/fop/render/pdf/PDFRendererConfigOptions.java new file mode 100644 index 000000000..81a410c3d --- /dev/null +++ b/src/java/org/apache/fop/render/pdf/PDFRendererConfigOptions.java @@ -0,0 +1,112 @@ +/* + * 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 org.apache.fop.pdf.PDFAMode; +import org.apache.fop.pdf.PDFXMode; +import org.apache.fop.render.RendererConfigOptions; + +public enum PDFRendererConfigOptions implements RendererConfigOptions { + FILTER_LIST("filterList"), + /** Rendering Options key for the PDF/A mode, default: {@link PDFAMode#DISABLED} */ + PDF_A_MODE("pdf-a-mode", PDFAMode.DISABLED), + /** Rendering Options key for the PDF/X mode, default: {@link PDFXMode#DISABLED} */ + PDF_X_MODE("pdf-x-mode", PDFXMode.DISABLED), + /** PDF version entry: specify the version of the PDF document created, datatype: String */ + VERSION("version"), + /** + * Rendering Options key for disabling the sRGB color space (only possible if no PDF/A or + * PDF/X profile is active), default: false + */ + DISABLE_SRGB_COLORSPACE("disable-srgb-colorspace", false), + /** Rendering Options key for the ICC profile for the output intent. */ + OUTPUT_PROFILE("output-profile"), + /** PDF encryption parameter: all parameters as object, datatype: PDFEncryptionParams */ + ENCRYPTION_PARAMS("encryption-params"), + /** + * PDF encryption length parameter: must be a multiple of 8 between 40 and 128, + * default value 40, datatype: int, default: 40 + */ + ENCRYPTION_LENGTH("encryption-length", 40), + /** + * PDF encryption parameter: Forbids printing to high quality, datatype: Boolean or + * "true"/"false", default: false + */ + NO_PRINTHQ("noprinthq", 40), + /** + * PDF encryption parameter: Forbids assembling document, datatype: Boolean or + * "true"/"false", default: false + */ + NO_ASSEMBLEDOC("noassembledoc", false), + /** + * PDF encryption parameter: Forbids extracting text and graphics, datatype: Boolean + * or "true"/"false", default: false + */ + NO_ACCESSCONTENT("noaccesscontent", false), + /** + * PDF encryption parameter: Forbids filling in existing interactive forms, datatype: + * Boolean or "true"/"false", default: false + */ + NO_FILLINFORMS("nofillinforms", false), + /** + * PDF encryption parameter: Forbids annotations, datatype: Boolean or "true"/"false", + * default: false + */ + NO_ANNOTATIONS("noannotations", false), + /** + * PDF encryption parameter: Forbids printing, datatype: Boolean or "true"/"false", + * default: false + */ + NO_PRINT("noprint", false), + /** + * PDF encryption parameter: Forbids copying content, datatype: Boolean or "true"/"false", + * default: false + */ + NO_COPY_CONTENT("nocopy", false), + /** + * PDF encryption parameter: Forbids editing content, datatype: Boolean or "true"/"false", + * default: false + */ + NO_EDIT_CONTENT("noedit", false), + /** PDF encryption parameter: user password, datatype: String, default: "" */ + USER_PASSWORD("user-password", ""), + /** PDF encryption parameter: owner password, datatype: String, default: "" */ + OWNER_PASSWORD("owner-password", ""); + + private final String name; + private final Object defaultValue; + + private PDFRendererConfigOptions(String name, Object defaultValue) { + this.name = name; + this.defaultValue = defaultValue; + } + + private PDFRendererConfigOptions(String name) { + this(name, null); + } + + public String getName() { + return name; + } + + public Object getDefaultValue() { + return defaultValue; + } +} diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java b/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java index df5224c04..a4892dd70 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java +++ b/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java @@ -19,238 +19,72 @@ 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.PDFEncryptionParams; -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.render.RendererConfig.RendererConfigParser; +import org.apache.fop.render.adobe.AdobeRendererConfigurator; import org.apache.fop.render.intermediate.IFDocumentHandler; -import org.apache.fop.util.LogUtil; /** * PDF renderer configurator. */ -public class PDFRendererConfigurator extends PrintRendererConfigurator { +public class PDFRendererConfigurator extends AdobeRendererConfigurator { /** * Default constructor * * @param userAgent user agent */ - public PDFRendererConfigurator(FOUserAgent userAgent) { - super(userAgent); - } - - /** - * Throws an UnsupportedOperationException. - * - * @param renderer not used - */ - public void configure(Renderer renderer) { - throw new UnsupportedOperationException(); + public PDFRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser) { + super(userAgent, rendererConfigParser); } - private void configure(Configuration cfg, PDFRenderingUtil pdfUtil) throws FOPException { - //PDF filters - try { - Map filterMap = buildFilterMapFromConfiguration(cfg); - if (filterMap != null) { - pdfUtil.setFilterMap(filterMap); - } - } catch (ConfigurationException e) { - LogUtil.handleException(log, e, false); - } + // ---=== IFDocumentHandler configuration ===--- - String s = cfg.getChild(PDFConfigurationConstants.PDF_A_MODE, true).getValue(null); - if (s != null) { - pdfUtil.setAMode(PDFAMode.valueOf(s)); - } - s = cfg.getChild(PDFConfigurationConstants.PDF_X_MODE, true).getValue(null); - if (s != null) { - pdfUtil.setXMode(PDFXMode.valueOf(s)); - } - Configuration encryptionParamsConfig - = cfg.getChild(PDFConfigurationConstants.ENCRYPTION_PARAMS, false); - if (encryptionParamsConfig != null) { - PDFEncryptionParams encryptionParams = pdfUtil.getEncryptionParams(); - Configuration ownerPasswordConfig = encryptionParamsConfig.getChild( - PDFConfigurationConstants.OWNER_PASSWORD, false); - if (ownerPasswordConfig != null) { - String ownerPassword = ownerPasswordConfig.getValue(null); - if (ownerPassword != null) { - encryptionParams.setOwnerPassword(ownerPassword); - } - } - Configuration userPasswordConfig = encryptionParamsConfig.getChild( - PDFConfigurationConstants.USER_PASSWORD, false); - if (userPasswordConfig != null) { - String userPassword = userPasswordConfig.getValue(null); - if (userPassword != null) { - encryptionParams.setUserPassword(userPassword); - } - } - Configuration noPrintConfig = encryptionParamsConfig.getChild( - PDFConfigurationConstants.NO_PRINT, false); - if (noPrintConfig != null) { - encryptionParams.setAllowPrint(false); - } - Configuration noCopyContentConfig = encryptionParamsConfig.getChild( - PDFConfigurationConstants.NO_COPY_CONTENT, false); - if (noCopyContentConfig != null) { - encryptionParams.setAllowCopyContent(false); - } - Configuration noEditContentConfig = encryptionParamsConfig.getChild( - PDFConfigurationConstants.NO_EDIT_CONTENT, false); - if (noEditContentConfig != null) { - encryptionParams.setAllowEditContent(false); - } - Configuration noAnnotationsConfig = encryptionParamsConfig.getChild( - PDFConfigurationConstants.NO_ANNOTATIONS, false); - if (noAnnotationsConfig != null) { - encryptionParams.setAllowEditAnnotations(false); - } - Configuration noFillInForms = encryptionParamsConfig.getChild( - PDFConfigurationConstants.NO_FILLINFORMS, false); - if (noFillInForms != null) { - encryptionParams.setAllowFillInForms(false); - } - Configuration noAccessContentConfig = encryptionParamsConfig.getChild( - PDFConfigurationConstants.NO_ACCESSCONTENT, false); - if (noAccessContentConfig != null) { - encryptionParams.setAllowAccessContent(false); - } - Configuration noAssembleDocConfig = encryptionParamsConfig.getChild( - PDFConfigurationConstants.NO_ASSEMBLEDOC, false); - if (noAssembleDocConfig != null) { - encryptionParams.setAllowAssembleDocument(false); + /** {@inheritDoc} */ + public void configure(IFDocumentHandler documentHandler) throws FOPException { + final PDFRendererConfig pdfConfig = (PDFRendererConfig) getRendererConfig(documentHandler); + if (pdfConfig != null) { + PDFDocumentHandler pdfDocumentHandler = (PDFDocumentHandler) documentHandler; + PDFRenderingUtil pdfUtil = pdfDocumentHandler.getPDFUtil(); + if (pdfConfig.getFilterMap() != null) { + pdfUtil.setFilterMap(pdfConfig.getFilterMap()); } - Configuration noPrintHqConfig = encryptionParamsConfig.getChild( - PDFConfigurationConstants.NO_PRINTHQ, false); - if (noPrintHqConfig != null) { - encryptionParams.setAllowPrintHq(false); + if (pdfConfig.getPDFAMode() != null) { + pdfUtil.setAMode(pdfConfig.getPDFAMode()); } - Configuration encryptionLengthConfig = encryptionParamsConfig.getChild( - PDFConfigurationConstants.ENCRYPTION_LENGTH, false); - if (encryptionLengthConfig != null) { - int encryptionLength = checkEncryptionLength( - Integer.parseInt(encryptionLengthConfig.getValue(null))); - encryptionParams.setEncryptionLengthInBits(encryptionLength); + if (pdfConfig.getPDFXMode() != null) { + pdfUtil.setXMode(pdfConfig.getPDFXMode()); } - } - - s = cfg.getChild(PDFConfigurationConstants.KEY_OUTPUT_PROFILE, true).getValue(null); - if (s != null) { - pdfUtil.setOutputProfileURI(s); - } - Configuration disableColorSpaceConfig = cfg.getChild( - PDFConfigurationConstants.KEY_DISABLE_SRGB_COLORSPACE, false); - if (disableColorSpaceConfig != null) { - pdfUtil.setDisableSRGBColorSpace( - disableColorSpaceConfig.getValueAsBoolean(false)); - } - - setPDFDocVersion(cfg, pdfUtil); - } - - private int checkEncryptionLength(int encryptionLength) { - int correctEncryptionLength = encryptionLength; - if (encryptionLength < 40) { - correctEncryptionLength = 40; - } else if (encryptionLength > 128) { - correctEncryptionLength = 128; - } else if (encryptionLength % 8 != 0) { - correctEncryptionLength = ((int) Math.round(encryptionLength / 8.0f)) * 8; - } - if (correctEncryptionLength != encryptionLength) { - PDFEventProducer.Provider.get(userAgent.getEventBroadcaster()) - .incorrectEncryptionLength(this, encryptionLength, correctEncryptionLength); - } - return correctEncryptionLength; - } - - private void setPDFDocVersion(Configuration cfg, PDFRenderingUtil pdfUtil) throws FOPException { - Configuration pdfVersion = cfg.getChild(PDFConfigurationConstants.PDF_VERSION, false); - if (pdfVersion != null) { - String version = pdfVersion.getValue(null); - if (version != null && version.length() != 0) { - try { - pdfUtil.setPDFVersion(version); - } catch (IllegalArgumentException e) { - throw new FOPException(e.getMessage()); - } - } else { - throw new FOPException("The PDF version has not been set."); + if (pdfConfig.getOutputProfileURI() != null) { + pdfUtil.setOutputProfileURI(pdfConfig.getOutputProfileURI()); } - } - } - - /** - * 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 (pdfConfig.getPDFVersion() != null) { + pdfUtil.setPDFVersion(pdfConfig.getPDFVersion()); } - - if (type == null) { - type = PDFFilterList.DEFAULT_FILTER; + if (pdfConfig.getDisableSRGBColorSpace() != null) { + pdfUtil.setDisableSRGBColorSpace(pdfConfig.getDisableSRGBColorSpace()); } - if (!filterList.isEmpty() && log.isDebugEnabled()) { - StringBuffer debug = new StringBuffer("Adding PDF filter"); - if (filterList.size() != 1) { - debug.append("s"); + PDFEncryptionParams config = pdfConfig.getEncryptionParameters(); + if (config != null) { + PDFEncryptionParams utilParams = pdfUtil.getEncryptionParams(); + if (config.getUserPassword() != null) { + utilParams.setUserPassword(config.getUserPassword()); } - 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)); + if (config.getOwnerPassword() != null) { + utilParams.setOwnerPassword(config.getOwnerPassword()); } - log.debug(debug.toString()); + utilParams.setAllowPrint(config.isAllowPrint()); + utilParams.setAllowCopyContent(config.isAllowCopyContent()); + utilParams.setAllowEditContent(config.isAllowEditContent()); + utilParams.setAllowAssembleDocument(config.isAllowAssembleDocument()); + utilParams.setAllowAccessContent(config.isAllowAccessContent()); + utilParams.setAllowFillInForms(config.isAllowFillInForms()); + utilParams.setAllowPrintHq(config.isAllowPrintHq()); + utilParams.setEncryptionLengthInBits(config.getEncryptionLengthInBits()); } - - if (filterMap.get(type) != null) { - throw new ConfigurationException("A filterList of type '" - + type + "' has already been defined"); - } - filterMap.put(type, filterList); - } - return filterMap; - } - - // ---=== IFDocumentHandler configuration ===--- - - /** {@inheritDoc} */ - public void configure(IFDocumentHandler documentHandler) throws FOPException { - Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); - if (cfg != null) { - PDFDocumentHandler pdfDocumentHandler = (PDFDocumentHandler)documentHandler; - PDFRenderingUtil pdfUtil = pdfDocumentHandler.getPDFUtil(); - configure(cfg, pdfUtil); } } diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java index 53d259677..c7252baf1 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java @@ -68,11 +68,27 @@ import org.apache.fop.pdf.Version; import org.apache.fop.pdf.VersionController; import org.apache.fop.render.pdf.extensions.PDFEmbeddedFileExtensionAttachment; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.DISABLE_SRGB_COLORSPACE; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.ENCRYPTION_PARAMS; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.NO_ACCESSCONTENT; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.NO_ANNOTATIONS; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.NO_ASSEMBLEDOC; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.NO_COPY_CONTENT; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.NO_EDIT_CONTENT; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.NO_FILLINFORMS; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.NO_PRINT; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.NO_PRINTHQ; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.OUTPUT_PROFILE; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.OWNER_PASSWORD; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.PDF_A_MODE; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.PDF_X_MODE; +import static org.apache.fop.render.pdf.PDFRendererConfigOptions.USER_PASSWORD; + /** * Utility class which enables all sorts of features that are not directly connected to the * normal rendering process. */ -class PDFRenderingUtil implements PDFConfigurationConstants { +class PDFRenderingUtil { /** logging instance */ private static Log log = LogFactory.getLog(PDFRenderingUtil.class); @@ -80,31 +96,31 @@ class PDFRenderingUtil implements PDFConfigurationConstants { private FOUserAgent userAgent; /** the PDF Document being created */ - protected PDFDocument pdfDoc; + private PDFDocument pdfDoc; /** the PDF/A mode (Default: disabled) */ - protected PDFAMode pdfAMode = PDFAMode.DISABLED; + private PDFAMode pdfAMode = (PDFAMode) PDFRendererConfigOptions.PDF_A_MODE.getDefaultValue(); /** the PDF/X mode (Default: disabled) */ - protected PDFXMode pdfXMode = PDFXMode.DISABLED; + private PDFXMode pdfXMode = (PDFXMode) PDFRendererConfigOptions.PDF_X_MODE.getDefaultValue(); /** the (optional) encryption parameters */ - protected PDFEncryptionParams encryptionParams; + private PDFEncryptionParams encryptionParams; /** Registry of PDF filters */ - protected Map filterMap; + private Map filterMap; /** the ICC stream used as output profile by this document for PDF/A and PDF/X functionality. */ - protected PDFICCStream outputProfile; + private PDFICCStream outputProfile; /** the default sRGB color space. */ - protected PDFICCBasedColorSpace sRGBColorSpace; + private PDFICCBasedColorSpace sRGBColorSpace; /** controls whether the sRGB color space should be installed */ - protected boolean disableSRGBColorSpace = false; + private boolean disableSRGBColorSpace = false; /** Optional URI to an output profile to be used. */ - protected String outputProfileURI; + private String outputProfileURI; - protected Version maxPDFVersion; + private Version maxPDFVersion; PDFRenderingUtil(FOUserAgent userAgent) { @@ -124,68 +140,67 @@ class PDFRenderingUtil implements PDFConfigurationConstants { private void initialize() { PDFEncryptionParams params - = (PDFEncryptionParams)userAgent.getRendererOptions().get(ENCRYPTION_PARAMS); + = (PDFEncryptionParams) userAgent.getRendererOption(ENCRYPTION_PARAMS); if (params != null) { this.encryptionParams = params; //overwrite if available } - String userPassword = (String)userAgent.getRendererOptions().get(USER_PASSWORD); + String userPassword = (String) userAgent.getRendererOption(USER_PASSWORD); if (userPassword != null) { getEncryptionParams().setUserPassword(userPassword); } - String ownerPassword = (String)userAgent.getRendererOptions().get(OWNER_PASSWORD); + String ownerPassword = (String) userAgent.getRendererOption(OWNER_PASSWORD); if (ownerPassword != null) { getEncryptionParams().setOwnerPassword(ownerPassword); } - Object noPrint = userAgent.getRendererOptions().get(NO_PRINT); + Object noPrint = userAgent.getRendererOption(NO_PRINT); if (noPrint != null) { getEncryptionParams().setAllowPrint(!booleanValueOf(noPrint)); } - Object noCopyContent = userAgent.getRendererOptions().get(NO_COPY_CONTENT); + Object noCopyContent = userAgent.getRendererOption(NO_COPY_CONTENT); if (noCopyContent != null) { getEncryptionParams().setAllowCopyContent(!booleanValueOf(noCopyContent)); } - Object noEditContent = userAgent.getRendererOptions().get(NO_EDIT_CONTENT); + Object noEditContent = userAgent.getRendererOption(NO_EDIT_CONTENT); if (noEditContent != null) { getEncryptionParams().setAllowEditContent(!booleanValueOf(noEditContent)); } - Object noAnnotations = userAgent.getRendererOptions().get(NO_ANNOTATIONS); + Object noAnnotations = userAgent.getRendererOption(NO_ANNOTATIONS); if (noAnnotations != null) { getEncryptionParams().setAllowEditAnnotations(!booleanValueOf(noAnnotations)); } - Object noFillInForms = userAgent.getRendererOptions().get(NO_FILLINFORMS); + Object noFillInForms = userAgent.getRendererOption(NO_FILLINFORMS); if (noFillInForms != null) { getEncryptionParams().setAllowFillInForms(!booleanValueOf(noFillInForms)); } - Object noAccessContent = userAgent.getRendererOptions().get(NO_ACCESSCONTENT); + Object noAccessContent = userAgent.getRendererOption(NO_ACCESSCONTENT); if (noAccessContent != null) { getEncryptionParams().setAllowAccessContent(!booleanValueOf(noAccessContent)); } - Object noAssembleDoc = userAgent.getRendererOptions().get(NO_ASSEMBLEDOC); + Object noAssembleDoc = userAgent.getRendererOption(NO_ASSEMBLEDOC); if (noAssembleDoc != null) { getEncryptionParams().setAllowAssembleDocument(!booleanValueOf(noAssembleDoc)); } - Object noPrintHQ = userAgent.getRendererOptions().get(NO_PRINTHQ); + Object noPrintHQ = userAgent.getRendererOption(NO_PRINTHQ); if (noPrintHQ != null) { getEncryptionParams().setAllowPrintHq(!booleanValueOf(noPrintHQ)); } - String s = (String)userAgent.getRendererOptions().get(PDF_A_MODE); + String s = (String) userAgent.getRendererOption(PDF_A_MODE); if (s != null) { - this.pdfAMode = PDFAMode.valueOf(s); + this.pdfAMode = PDFAMode.getValueOf(s); } if (this.pdfAMode.isPDFA1LevelA()) { //Enable accessibility if PDF/A-1a is enabled because it requires tagged PDF. userAgent.getRendererOptions().put(Accessibility.ACCESSIBILITY, Boolean.TRUE); } - s = (String)userAgent.getRendererOptions().get(PDF_X_MODE); + s = (String) userAgent.getRendererOption(PDF_X_MODE); if (s != null) { - this.pdfXMode = PDFXMode.valueOf(s); + this.pdfXMode = PDFXMode.getValueOf(s); } - s = (String)userAgent.getRendererOptions().get(KEY_OUTPUT_PROFILE); + s = (String) userAgent.getRendererOption(OUTPUT_PROFILE); if (s != null) { this.outputProfileURI = s; } - Object disableSRGBColorSpace = userAgent.getRendererOptions().get( - KEY_DISABLE_SRGB_COLORSPACE); + Object disableSRGBColorSpace = userAgent.getRendererOption(DISABLE_SRGB_COLORSPACE); if (disableSRGBColorSpace != null) { this.disableSRGBColorSpace = booleanValueOf(disableSRGBColorSpace); } @@ -504,7 +519,7 @@ class PDFRenderingUtil implements PDFConfigurationConstants { * @throws IllegalArgumentException if the format of version doesn't conform to that specified * by {@link Version} */ - public void setPDFVersion(String version) { - maxPDFVersion = Version.getValueOf(version); + public void setPDFVersion(Version version) { + maxPDFVersion = version; } } diff --git a/src/java/org/apache/fop/render/print/PrintRendererMaker.java b/src/java/org/apache/fop/render/print/PrintRendererMaker.java index 63444a628..66eb4b108 100644 --- a/src/java/org/apache/fop/render/print/PrintRendererMaker.java +++ b/src/java/org/apache/fop/render/print/PrintRendererMaker.java @@ -19,12 +19,15 @@ package org.apache.fop.render.print; +import java.util.List; + +import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; +import org.apache.fop.fonts.FontCollection; 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. @@ -33,22 +36,28 @@ public class PrintRendererMaker extends AbstractRendererMaker { private static final String[] MIMES = new String[] {MimeConstants.MIME_FOP_PRINT}; - /**{@inheritDoc} */ + @Override public Renderer makeRenderer(FOUserAgent userAgent) { return new PrintRenderer(userAgent); } - /** {@inheritDoc} */ - public RendererConfigurator getConfigurator(FOUserAgent userAgent) { - return new PrintRendererConfigurator(userAgent); + @Override + public void configureRenderer(FOUserAgent userAgent, Renderer renderer) throws FOPException { + // TODO what constructor params? + new PrintRendererConfigurator(userAgent, null) { + @Override + protected List<FontCollection> getDefaultFontCollection() { + throw new UnsupportedOperationException(); + } + } .configure(renderer); } - /** {@inheritDoc} */ + @Override public boolean needsOutputStream() { return false; } - /** {@inheritDoc} */ + @Override public String[] getSupportedMimeTypes() { return MIMES; } diff --git a/src/java/org/apache/fop/render/ps/PSDocumentHandler.java b/src/java/org/apache/fop/render/ps/PSDocumentHandler.java index 95647d820..e6ba623da 100644 --- a/src/java/org/apache/fop/render/ps/PSDocumentHandler.java +++ b/src/java/org/apache/fop/render/ps/PSDocumentHandler.java @@ -56,12 +56,14 @@ import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFPainter; +import org.apache.fop.render.ps.PSRendererConfig.PSRendererConfigParser; import org.apache.fop.render.ps.extensions.PSCommentAfter; import org.apache.fop.render.ps.extensions.PSCommentBefore; import org.apache.fop.render.ps.extensions.PSPageTrailerCodeBefore; import org.apache.fop.render.ps.extensions.PSSetPageDevice; import org.apache.fop.render.ps.extensions.PSSetupCode; + /** * {@link IFDocumentHandler} implementation that produces PostScript. */ @@ -109,7 +111,9 @@ public class PSDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { /** * Default constructor. */ - public PSDocumentHandler() { + public PSDocumentHandler(IFContext context) { + super(context); + this.psUtil = new PSRenderingUtil(context.getUserAgent()); } /** {@inheritDoc} */ @@ -123,14 +127,8 @@ public class PSDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { } /** {@inheritDoc} */ - public void setContext(IFContext context) { - super.setContext(context); - this.psUtil = new PSRenderingUtil(context.getUserAgent()); - } - - /** {@inheritDoc} */ public IFDocumentHandlerConfigurator getConfigurator() { - return new PSRendererConfigurator(getUserAgent()); + return new PSRendererConfigurator(getUserAgent(), new PSRendererConfigParser()); } PSRenderingUtil getPSUtil() { diff --git a/src/java/org/apache/fop/render/ps/PSDocumentHandlerMaker.java b/src/java/org/apache/fop/render/ps/PSDocumentHandlerMaker.java index c581f9e02..1c31c4906 100644 --- a/src/java/org/apache/fop/render/ps/PSDocumentHandlerMaker.java +++ b/src/java/org/apache/fop/render/ps/PSDocumentHandlerMaker.java @@ -19,7 +19,6 @@ package org.apache.fop.render.ps; -import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker; import org.apache.fop.render.intermediate.IFContext; @@ -33,19 +32,17 @@ public class PSDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { private static final String[] MIMES = new String[] {MimeConstants.MIME_POSTSCRIPT}; - /** {@inheritDoc} */ - public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { - PSDocumentHandler handler = new PSDocumentHandler(); - handler.setContext(new IFContext(ua)); - return handler; + @Override + public IFDocumentHandler makeIFDocumentHandler(IFContext ifContext) { + return new PSDocumentHandler(ifContext); } - /** {@inheritDoc} */ + @Override public boolean needsOutputStream() { return true; } - /** {@inheritDoc} */ + @Override public String[] getSupportedMimeTypes() { return MIMES; } diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index 5e95b5ded..7b86c31cf 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -19,15 +19,10 @@ package org.apache.fop.render.ps; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; import java.util.Map; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -226,27 +221,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { private static InputStream getInputStreamOnFont(PSGenerator gen, CustomFont font) throws IOException { if (isEmbeddable(font)) { - Source source = font.getEmbedFileSource(); - if (source == null && font.getEmbedResourceName() != null) { - source = new StreamSource(PSFontUtils.class - .getResourceAsStream(font.getEmbedResourceName())); - } - if (source == null) { - return null; - } - InputStream in = null; - if (source instanceof StreamSource) { - in = ((StreamSource) source).getInputStream(); - } - if (in == null && source.getSystemId() != null) { - try { - in = new java.net.URL(source.getSystemId()).openStream(); - } catch (MalformedURLException e) { - new FileNotFoundException( - "File not found. URL could not be resolved: " - + e.getMessage()); - } - } + InputStream in = font.getInputStream(); if (in == null) { return null; } diff --git a/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java b/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java index 839a0cab6..3ade34522 100644 --- a/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java +++ b/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java @@ -70,7 +70,7 @@ public class PSImageHandlerSVG implements ImageHandler { BridgeContext ctx = new PSBridgeContext(ua, (strokeText ? null : psContext.getFontInfo()), - context.getUserAgent().getFactory().getImageManager(), + context.getUserAgent().getImageManager(), context.getUserAgent().getImageSessionContext()); //Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine) diff --git a/src/java/org/apache/fop/render/ps/PSImageUtils.java b/src/java/org/apache/fop/render/ps/PSImageUtils.java index 431071701..962f19d10 100644 --- a/src/java/org/apache/fop/render/ps/PSImageUtils.java +++ b/src/java/org/apache/fop/render/ps/PSImageUtils.java @@ -53,7 +53,7 @@ public class PSImageUtils extends org.apache.xmlgraphics.ps.PSImageUtils { } //Investigate choice for inline mode ImageFlavor[] inlineFlavors = determineSupportedImageFlavors(renderingContext); - ImageManager manager = renderingContext.getUserAgent().getFactory().getImageManager(); + ImageManager manager = renderingContext.getUserAgent().getImageManager(); ImageProviderPipeline[] inlineCandidates = manager.getPipelineFactory().determineCandidatePipelines( info, inlineFlavors); @@ -79,7 +79,7 @@ public class PSImageUtils extends org.apache.xmlgraphics.ps.PSImageUtils { private static ImageFlavor[] determineSupportedImageFlavors(RenderingContext renderingContext) { ImageFlavor[] inlineFlavors; ImageHandlerRegistry imageHandlerRegistry - = renderingContext.getUserAgent().getFactory().getImageHandlerRegistry(); + = renderingContext.getUserAgent().getImageHandlerRegistry(); inlineFlavors = imageHandlerRegistry.getSupportedFlavors(renderingContext); return inlineFlavors; } diff --git a/src/java/org/apache/fop/render/ps/PSRendererConfig.java b/src/java/org/apache/fop/render/ps/PSRendererConfig.java new file mode 100644 index 000000000..f023b4647 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSRendererConfig.java @@ -0,0 +1,141 @@ +/* + * 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 java.util.EnumMap; +import java.util.Locale; + +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; +import org.apache.fop.apps.MimeConstants; +import org.apache.fop.fonts.DefaultFontConfig; +import org.apache.fop.fonts.DefaultFontConfig.DefaultFontConfigParser; +import org.apache.fop.render.RendererConfig; +import org.apache.fop.util.LogUtil; + +import static org.apache.fop.render.ps.PSRendererConfigurationOptions.AUTO_ROTATE_LANDSCAPE; +import static org.apache.fop.render.ps.PSRendererConfigurationOptions.DSC_COMPLIANT; +import static org.apache.fop.render.ps.PSRendererConfigurationOptions.LANGUAGE_LEVEL; +import static org.apache.fop.render.ps.PSRendererConfigurationOptions.OPTIMIZE_RESOURCES; +import static org.apache.fop.render.ps.PSRendererConfigurationOptions.RENDERING_MODE; +import static org.apache.fop.render.ps.PSRendererConfigurationOptions.SAFE_SET_PAGE_DEVICE; + +public final class PSRendererConfig implements RendererConfig { + + private final EnumMap<PSRendererConfigurationOptions, Object> params + = new EnumMap<PSRendererConfigurationOptions, Object>(PSRendererConfigurationOptions.class); + + private final DefaultFontConfig fontConfig; + + private PSRendererConfig(DefaultFontConfig fontConfig) { + this.fontConfig = fontConfig; + } + + public DefaultFontConfig getFontInfoConfig() { + return fontConfig; + } + + public Boolean isAutoRotateLandscape() { + return (Boolean) params.get(AUTO_ROTATE_LANDSCAPE); + } + + public Integer getLanguageLevel() { + return (Integer) params.get(LANGUAGE_LEVEL); + } + + public Boolean isOptimizeResources() { + return (Boolean) params.get(OPTIMIZE_RESOURCES); + } + + public Boolean isSafeSetPageDevice() { + return (Boolean) params.get(SAFE_SET_PAGE_DEVICE); + } + + public Boolean isDscComplianceEnabled() { + return (Boolean) params.get(DSC_COMPLIANT); + } + + public PSRenderingMode getRenderingMode() { + return (PSRenderingMode) params.get(RENDERING_MODE); + } + + public static final class PSRendererConfigParser implements RendererConfigParser { + + private static final Log LOG = LogFactory.getLog(PSRendererConfigParser.class); + + public PSRendererConfig build(FOUserAgent userAgent, Configuration cfg) throws FOPException { + PSRendererConfig config = null; + try { + config = new ParserHelper(cfg, userAgent).config; + } catch (ConfigurationException e) { + LogUtil.handleException(LOG, e, false); + } + return config; + } + + public String getMimeType() { + return MimeConstants.MIME_POSTSCRIPT; + } + } + + private static final class ParserHelper { + + private PSRendererConfig config; + + private ParserHelper(Configuration cfg, FOUserAgent userAgent) + throws ConfigurationException, FOPException { + config = new PSRendererConfig(new DefaultFontConfigParser().parse(cfg, + userAgent.validateStrictly())); + if (cfg != null) { + setBoolConfigParam(cfg, AUTO_ROTATE_LANDSCAPE); + setConfigParameter(LANGUAGE_LEVEL, + cfg.getChild(LANGUAGE_LEVEL.getName()) + .getValueAsInteger((Integer) LANGUAGE_LEVEL.getDefaultValue())); + setBoolConfigParam(cfg, OPTIMIZE_RESOURCES); + setBoolConfigParam(cfg, SAFE_SET_PAGE_DEVICE); + setBoolConfigParam(cfg, DSC_COMPLIANT); + Configuration child = cfg.getChild("rendering"); + if (child != null) { + config.params.put(RENDERING_MODE, + PSRenderingMode.valueOf(child.getValue( + RENDERING_MODE.getDefaultValue().toString()) + .toUpperCase(Locale.ENGLISH))); + } + } + } + + private void setConfigParameter(PSRendererConfigurationOptions option, + Object value) { + config.params.put(option, value != null ? value : option.getDefaultValue()); + } + + private void setBoolConfigParam(Configuration cfg, PSRendererConfigurationOptions option) { + setConfigParameter(option, cfg.getChild( + option.getName()).getValueAsBoolean((Boolean) option.getDefaultValue())); + } + + } + +} diff --git a/src/java/org/apache/fop/render/ps/PSRendererConfigurationOptions.java b/src/java/org/apache/fop/render/ps/PSRendererConfigurationOptions.java new file mode 100644 index 000000000..ffecbf6b4 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSRendererConfigurationOptions.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.ps; + +import org.apache.xmlgraphics.ps.PSGenerator; + +import org.apache.fop.render.RendererConfigOptions; + +/** + * An enumeration of the PostScript renderer configuration options along with their default values. + */ +public enum PSRendererConfigurationOptions implements RendererConfigOptions { + /** Indicates whether landscape pages should be rotated, default: false */ + AUTO_ROTATE_LANDSCAPE("auto-rotate-landscape", false), + /** Sets the PostScript language leven, default: {@see PSGenerator#DEFAULT_LANGUAGE_LEVEL}*/ + LANGUAGE_LEVEL("language-level", PSGenerator.DEFAULT_LANGUAGE_LEVEL), + /** Whether resources should be optimized in a post-processing run, default: false */ + OPTIMIZE_RESOURCES("optimize-resources", false), + /** Indicates whether the "safe setpagedevice" mode is active, default: false */ + SAFE_SET_PAGE_DEVICE("safe-set-page-device", false), + /** Indicates whether the PostScript output should be DSC compliant, default: true*/ + DSC_COMPLIANT("dsc-compliant", true), + RENDERING_MODE("rendering", PSRenderingMode.QUALITY); + + private final String name; + private final Object defaultValue; + + private PSRendererConfigurationOptions(String name, Object defaultValue) { + this.name = name; + this.defaultValue = defaultValue; + } + + public String getName() { + return name; + } + + public Object getDefaultValue() { + return defaultValue; + } +} diff --git a/src/java/org/apache/fop/render/ps/PSRendererConfigurator.java b/src/java/org/apache/fop/render/ps/PSRendererConfigurator.java index 00f3fc154..cec3a6547 100644 --- a/src/java/org/apache/fop/render/ps/PSRendererConfigurator.java +++ b/src/java/org/apache/fop/render/ps/PSRendererConfigurator.java @@ -19,75 +19,56 @@ package org.apache.fop.render.ps; -import java.util.Locale; - -import org.apache.avalon.framework.configuration.Configuration; - -import org.apache.xmlgraphics.ps.PSGenerator; - import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.render.PrintRendererConfigurator; -import org.apache.fop.render.Renderer; +import org.apache.fop.render.RendererConfig.RendererConfigParser; +import org.apache.fop.render.adobe.AdobeRendererConfigurator; import org.apache.fop.render.intermediate.IFDocumentHandler; import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; + /** * Postscript renderer config */ -public class PSRendererConfigurator extends PrintRendererConfigurator - implements IFDocumentHandlerConfigurator { +public class PSRendererConfigurator extends AdobeRendererConfigurator + implements IFDocumentHandlerConfigurator { /** * Default constructor * @param userAgent user agent */ - public PSRendererConfigurator(FOUserAgent userAgent) { - super(userAgent); + public PSRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser) { + super(userAgent, rendererConfigParser); } - /** - * Throws an UnsupportedOperationException. - * - * @param renderer not used - */ - public void configure(Renderer renderer) { - throw new UnsupportedOperationException(); - } - - private void configure(PSRenderingUtil psUtil, Configuration cfg) { - psUtil.setAutoRotateLandscape( - cfg.getChild("auto-rotate-landscape").getValueAsBoolean(false)); - Configuration child; - child = cfg.getChild("language-level"); - if (child != null) { - psUtil.setLanguageLevel(child.getValueAsInteger( - PSGenerator.DEFAULT_LANGUAGE_LEVEL)); + private void configure(PSRenderingUtil psUtil, PSRendererConfig psConfig) { + if (psConfig.isAutoRotateLandscape() != null) { + psUtil.setAutoRotateLandscape(psConfig.isAutoRotateLandscape()); + } + if (psConfig.getLanguageLevel() != null) { + psUtil.setLanguageLevel(psConfig.getLanguageLevel()); + } + if (psConfig.isOptimizeResources() != null) { + psUtil.setOptimizeResources(psConfig.isOptimizeResources()); } - child = cfg.getChild("optimize-resources"); - if (child != null) { - psUtil.setOptimizeResources(child.getValueAsBoolean(false)); + if (psConfig.isSafeSetPageDevice() != null) { + psUtil.setSafeSetPageDevice(psConfig.isSafeSetPageDevice()); } - child = cfg.getChild("rendering"); - if (child != null) { - psUtil.setRenderingMode(PSRenderingMode.valueOf( - child.getValue(psUtil.getRenderingMode().toString()) - .toUpperCase(Locale.ENGLISH))); + if (psConfig.isDscComplianceEnabled() != null) { + psUtil.setDSCComplianceEnabled(psConfig.isDscComplianceEnabled()); + } + if (psConfig.getRenderingMode() != null) { + psUtil.setRenderingMode(psConfig.getRenderingMode()); } - psUtil.setSafeSetPageDevice( - cfg.getChild("safe-set-page-device").getValueAsBoolean(false)); - psUtil.setDSCComplianceEnabled( - cfg.getChild("dsc-compliant").getValueAsBoolean(true)); } - /** {@inheritDoc} */ + @Override public void configure(IFDocumentHandler documentHandler) throws FOPException { - Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); - if (cfg != null) { - PSDocumentHandler psDocumentHandler = (PSDocumentHandler)documentHandler; - configure(psDocumentHandler.getPSUtil(), cfg); + PSRendererConfig psConfig = (PSRendererConfig) getRendererConfig(documentHandler); + if (psConfig != null) { + PSDocumentHandler psDocumentHandler = (PSDocumentHandler) documentHandler; + PSRenderingUtil psUtil = psDocumentHandler.getPSUtil(); + configure(psUtil, psConfig); } - } - } diff --git a/src/java/org/apache/fop/render/ps/PSRenderingUtil.java b/src/java/org/apache/fop/render/ps/PSRenderingUtil.java index b22391718..9d40c378c 100644 --- a/src/java/org/apache/fop/render/ps/PSRenderingUtil.java +++ b/src/java/org/apache/fop/render/ps/PSRenderingUtil.java @@ -33,11 +33,15 @@ import org.apache.fop.render.ps.extensions.PSCommentBefore; import org.apache.fop.render.ps.extensions.PSExtensionAttachment; import org.apache.fop.render.ps.extensions.PSSetupCode; +import static org.apache.fop.render.ps.PSRendererConfigurationOptions.AUTO_ROTATE_LANDSCAPE; +import static org.apache.fop.render.ps.PSRendererConfigurationOptions.LANGUAGE_LEVEL; +import static org.apache.fop.render.ps.PSRendererConfigurationOptions.OPTIMIZE_RESOURCES; + /** * Utility class which enables all sorts of features that are not directly connected to the * normal rendering process. */ -public class PSRenderingUtil implements PSConfigurationConstants { +public class PSRenderingUtil { private FOUserAgent userAgent; @@ -64,20 +68,21 @@ public class PSRenderingUtil implements PSConfigurationConstants { PSRenderingUtil(FOUserAgent userAgent) { this.userAgent = userAgent; + //PSRendererConfig confi = userAgent.getRendererConfig(rendererConfiguration, configCreator) initialize(); } private void initialize() { Object obj; - obj = userAgent.getRendererOptions().get(AUTO_ROTATE_LANDSCAPE); + obj = userAgent.getRendererOptions().get(AUTO_ROTATE_LANDSCAPE.getName()); if (obj != null) { setAutoRotateLandscape(booleanValueOf(obj)); } - obj = userAgent.getRendererOptions().get(LANGUAGE_LEVEL); + obj = userAgent.getRendererOptions().get(LANGUAGE_LEVEL.getName()); if (obj != null) { setLanguageLevel(intValueOf(obj)); } - obj = userAgent.getRendererOptions().get(OPTIMIZE_RESOURCES); + obj = userAgent.getRendererOptions().get(OPTIMIZE_RESOURCES.getName()); if (obj != null) { setOptimizeResources(booleanValueOf(obj)); } diff --git a/src/java/org/apache/fop/render/ps/PSSVGHandler.java b/src/java/org/apache/fop/render/ps/PSSVGHandler.java index c52f45332..e30f6391b 100644 --- a/src/java/org/apache/fop/render/ps/PSSVGHandler.java +++ b/src/java/org/apache/fop/render/ps/PSSVGHandler.java @@ -257,7 +257,7 @@ public class PSSVGHandler extends AbstractGenericSVGHandler BridgeContext ctx = new PSBridgeContext(ua, (strokeText ? null : psInfo.fontInfo), - context.getUserAgent().getFactory().getImageManager(), + context.getUserAgent().getImageManager(), context.getUserAgent().getImageSessionContext()); //Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine) diff --git a/src/java/org/apache/fop/render/ps/ResourceHandler.java b/src/java/org/apache/fop/render/ps/ResourceHandler.java index 502242c17..33a4a6dfe 100644 --- a/src/java/org/apache/fop/render/ps/ResourceHandler.java +++ b/src/java/org/apache/fop/render/ps/ResourceHandler.java @@ -283,7 +283,7 @@ public class ResourceHandler implements DSCParserConstants, PSSupportedFlavors { throws IOException { final String uri = form.getImageURI(); - ImageManager manager = userAgent.getFactory().getImageManager(); + ImageManager manager = userAgent.getImageManager(); ImageInfo info = null; try { ImageSessionContext sessionContext = userAgent.getImageSessionContext(); @@ -295,7 +295,7 @@ public class ResourceHandler implements DSCParserConstants, PSSupportedFlavors { ImageFlavor[] flavors; ImageHandlerRegistry imageHandlerRegistry - = userAgent.getFactory().getImageHandlerRegistry(); + = userAgent.getImageHandlerRegistry(); flavors = imageHandlerRegistry.getSupportedFlavors(formContext); Map hints = ImageUtil.getDefaultHints(sessionContext); diff --git a/src/java/org/apache/fop/render/rtf/RTFHandler.java b/src/java/org/apache/fop/render/rtf/RTFHandler.java index 956ea8b57..4d5de6f4a 100644 --- a/src/java/org/apache/fop/render/rtf/RTFHandler.java +++ b/src/java/org/apache/fop/render/rtf/RTFHandler.java @@ -97,7 +97,6 @@ import org.apache.fop.fo.properties.EnumLength; import org.apache.fop.fonts.FontSetup; import org.apache.fop.layoutmgr.inline.ImageLayout; import org.apache.fop.layoutmgr.table.ColumnSetup; -import org.apache.fop.render.DefaultFontResolver; import org.apache.fop.render.RendererEventProducer; import org.apache.fop.render.rtf.rtflib.exceptions.RtfException; import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfAfterContainer; @@ -169,7 +168,7 @@ public class RTFHandler extends FOEventHandler { bDefer = true; boolean base14Kerning = false; - FontSetup.setup(fontInfo, null, new DefaultFontResolver(userAgent), base14Kerning); + FontSetup.setup(fontInfo, null, userAgent.getNewURIResolver(), base14Kerning); } /** @@ -1086,7 +1085,7 @@ public class RTFHandler extends FOEventHandler { //set image data FOUserAgent userAgent = eg.getUserAgent(); - ImageManager manager = userAgent.getFactory().getImageManager(); + ImageManager manager = userAgent.getImageManager(); info = manager.getImageInfo(uri, userAgent.getImageSessionContext()); putGraphic(eg, info); @@ -1140,7 +1139,7 @@ public class RTFHandler extends FOEventHandler { ImageXMLDOM image = new ImageXMLDOM(info, doc, ns); FOUserAgent userAgent = ifo.getUserAgent(); - ImageManager manager = userAgent.getFactory().getImageManager(); + ImageManager manager = userAgent.getImageManager(); Map hints = ImageUtil.getDefaultHints(ua.getImageSessionContext()); Image converted = manager.convertImage(image, FLAVORS, hints); putGraphic(ifo, converted); @@ -1170,7 +1169,7 @@ public class RTFHandler extends FOEventHandler { throws IOException { try { FOUserAgent userAgent = abstractGraphic.getUserAgent(); - ImageManager manager = userAgent.getFactory().getImageManager(); + ImageManager manager = userAgent.getImageManager(); ImageSessionContext sessionContext = userAgent.getImageSessionContext(); Map hints = ImageUtil.getDefaultHints(sessionContext); Image image = manager.getImage(info, FLAVORS, hints, sessionContext); @@ -1701,7 +1700,7 @@ public class RTFHandler extends FOEventHandler { Region regionBefore = pagemaster.getRegion(Constants.FO_REGION_BEFORE); if (regionBefore != null) { - FONode staticBefore = (FONode) pageSequence.getFlowMap().get( + FONode staticBefore = pageSequence.getFlowMap().get( regionBefore.getRegionName()); if (staticBefore != null) { recurseFONode(staticBefore); @@ -1709,7 +1708,7 @@ public class RTFHandler extends FOEventHandler { } Region regionAfter = pagemaster.getRegion(Constants.FO_REGION_AFTER); if (regionAfter != null) { - FONode staticAfter = (FONode) pageSequence.getFlowMap().get( + FONode staticAfter = pageSequence.getFlowMap().get( regionAfter.getRegionName()); if (staticAfter != null) { recurseFONode(staticAfter); diff --git a/src/java/org/apache/fop/render/txt/TXTRendererConfigurator.java b/src/java/org/apache/fop/render/txt/TXTRendererConfigurator.java index 59c3bf5e6..8532873dd 100644 --- a/src/java/org/apache/fop/render/txt/TXTRendererConfigurator.java +++ b/src/java/org/apache/fop/render/txt/TXTRendererConfigurator.java @@ -19,24 +19,23 @@ 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; +import org.apache.fop.render.RendererConfig.RendererConfigParser; +import org.apache.fop.render.adobe.AdobeRendererConfigurator; /** * TXT Renderer configurator */ -public class TXTRendererConfigurator extends PrintRendererConfigurator { +public class TXTRendererConfigurator extends AdobeRendererConfigurator { /** * Default constructor * @param userAgent user agent */ - public TXTRendererConfigurator(FOUserAgent userAgent) { - super(userAgent); + public TXTRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser) { + super(userAgent, rendererConfigParser); } /** @@ -45,10 +44,11 @@ public class TXTRendererConfigurator extends PrintRendererConfigurator { * @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)); + TxtRendererConfig config = (TxtRendererConfig) getRendererConfig(renderer); + if (config != null) { + TXTRenderer txtRenderer = (TXTRenderer) renderer; + txtRenderer.setEncoding(config.getEncoding()); } } + } diff --git a/src/java/org/apache/fop/render/txt/TXTRendererMaker.java b/src/java/org/apache/fop/render/txt/TXTRendererMaker.java index 740866e0c..150338120 100644 --- a/src/java/org/apache/fop/render/txt/TXTRendererMaker.java +++ b/src/java/org/apache/fop/render/txt/TXTRendererMaker.java @@ -19,11 +19,12 @@ package org.apache.fop.render.txt; +import org.apache.fop.apps.FOPException; 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; +import org.apache.fop.render.txt.TxtRendererConfig.TxtRendererConfigParser; /** * RendererMaker for the Plain Text Renderer. @@ -32,22 +33,22 @@ public class TXTRendererMaker extends AbstractRendererMaker { private static final String[] MIMES = new String[] {MimeConstants.MIME_PLAIN_TEXT}; - /**{@inheritDoc} */ + @Override public Renderer makeRenderer(FOUserAgent userAgent) { return new TXTRenderer(userAgent); } - /**{@inheritDoc} */ - public RendererConfigurator getConfigurator(FOUserAgent userAgent) { - return new TXTRendererConfigurator(userAgent); + @Override + public void configureRenderer(FOUserAgent userAgent, Renderer renderer) throws FOPException { + new TXTRendererConfigurator(userAgent, new TxtRendererConfigParser()).configure(renderer); } - /** {@inheritDoc} */ + @Override public boolean needsOutputStream() { return true; } - /** {@inheritDoc} */ + @Override public String[] getSupportedMimeTypes() { return MIMES; } diff --git a/src/java/org/apache/fop/render/txt/TxtRendererConfig.java b/src/java/org/apache/fop/render/txt/TxtRendererConfig.java new file mode 100644 index 000000000..c0c819206 --- /dev/null +++ b/src/java/org/apache/fop/render/txt/TxtRendererConfig.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.txt; + +import java.util.EnumMap; + +import org.apache.avalon.framework.configuration.Configuration; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.MimeConstants; +import org.apache.fop.fonts.DefaultFontConfig; +import org.apache.fop.fonts.DefaultFontConfig.DefaultFontConfigParser; +import org.apache.fop.render.RendererConfig; +import org.apache.fop.render.RendererConfigOptions; + +public class TxtRendererConfig implements RendererConfig { + + public enum TxtRendererConfigOptions implements RendererConfigOptions { + ENCODING("encoding", "UTF-8"); + + private final String name; + private final Object defaultValue; + + private TxtRendererConfigOptions(String name, Object defaultValue) { + this.name = name; + this.defaultValue = defaultValue; + } + + public String getName() { + return name; + } + + public Object getDefaultValue() { + return defaultValue; + } + } + + private final EnumMap<TxtRendererConfigOptions, Object> params + = new EnumMap<TxtRendererConfigOptions, Object>(TxtRendererConfigOptions.class); + + private final DefaultFontConfig fontConfig; + + private TxtRendererConfig(DefaultFontConfig fontConfig) { + this.fontConfig = fontConfig; + } + + public DefaultFontConfig getFontInfoConfig() { + return fontConfig; + } + + public String getEncoding() { + return (String) params.get(TxtRendererConfigOptions.ENCODING); + } + + public static final class TxtRendererConfigParser implements RendererConfigParser { + + public TxtRendererConfig build(FOUserAgent userAgent, Configuration cfg) throws FOPException { + TxtRendererConfig config = new TxtRendererConfig(new DefaultFontConfigParser().parse(cfg, + userAgent.validateStrictly())); + if (cfg != null) { + TxtRendererConfigOptions option = TxtRendererConfigOptions.ENCODING; + String value = cfg.getChild(option.getName(), true).getValue(null); + config.params.put(option, value != null ? value : option.getDefaultValue()); + } + return config; + } + + public String getMimeType() { + return MimeConstants.MIME_PLAIN_TEXT; + } + } + +} diff --git a/src/java/org/apache/fop/render/xml/XMLRendererMaker.java b/src/java/org/apache/fop/render/xml/XMLRendererMaker.java index f54c74b32..f0cd3a850 100644 --- a/src/java/org/apache/fop/render/xml/XMLRendererMaker.java +++ b/src/java/org/apache/fop/render/xml/XMLRendererMaker.java @@ -19,12 +19,15 @@ package org.apache.fop.render.xml; +import java.util.List; + +import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; +import org.apache.fop.fonts.FontCollection; 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. @@ -33,22 +36,28 @@ public class XMLRendererMaker extends AbstractRendererMaker { private static final String[] MIMES = new String[] {MimeConstants.MIME_FOP_AREA_TREE}; - /**{@inheritDoc} */ + @Override public Renderer makeRenderer(FOUserAgent userAgent) { return new XMLRenderer(userAgent); } - /**{@inheritDoc} */ - public RendererConfigurator getConfigurator(FOUserAgent userAgent) { - return new PrintRendererConfigurator(userAgent); + @Override + public void configureRenderer(FOUserAgent userAgent, Renderer renderer) throws FOPException { + // TODO what constructor params? + new PrintRendererConfigurator(userAgent, null) { + @Override + protected List<FontCollection> getDefaultFontCollection() { + throw new UnsupportedOperationException(); + } + } .configure(renderer); } - /** {@inheritDoc} */ + @Override public boolean needsOutputStream() { return true; } - /** {@inheritDoc} */ + @Override public String[] getSupportedMimeTypes() { return MIMES; } diff --git a/src/java/org/apache/fop/servlet/FopServlet.java b/src/java/org/apache/fop/servlet/FopServlet.java index cfe7f6cbf..57c5a295b 100644 --- a/src/java/org/apache/fop/servlet/FopServlet.java +++ b/src/java/org/apache/fop/servlet/FopServlet.java @@ -21,7 +21,11 @@ package org.apache.fop.servlet; import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.io.PrintWriter; +import java.net.URI; +import java.net.URL; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -42,7 +46,10 @@ import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.Fop; import org.apache.fop.apps.FopFactory; +import org.apache.fop.apps.FopFactoryBuilder; import org.apache.fop.apps.MimeConstants; +import org.apache.fop.apps.io.Resource; +import org.apache.fop.apps.io.ResourceResolver; /** * Example servlet to generate a PDF from a servlet. @@ -91,16 +98,27 @@ public class FopServlet extends HttpServlet { this.transFactory = TransformerFactory.newInstance(); this.transFactory.setURIResolver(this.uriResolver); //Configure FopFactory as desired - this.fopFactory = FopFactory.newInstance(); - this.fopFactory.setURIResolver(this.uriResolver); - configureFopFactory(); + // TODO: Double check this behaves properly!! + ResourceResolver resolver = new ResourceResolver() { + public OutputStream getOutputStream(URI uri) throws IOException { + URL url = getServletContext().getResource(uri.toASCIIString()); + return url.openConnection().getOutputStream(); + } + + public Resource getResource(URI uri) throws IOException { + return new Resource(getServletContext().getResourceAsStream(uri.toASCIIString())); + } + }; + FopFactoryBuilder builder = new FopFactoryBuilder(new File(".").toURI(), resolver); + configureFopFactory(builder); + fopFactory = builder.build(); } /** * This method is called right after the FopFactory is instantiated and can be overridden * by subclasses to perform additional configuration. */ - protected void configureFopFactory() { + protected void configureFopFactory(FopFactoryBuilder builder) { //Subclass and override this method to perform additional configuration } diff --git a/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java b/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java index 954291a57..844751db7 100644 --- a/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java +++ b/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java @@ -25,17 +25,20 @@ 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.CustomFontCollection; -import org.apache.fop.fonts.FontCollection; +import org.apache.fop.apps.io.DefaultResourceResolver; +import org.apache.fop.apps.io.URIResolverWrapper; +import org.apache.fop.fonts.DefaultFontConfig; +import org.apache.fop.fonts.DefaultFontConfigurator; +import org.apache.fop.fonts.EmbedFontInfo; +import org.apache.fop.fonts.FontCacheManagerFactory; +import org.apache.fop.fonts.FontDetectorFactory; 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.FontManagerConfigurator; -import org.apache.fop.fonts.FontResolver; -import org.apache.fop.fonts.base14.Base14FontCollection; +import org.apache.fop.fonts.FontSetup; import org.apache.fop.pdf.PDFDocument; -import org.apache.fop.render.pdf.PDFRendererConfigurator; +import org.apache.fop.render.pdf.PDFRendererConfig; +import org.apache.fop.render.pdf.PDFRendererConfig.PDFRendererConfigParser; /** * Configurator class for PDFDocumentGraphics2D. @@ -53,10 +56,13 @@ public class PDFDocumentGraphics2DConfigurator { boolean useComplexScriptFeatures ) throws ConfigurationException { PDFDocument pdfDoc = graphics.getPDFDocument(); - - //Filter map - pdfDoc.setFilterMap( - PDFRendererConfigurator.buildFilterMapFromConfiguration(cfg)); + try { + //Filter map + PDFRendererConfig pdfConfig = new PDFRendererConfigParser().build(null, cfg); + pdfDoc.setFilterMap(pdfConfig.getFilterMap()); + } catch (FOPException e) { + throw new RuntimeException(e); + } //Fonts try { @@ -78,30 +84,28 @@ public class PDFDocumentGraphics2DConfigurator { throws FOPException { FontInfo fontInfo = new FontInfo(); final boolean strict = false; - FontResolver fontResolver = FontManager.createMinimalFontResolver(useComplexScriptFeatures); - //TODO The following could be optimized by retaining the FontManager somewhere - FontManager fontManager = new FontManager(); if (cfg != null) { - FontManagerConfigurator fmConfigurator = new FontManagerConfigurator(cfg); - fmConfigurator.configure(fontManager, strict); - } + //TODO Wire in the FontEventListener + URIResolverWrapper resolver = DefaultResourceResolver.createDefaultWrapper(); + //TODO The following could be optimized by retaining the FontManager somewhere + FontManager fontManager = new FontManager(resolver, FontDetectorFactory.createDefault(), + FontCacheManagerFactory.createDefault()); - List fontCollections = new java.util.ArrayList(); - fontCollections.add(new Base14FontCollection(fontManager.isBase14KerningEnabled())); + //TODO Make use of fontBaseURL, font substitution and referencing configuration + //Requires a change to the expected configuration layout - if (cfg != null) { - //TODO Wire in the FontEventListener - FontEventListener listener = null; //new FontEventAdapter(eventBroadcaster); - FontInfoConfigurator fontInfoConfigurator - = new FontInfoConfigurator(cfg, fontManager, fontResolver, listener, strict); - List/*<EmbedFontInfo>*/ fontInfoList = new java.util.ArrayList/*<EmbedFontInfo>*/(); - fontInfoConfigurator.configure(fontInfoList); - fontCollections.add(new CustomFontCollection(fontResolver, fontInfoList, - fontResolver.isComplexScriptFeaturesEnabled())); + final FontEventListener listener = null; + DefaultFontConfig.DefaultFontConfigParser parser + = new DefaultFontConfig.DefaultFontConfigParser(); + DefaultFontConfig fontInfoConfig = parser.parse(cfg, strict); + DefaultFontConfigurator fontInfoConfigurator + = new DefaultFontConfigurator(fontManager, listener, strict); + List<EmbedFontInfo> fontInfoList = fontInfoConfigurator.configure(fontInfoConfig); + fontManager.saveCache(); + FontSetup.setup(fontInfo, fontInfoList, resolver, useComplexScriptFeatures); + } else { + FontSetup.setup(fontInfo, useComplexScriptFeatures); } - fontManager.setup(fontInfo, - (FontCollection[])fontCollections.toArray( - new FontCollection[fontCollections.size()])); return fontInfo; } diff --git a/src/java/org/apache/fop/svg/PDFTranscoder.java b/src/java/org/apache/fop/svg/PDFTranscoder.java index e222a08dd..30b787a77 100644 --- a/src/java/org/apache/fop/svg/PDFTranscoder.java +++ b/src/java/org/apache/fop/svg/PDFTranscoder.java @@ -133,7 +133,7 @@ public class PDFTranscoder extends AbstractFOPTranscoder { } } catch (Exception e) { throw new TranscoderException( - "Error while setting up PDFDocumentGraphics2D", e); + "Error while setting up PDFDocumentGraphics2D", e); } super.transcode(document, uri, output); diff --git a/src/java/org/apache/fop/tools/TestConverter.java b/src/java/org/apache/fop/tools/TestConverter.java index f453fecdf..3ce3eff35 100644 --- a/src/java/org/apache/fop/tools/TestConverter.java +++ b/src/java/org/apache/fop/tools/TestConverter.java @@ -21,6 +21,7 @@ package org.apache.fop.tools; import java.io.File; import java.io.OutputStream; +import java.net.URI; import java.util.Map; import javax.xml.parsers.DocumentBuilder; @@ -50,9 +51,6 @@ import org.apache.fop.tools.anttasks.FileCompare; */ public class TestConverter { - // configure fopFactory as desired - private FopFactory fopFactory = FopFactory.newInstance(); - private boolean failOnly = false; private String outputFormat = MimeConstants.MIME_FOP_AREA_TREE; private File destdir; @@ -273,24 +271,17 @@ public class TestConverter { } try { File xmlFile = new File(baseDir + "/" + xml); - String baseURL = null; - try { - baseURL = xmlFile.getParentFile().toURI().toURL().toExternalForm(); - } catch (Exception e) { - logger.error("Error setting base directory"); - } + URI baseUri = xmlFile.getParentFile().toURI(); InputHandler inputHandler = null; if (xsl == null) { inputHandler = new InputHandler(xmlFile); } else { - inputHandler = new InputHandler(xmlFile, - new File(baseDir + "/" - + xsl), null); + inputHandler = new InputHandler(xmlFile, new File(baseDir + "/" + xsl), null); } + FopFactory fopFactory = FopFactory.newInstance(baseUri); FOUserAgent userAgent = fopFactory.newFOUserAgent(); - userAgent.setBaseURL(baseURL); userAgent.getRendererOptions().put("fineDetail", new Boolean(false)); userAgent.getRendererOptions().put("consistentOutput", new Boolean(true)); diff --git a/src/java/org/apache/fop/tools/anttasks/Fop.java b/src/java/org/apache/fop/tools/anttasks/Fop.java index 3cc93bafa..5e6c5141e 100644 --- a/src/java/org/apache/fop/tools/anttasks/Fop.java +++ b/src/java/org/apache/fop/tools/anttasks/Fop.java @@ -24,7 +24,7 @@ import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; import java.io.OutputStream; -import java.net.MalformedURLException; +import java.net.URI; import java.util.List; import java.util.Vector; @@ -41,7 +41,9 @@ import org.apache.tools.ant.util.GlobPatternMapper; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.FopConfParser; import org.apache.fop.apps.FopFactory; +import org.apache.fop.apps.FopFactoryBuilder; import org.apache.fop.apps.MimeConstants; import org.apache.fop.cli.InputHandler; @@ -379,10 +381,10 @@ public class Fop extends Task { class FOPTaskStarter { // configure fopFactory as desired - private FopFactory fopFactory = FopFactory.newInstance(); + private final FopFactory fopFactory; private Fop task; - private String baseURL = null; + private URI baseUri; /** * logging instance @@ -408,8 +410,21 @@ class FOPTaskStarter { FOPTaskStarter(Fop task) throws SAXException, IOException { this.task = task; + //Set base directory + if (task.getBasedir() != null) { + this.baseUri = task.getBasedir().toURI(); + } else { + if (task.getFofile() != null) { + this.baseUri = task.getFofile().getParentFile().toURI(); + } + } if (task.getUserconfig() != null) { - fopFactory.setUserConfig(task.getUserconfig()); + FopFactoryBuilder confBuilder = new FopConfParser( + task.getUserconfig()).getFopFactoryBuilder(); + confBuilder.setBaseURI(baseUri); + fopFactory = confBuilder.build(); + } else { + fopFactory = FopFactory.newInstance(baseUri); } } @@ -488,25 +503,7 @@ class FOPTaskStarter { } public void run() throws FOPException { - //Set base directory - if (task.getBasedir() != null) { - try { - this.baseURL = task.getBasedir().toURI().toURL().toExternalForm(); - } catch (MalformedURLException mfue) { - logger.error("Error creating base URL from base directory", mfue); - } - } else { - try { - if (task.getFofile() != null) { - this.baseURL = task.getFofile().getParentFile().toURI().toURL() - .toExternalForm(); - } - } catch (MalformedURLException mfue) { - logger.error("Error creating base URL from XSL-FO input file", mfue); - } - } - - task.log("Using base URL: " + baseURL, Project.MSG_DEBUG); + task.log("Using base URI: " + baseUri, Project.MSG_DEBUG); String outputFormat = normalizeOutputFormat(task.getFormat()); String newExtension = determineExtension(outputFormat); @@ -598,12 +595,10 @@ class FOPTaskStarter { } try { if (task.getRelativebase()) { - this.baseURL = f.getParentFile().toURI().toURL() - .toExternalForm(); + this.baseUri = f.getParentFile().toURI(); } - if (this.baseURL == null) { - this.baseURL = fs.getDir(task.getProject()).toURI().toURL() - .toExternalForm(); + if (this.baseUri == null) { + this.baseUri = fs.getDir(task.getProject()).toURI(); } } catch (Exception e) { @@ -649,7 +644,6 @@ class FOPTaskStarter { boolean success = false; try { FOUserAgent userAgent = fopFactory.newFOUserAgent(); - userAgent.setBaseURL(this.baseURL); inputHandler.renderTo(userAgent, outputFormat, out); success = true; } catch (Exception ex) { diff --git a/src/java/org/apache/fop/tools/fontlist/FontListGenerator.java b/src/java/org/apache/fop/tools/fontlist/FontListGenerator.java index ce44eee19..0f3f737f7 100644 --- a/src/java/org/apache/fop/tools/fontlist/FontListGenerator.java +++ b/src/java/org/apache/fop/tools/fontlist/FontListGenerator.java @@ -68,7 +68,8 @@ public class FontListGenerator { IFDocumentHandlerConfigurator configurator = documentHandler.getConfigurator(); FontInfo fontInfo = new FontInfo(); - configurator.setupFontInfo(documentHandler, fontInfo); + configurator.setupFontInfo(documentHandler.getMimeType(), fontInfo); + documentHandler.setFontInfo(fontInfo); return fontInfo; } diff --git a/src/java/org/apache/fop/tools/fontlist/FontListMain.java b/src/java/org/apache/fop/tools/fontlist/FontListMain.java index b9b01f706..659f7ccac 100644 --- a/src/java/org/apache/fop/tools/fontlist/FontListMain.java +++ b/src/java/org/apache/fop/tools/fontlist/FontListMain.java @@ -64,7 +64,7 @@ public final class FontListMain { private static final int GENERATE_FO = 2; private static final int GENERATE_RENDERED = 3; - private FopFactory fopFactory = FopFactory.newInstance(); + private FopFactory fopFactory; private File configFile; private File outputFile; @@ -78,7 +78,9 @@ public final class FontListMain { private void prepare() throws SAXException, IOException { if (this.configFile != null) { - fopFactory.setUserConfig(this.configFile); + fopFactory = FopFactory.newInstance(configFile); + } else { + fopFactory = FopFactory.newInstance(new File(".").toURI()); } } diff --git a/src/java/org/apache/fop/util/ColorSpaceCache.java b/src/java/org/apache/fop/util/ColorSpaceCache.java index 246477f6b..e7c8f04b5 100644 --- a/src/java/org/apache/fop/util/ColorSpaceCache.java +++ b/src/java/org/apache/fop/util/ColorSpaceCache.java @@ -21,6 +21,8 @@ package org.apache.fop.util; import java.awt.color.ColorSpace; import java.awt.color.ICC_Profile; +import java.net.URI; +import java.net.URISyntaxException; import java.util.Collections; import java.util.Map; @@ -35,6 +37,8 @@ import org.apache.xmlgraphics.java2d.color.ICCColorSpaceWithIntent; import org.apache.xmlgraphics.java2d.color.RenderingIntent; import org.apache.xmlgraphics.java2d.color.profile.ColorProfileUtil; +import org.apache.fop.apps.io.URIResolverWrapper; + /** * Map with cached ICC based ColorSpace objects. */ @@ -72,6 +76,13 @@ public class ColorSpaceCache { public ColorSpace get(String profileName, String base, String iccProfileSrc, RenderingIntent renderingIntent) { String key = profileName + ":" + base + iccProfileSrc; + // TODO: This stuff needs some TLC, fix it!! + try { + URI uri = URIResolverWrapper.getBaseURI(base); + key = uri.resolve(URIResolverWrapper.cleanURI(iccProfileSrc)).toASCIIString(); + } catch (URISyntaxException e) { + // TODO: handle this + } ColorSpace colorSpace = null; if (!colorSpaceMap.containsKey(key)) { try { diff --git a/src/java/org/apache/fop/util/ColorUtil.java b/src/java/org/apache/fop/util/ColorUtil.java index 09e9dd50b..c03130f2d 100644 --- a/src/java/org/apache/fop/util/ColorUtil.java +++ b/src/java/org/apache/fop/util/ColorUtil.java @@ -404,10 +404,10 @@ public final class ColorUtil { if (foUserAgent != null && iccProfileSrc != null) { RenderingIntent renderingIntent = RenderingIntent.AUTO; //TODO connect to fo:color-profile/@rendering-intent - colorSpace = foUserAgent.getFactory().getColorSpaceCache().get( + colorSpace = foUserAgent.getColorSpaceCache().get( iccProfileName, - foUserAgent.getBaseURL(), iccProfileSrc, - renderingIntent); + foUserAgent.getNewURIResolver().getBaseURI().toASCIIString(), + iccProfileSrc, renderingIntent); } if (colorSpace != null) { // ColorSpace is available @@ -488,10 +488,10 @@ public final class ColorUtil { if (foUserAgent != null && iccProfileSrc != null) { RenderingIntent renderingIntent = RenderingIntent.AUTO; //TODO connect to fo:color-profile/@rendering-intent - colorSpace = (ICC_ColorSpace)foUserAgent.getFactory().getColorSpaceCache().get( + colorSpace = (ICC_ColorSpace)foUserAgent.getColorSpaceCache().get( iccProfileName, - foUserAgent.getBaseURL(), iccProfileSrc, - renderingIntent); + foUserAgent.getNewURIResolver().getBaseURI().toASCIIString(), + iccProfileSrc, renderingIntent); } if (colorSpace != null) { ICC_Profile profile = colorSpace.getProfile(); |