/* * 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; // Java import java.io.File; import java.net.MalformedURLException; import java.util.Date; import java.util.Map; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; import javax.xml.transform.URIResolver; 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.ImageSessionContext; import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext; import org.apache.xmlgraphics.util.UnitConv; 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.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.FOEventHandler; import org.apache.fop.fonts.FontManager; import org.apache.fop.render.Renderer; import org.apache.fop.render.RendererFactory; import org.apache.fop.render.XMLHandlerRegistry; import org.apache.fop.render.intermediate.IFDocumentHandler; /** * This is the user agent for FOP. * It is the entity through which you can interact with the XSL-FO processing and is * used by the processing to obtain user configurable options. *

* Renderer specific extensions (that do not produce normal areas on * the output) will be done like so: *
* The extension will create an area, custom if necessary *
* this area will be added to the user agent with a key *
* the renderer will know keys for particular extensions *
* eg. bookmarks will be held in a special hierarchical area representing * the title and bookmark structure *
* These areas may contain resolvable areas that will be processed * with other resolvable areas */ 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; /** A user settable URI Resolver */ private URIResolver uriResolver = null; private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION; private Map rendererOptions = new java.util.HashMap(); private File outputFile = null; private IFDocumentHandler documentHandlerOverride = null; private Renderer rendererOverride = null; private FOEventHandler foEventHandlerOverride = null; private boolean locatorEnabled = true; // true by default (for error messages). private boolean conserveMemoryPolicy = false; private EventBroadcaster eventBroadcaster = new FOPEventBroadcaster(); private StructureTreeEventHandler structureTreeEventHandler = DummyStructureTreeEventHandler.INSTANCE; /** Producer: Metadata element for the system/software that produces * the document. (Some renderers can store this in the document.) */ protected String producer = "Apache FOP Version " + Version.getVersion(); /** Creator: Metadata element for the user that created the * document. (Some renderers can store this in the document.) */ protected String creator = null; /** Creation Date: Override of the date the document was created. * (Some renderers can store this in the document.) */ protected Date creationDate = null; /** Author of the content of the document. */ protected String author = null; /** Title of the document. */ protected String title = null; /** Subject of the document. */ protected String subject = null; /** Set of keywords applicable to this document. */ protected String keywords = null; private ImageSessionContext imageSessionContext = new AbstractImageSessionContext() { public ImageContext getParentContext() { return getFactory(); } public float getTargetResolution() { return FOUserAgent.this.getTargetResolution(); } public Source resolveURI(String uri) { return FOUserAgent.this.resolveURI(uri); } }; /** * Main constructor. This constructor should not be called directly. Please use the * methods from FopFactory to construct FOUserAgent instances! * @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"); } this.factory = factory; setBaseURL(factory.getBaseURL()); setTargetResolution(factory.getTargetResolution()); setAccessibility(factory.isAccessibilityEnabled()); } /** @return the associated FopFactory instance */ public FopFactory getFactory() { return this.factory; } // ---------------------------------------------- rendering-run dependent stuff /** * Sets an explicit document handler to use which overrides the one that would be * selected by default. * @param documentHandler the document handler instance to use */ public void setDocumentHandlerOverride(IFDocumentHandler documentHandler) { if (isAccessibilityEnabled()) { setStructureTreeEventHandler(documentHandler.getStructureTreeEventHandler()); } this.documentHandlerOverride = documentHandler; } /** * Returns the overriding {@link IFDocumentHandler} instance, if any. * @return the overriding document handler or null */ public IFDocumentHandler getDocumentHandlerOverride() { return this.documentHandlerOverride; } /** * Sets an explicit renderer to use which overrides the one defined by the * render type setting. * @param renderer the Renderer instance to use */ public void setRendererOverride(Renderer renderer) { this.rendererOverride = renderer; } /** * Returns the overriding Renderer instance, if any. * @return the overriding Renderer or null */ public Renderer getRendererOverride() { return rendererOverride; } /** * Sets an explicit FOEventHandler instance which overrides the one * defined by the render type setting. * @param handler the FOEventHandler instance */ public void setFOEventHandlerOverride(FOEventHandler handler) { this.foEventHandlerOverride = handler; } /** * Returns the overriding FOEventHandler instance, if any. * @return the overriding FOEventHandler or null */ public FOEventHandler getFOEventHandlerOverride() { return this.foEventHandlerOverride; } /** * Sets the producer of the document. * @param producer source of document */ public void setProducer(String producer) { this.producer = producer; } /** * Returns the producer of the document * @return producer name */ public String getProducer() { return producer; } /** * Sets the creator of the document. * @param creator of document */ public void setCreator(String creator) { this.creator = creator; } /** * Returns the creator of the document * @return creator name */ public String getCreator() { return creator; } /** * Sets the creation date of the document. * @param creationDate date of document */ public void setCreationDate(Date creationDate) { this.creationDate = creationDate; } /** * Returns the creation date of the document * @return creation date of document */ public Date getCreationDate() { return creationDate; } /** * Sets the author of the document. * @param author of document */ public void setAuthor(String author) { this.author = author; } /** * Returns the author of the document * @return author name */ public String getAuthor() { return author; } /** * Sets the title of the document. This will override any title coming from * an fo:title element. * @param title of document */ public void setTitle(String title) { this.title = title; } /** * Returns the title of the document * @return title name */ public String getTitle() { return title; } /** * Sets the subject of the document. * @param subject of document */ public void setSubject(String subject) { this.subject = subject; } /** * Returns the subject of the document * @return the subject */ public String getSubject() { return subject; } /** * Sets the keywords for the document. * @param keywords for the document */ public void setKeywords(String keywords) { this.keywords = keywords; } /** * Returns the keywords for the document * @return the keywords */ public String getKeywords() { return keywords; } /** * Returns the renderer options * @return renderer options */ public Map getRendererOptions() { return rendererOptions; } /** * 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; } /** * Attempts to resolve the given URI. * Will use the configured resolver and if not successful fall back * to the default resolver. * @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 */ 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); } } if (source == null) { // URI Resolver not configured or returned null, use default resolver from the factory source = getFactory().resolveURI(href, base); } return source; } /** * Sets the output File. * @param f the output File */ public void setOutputFile(File f) { this.outputFile = f; } /** * Gets the output File. * @return the output File */ public File getOutputFile() { return outputFile; } /** * Returns the conversion factor from pixel units to millimeters. This * depends on the desired target resolution. * @return float conversion factor * @see #getTargetResolution() */ public float getTargetPixelUnitToMillimeter() { return UnitConv.IN2MM / this.targetResolution; } /** @return the resolution for resolution-dependant output */ public float getTargetResolution() { return this.targetResolution; } /** * Sets the target resolution in dpi. This value defines the target resolution of * bitmap images generated by the bitmap renderers (such as the TIFF renderer) and of * bitmap images generated by filter effects in Apache Batik. * @param dpi resolution in dpi */ public void setTargetResolution(float dpi) { this.targetResolution = dpi; if (log.isDebugEnabled()) { log.debug("target-resolution set to: " + targetResolution + "dpi (px2mm=" + getTargetPixelUnitToMillimeter() + ")"); } } /** * Sets the target resolution in dpi. This value defines the target resolution of * bitmap images generated by the bitmap renderers (such as the TIFF renderer) and of * bitmap images generated by filter effects in Apache Batik. * @param dpi resolution in dpi */ public void setTargetResolution(int dpi) { setTargetResolution((float)dpi); } /** * Returns the image session context for the image package. * @return the ImageSessionContext instance for this rendering run */ public ImageSessionContext getImageSessionContext() { return this.imageSessionContext; } // ---------------------------------------------- environment-level stuff // (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 the resolution for resolution-dependant input */ public float getSourceResolution() { return getFactory().getSourceResolution(); } /** * Gets the default page-height to use as fallback, * in case page-height="auto" * * @return the page-height, as a String * @see FopFactory#getPageHeight() */ public String getPageHeight() { return getFactory().getPageHeight(); } /** * Gets the default page-width to use as fallback, * in case page-width="auto" * * @return the page-width, as a String * @see FopFactory#getPageWidth() */ public String getPageWidth() { return getFactory().getPageWidth(); } /** * Returns whether FOP is strictly validating input XSL * @return true of strict validation turned on, false otherwise * @see FopFactory#validateStrictly() */ public boolean validateStrictly() { return getFactory().validateStrictly(); } /** * @return true if the indent inheritance should be broken when crossing reference area * boundaries (for more info, see the javadoc for the relative member variable) * @see FopFactory#isBreakIndentInheritanceOnReferenceAreaBoundary() */ public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() { return getFactory().isBreakIndentInheritanceOnReferenceAreaBoundary(); } /** * @return the RendererFactory */ public RendererFactory getRendererFactory() { return getFactory().getRendererFactory(); } /** * @return the XML handler registry */ public XMLHandlerRegistry getXMLHandlerRegistry() { return getFactory().getXMLHandlerRegistry(); } /** * Controls the use of SAXLocators to provide location information in error * messages. * * @param enableLocator false if SAX Locators should be disabled */ public void setLocatorEnabled(boolean enableLocator) { locatorEnabled = enableLocator; } /** * Checks if the use of Locators is enabled * @return true if context information should be stored on each node in the FO tree. */ public boolean isLocatorEnabled() { return locatorEnabled; } /** * Returns the event broadcaster that control events sent inside a processing run. Clients * can register event listeners with the event broadcaster to listen for events that occur * while a document is being processed. * @return the event broadcaster. */ public EventBroadcaster getEventBroadcaster() { return this.eventBroadcaster; } private class FOPEventBroadcaster extends DefaultEventBroadcaster { private EventListener rootListener; public FOPEventBroadcaster() { //Install a temporary event listener that catches the first event to //do some initialization. this.rootListener = new EventListener() { public void processEvent(Event event) { if (!listeners.hasEventListeners()) { //Backwards-compatibility: Make sure at least the LoggingEventListener is //plugged in so no events are just silently swallowed. addEventListener( new LoggingEventListener(LogFactory.getLog(FOUserAgent.class))); } //Replace with final event listener rootListener = new FOPEventListenerProxy( listeners, FOUserAgent.this); rootListener.processEvent(event); } }; } /** {@inheritDoc} */ public void broadcastEvent(Event event) { rootListener.processEvent(event); } } /** * Check whether memory-conservation is enabled. * * @return true if FOP is to conserve as much as possible */ public boolean isConserveMemoryPolicyEnabled() { return this.conserveMemoryPolicy; } /** * Control whether memory-conservation should be enabled * * @param conserveMemoryPolicy the cachingEnabled to set */ public void setConserveMemoryPolicy(boolean conserveMemoryPolicy) { this.conserveMemoryPolicy = conserveMemoryPolicy; } /** * Activates accessibility (for output formats that support it). * * @param accessibility true to enable accessibility support */ public void setAccessibility(boolean accessibility) { if (accessibility) { getRendererOptions().put(Accessibility.ACCESSIBILITY, Boolean.TRUE); } } /** * Check if accessibility is enabled. * @return true if accessibility is enabled */ public boolean isAccessibilityEnabled() { Boolean enabled = (Boolean)this.getRendererOptions().get(Accessibility.ACCESSIBILITY); if (enabled != null) { return enabled.booleanValue(); } else { return false; } } /** * Sets the document's structure tree event handler, for use by accessible * output formats. * * @param structureTreeEventHandler The structure tree event handler to set */ public void setStructureTreeEventHandler(StructureTreeEventHandler structureTreeEventHandler) { this.structureTreeEventHandler = structureTreeEventHandler; } /** * Returns the document's structure tree event handler, for use by * accessible output formats. * * @return The structure tree event handler */ public StructureTreeEventHandler getStructureTreeEventHandler() { return this.structureTreeEventHandler; } }