diff options
author | Peter Hancock <phancock@apache.org> | 2012-07-03 16:01:48 +0000 |
---|---|---|
committer | Peter Hancock <phancock@apache.org> | 2012-07-03 16:01:48 +0000 |
commit | fb48ed8bc5d5d14b7a1086486378c640cd8b56f8 (patch) | |
tree | 206b64290514dbc4fa622c8758153f99fbf2d58c /src/java/org/apache | |
parent | 3e31e071ea47f37ef7f8749b324dfdfe76745d18 (diff) | |
parent | fdb801262c8abbf13b12d9df5900a5c4627dda12 (diff) | |
download | xmlgraphics-fop-fb48ed8bc5d5d14b7a1086486378c640cd8b56f8.tar.gz xmlgraphics-fop-fb48ed8bc5d5d14b7a1086486378c640cd8b56f8.zip |
Merged trunk@1356765
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_RoundedCorners@1356804 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache')
209 files changed, 7878 insertions, 5500 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/AFPDitheredRectanglePainter.java b/src/java/org/apache/fop/afp/AFPDitheredRectanglePainter.java index d1c693afb..a953718bd 100644 --- a/src/java/org/apache/fop/afp/AFPDitheredRectanglePainter.java +++ b/src/java/org/apache/fop/afp/AFPDitheredRectanglePainter.java @@ -28,6 +28,7 @@ import java.io.IOException; import org.apache.xmlgraphics.image.loader.ImageSize; import org.apache.xmlgraphics.util.MimeConstants; +import org.apache.fop.afp.AFPResourceLevel.ResourceType; import org.apache.fop.afp.modca.triplets.MappingOptionTriplet; import org.apache.fop.util.bitmap.DitherUtil; @@ -66,7 +67,7 @@ public class AFPDitheredRectanglePainter extends AbstractAFPPainter { AFPImageObjectInfo imageObjectInfo = new AFPImageObjectInfo(); imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS10); //imageObjectInfo.setCreatePageSegment(true); - imageObjectInfo.getResourceInfo().setLevel(new AFPResourceLevel(AFPResourceLevel.INLINE)); + imageObjectInfo.getResourceInfo().setLevel(new AFPResourceLevel(ResourceType.INLINE)); imageObjectInfo.getResourceInfo().setImageDimension(ditherSize); imageObjectInfo.setBitsPerPixel(1); imageObjectInfo.setColor(false); diff --git a/src/java/org/apache/fop/afp/AFPResourceInfo.java b/src/java/org/apache/fop/afp/AFPResourceInfo.java index 1bf26f2bb..bbd552c67 100644 --- a/src/java/org/apache/fop/afp/AFPResourceInfo.java +++ b/src/java/org/apache/fop/afp/AFPResourceInfo.java @@ -21,6 +21,7 @@ package org.apache.fop.afp; import java.awt.Dimension; +import org.apache.fop.afp.AFPResourceLevel.ResourceType; /** * The level at which a resource is to reside in the AFP output @@ -29,7 +30,7 @@ public class AFPResourceInfo { /** the general default resource level */ public static final AFPResourceLevel DEFAULT_LEVEL - = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE); + = new AFPResourceLevel(ResourceType.PRINT_FILE); /** the URI of this resource */ private String uri = null; diff --git a/src/java/org/apache/fop/afp/AFPResourceLevel.java b/src/java/org/apache/fop/afp/AFPResourceLevel.java index d884b56a6..860ca3d26 100644 --- a/src/java/org/apache/fop/afp/AFPResourceLevel.java +++ b/src/java/org/apache/fop/afp/AFPResourceLevel.java @@ -19,46 +19,56 @@ package org.apache.fop.afp; +import java.net.URI; + +import static org.apache.fop.afp.AFPResourceLevel.ResourceType.DOCUMENT; +import static org.apache.fop.afp.AFPResourceLevel.ResourceType.EXTERNAL; +import static org.apache.fop.afp.AFPResourceLevel.ResourceType.INLINE; +import static org.apache.fop.afp.AFPResourceLevel.ResourceType.PAGE; +import static org.apache.fop.afp.AFPResourceLevel.ResourceType.PAGE_GROUP; +import static org.apache.fop.afp.AFPResourceLevel.ResourceType.PRINT_FILE; + /** * A resource level */ public class AFPResourceLevel { + public enum ResourceType { + /** directly in page **/ + INLINE("inline"), + /** page level **/ + PAGE("page"), + /** page group level **/ + PAGE_GROUP("page-group"), + /** document level **/ + DOCUMENT("document"), + /** print file level **/ + PRINT_FILE("print-file"), + /** external level **/ + EXTERNAL("external"); + + private final String name; + + private ResourceType(String name) { + this.name = name; + } - /** directly in page **/ - public static final int INLINE = 0; - - /** page level **/ - public static final int PAGE = 1; - - /** page group level **/ - public static final int PAGE_GROUP = 2; - - /** document level **/ - public static final int DOCUMENT = 3; - - /** print file level **/ - public static final int PRINT_FILE = 4; - - /** external level **/ - public static final int EXTERNAL = 5; - - private static final String NAME_INLINE = "inline"; - private static final String NAME_PAGE = "page"; - private static final String NAME_PAGE_GROUP = "page-group"; - private static final String NAME_DOCUMENT = "document"; - private static final String NAME_PRINT_FILE = "print-file"; - private static final String NAME_EXTERNAL = "external"; - - private static final String[] NAMES = new String[] { - NAME_INLINE, NAME_PAGE, NAME_PAGE_GROUP, NAME_DOCUMENT, NAME_PRINT_FILE, NAME_EXTERNAL - }; - + public static ResourceType getValueOf(String levelString) { + for (ResourceType resType : ResourceType.values()) { + if (resType.name.equalsIgnoreCase(levelString)) { + return resType; + } + } + return null; + } - /** where the resource will reside in the AFP output */ - private int level = PRINT_FILE; // default is print-file level (images) + public String getName() { + return name; + } + } /** the external resource group file path */ - private String extFilePath = null; + private URI extUri = null; + private ResourceType resourceType; /** * Sets the resource placement level within the AFP output @@ -67,18 +77,8 @@ public class AFPResourceLevel { * @return true if the resource level was successfully set */ public static AFPResourceLevel valueOf(String levelString) { - if (levelString != null) { - levelString = levelString.toLowerCase(); - AFPResourceLevel resourceLevel = null; - for (int i = 0; i < NAMES.length; i++) { - if (NAMES[i].equals(levelString)) { - resourceLevel = new AFPResourceLevel(i); - break; - } - } - return resourceLevel; - } - return null; + ResourceType resType = ResourceType.getValueOf(levelString); + return resType != null ? new AFPResourceLevel(resType) : null; } /** @@ -86,17 +86,8 @@ public class AFPResourceLevel { * * @param level the resource level */ - public AFPResourceLevel(int level) { - setLevel(level); - } - - /** - * Sets the resource level - * - * @param level the resource level - */ - public void setLevel(int level) { - this.level = level; + public AFPResourceLevel(ResourceType resourceType) { + this.resourceType = resourceType; } /** @@ -105,7 +96,7 @@ public class AFPResourceLevel { * @return true if this is at page level */ public boolean isPage() { - return level == PAGE; + return resourceType == PAGE; } /** @@ -114,7 +105,7 @@ public class AFPResourceLevel { * @return true if this is at page group level */ public boolean isPageGroup() { - return level == PAGE_GROUP; + return resourceType == PAGE_GROUP; } /** @@ -123,7 +114,7 @@ public class AFPResourceLevel { * @return true if this is at document level */ public boolean isDocument() { - return level == DOCUMENT; + return resourceType == DOCUMENT; } /** @@ -132,7 +123,7 @@ public class AFPResourceLevel { * @return true if this is at external level */ public boolean isExternal() { - return level == EXTERNAL; + return resourceType == EXTERNAL; } /** @@ -141,7 +132,7 @@ public class AFPResourceLevel { * @return true if this is at print-file level */ public boolean isPrintFile() { - return level == PRINT_FILE; + return resourceType == PRINT_FILE; } /** @@ -150,30 +141,30 @@ public class AFPResourceLevel { * @return true if this resource level is inline */ public boolean isInline() { - return level == INLINE; + return resourceType == INLINE; } /** - * Returns the destination file path of the external resource group file + * Returns the URI of the external resource group. * - * @return the destination file path of the external resource group file + * @return the destination URI of the external resource group */ - public String getExternalFilePath() { - return this.extFilePath; + public URI getExternalURI() { + return this.extUri; } /** - * Sets the external destination of the resource + * Sets the URI of the external resource group. * - * @param filePath the external resource group file + * @param filePath the URI of the external resource group */ - public void setExternalFilePath(String filePath) { - this.extFilePath = filePath; + public void setExternalUri(URI uri) { + this.extUri = uri; } /** {@inheritDoc} */ public String toString() { - return NAMES[level] + (isExternal() ? ", file=" + extFilePath : ""); + return resourceType + (isExternal() ? ", uri=" + extUri : ""); } /** {@inheritDoc} */ @@ -186,16 +177,16 @@ public class AFPResourceLevel { } AFPResourceLevel rl = (AFPResourceLevel)obj; - return (level == rl.level) - && (extFilePath == rl.extFilePath - || extFilePath != null && extFilePath.equals(rl.extFilePath)); + return (resourceType == rl.resourceType) + && (extUri == rl.extUri + || extUri != null && extUri.equals(rl.extUri)); } /** {@inheritDoc} */ public int hashCode() { int hash = 7; - hash = 31 * hash + level; - hash = 31 * hash + (null == extFilePath ? 0 : extFilePath.hashCode()); + hash = 31 * hash + resourceType.hashCode(); + hash = 31 * hash + (null == extUri ? 0 : extUri.hashCode()); return hash; } } diff --git a/src/java/org/apache/fop/afp/AFPResourceLevelDefaults.java b/src/java/org/apache/fop/afp/AFPResourceLevelDefaults.java index 8cb0ebaaf..aea97cb7d 100644 --- a/src/java/org/apache/fop/afp/AFPResourceLevelDefaults.java +++ b/src/java/org/apache/fop/afp/AFPResourceLevelDefaults.java @@ -22,6 +22,7 @@ package org.apache.fop.afp; import java.util.Iterator; import java.util.Map; +import org.apache.fop.afp.AFPResourceLevel.ResourceType; import org.apache.fop.afp.modca.ResourceObject; /** @@ -58,7 +59,7 @@ public class AFPResourceLevelDefaults { // level not explicitly set/changed so default to inline for GOCA graphic objects // (due to a bug in the IBM AFP Workbench Viewer (2.04.01.07), hard copy works just fine) setDefaultResourceLevel(ResourceObject.TYPE_GRAPHIC, - new AFPResourceLevel(AFPResourceLevel.INLINE)); + new AFPResourceLevel(ResourceType.INLINE)); } /** diff --git a/src/java/org/apache/fop/afp/AFPResourceManager.java b/src/java/org/apache/fop/afp/AFPResourceManager.java index 9544f76c7..43dc626a7 100644 --- a/src/java/org/apache/fop/afp/AFPResourceManager.java +++ b/src/java/org/apache/fop/afp/AFPResourceManager.java @@ -31,6 +31,7 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.afp.AFPResourceLevel.ResourceType; import org.apache.fop.afp.fonts.AFPFont; import org.apache.fop.afp.fonts.CharacterSet; import org.apache.fop.afp.modca.AbstractNamedAFPObject; @@ -41,8 +42,9 @@ import org.apache.fop.afp.modca.PageSegment; import org.apache.fop.afp.modca.Registry; import org.apache.fop.afp.modca.ResourceGroup; import org.apache.fop.afp.modca.ResourceObject; +import org.apache.fop.afp.util.AFPResourceAccessor; import org.apache.fop.afp.util.AFPResourceUtil; -import org.apache.fop.afp.util.ResourceAccessor; +import org.apache.fop.apps.io.InternalResourceResolver; /** * Manages the creation and storage of document resources @@ -74,9 +76,9 @@ public class AFPResourceManager { /** * Main constructor */ - public AFPResourceManager() { + public AFPResourceManager(InternalResourceResolver resourceResolver) { this.factory = new Factory(); - this.streamer = new AFPStreamer(factory); + this.streamer = new AFPStreamer(factory, resourceResolver); this.dataObjectFactory = new AFPDataObjectFactory(factory); } @@ -119,8 +121,8 @@ public class AFPResourceManager { * @param filePath the default resource group file path */ - public void setDefaultResourceGroupFilePath(String filePath) { - streamer.setDefaultResourceGroupFilePath(filePath); + public void setDefaultResourceGroupUri(URI uri) { + streamer.setDefaultResourceGroupUri(uri); } /** @@ -325,7 +327,7 @@ public class AFPResourceManager { if (afpFont.isEmbeddable()) { //Embed fonts (char sets and code pages) if (charSet.getResourceAccessor() != null) { - ResourceAccessor accessor = charSet.getResourceAccessor(); + AFPResourceAccessor accessor = charSet.getResourceAccessor(); createIncludedResource( charSet.getName(), accessor, ResourceObject.TYPE_FONT_CHARACTER_SET); @@ -352,7 +354,7 @@ public class AFPResourceManager { * @param resourceObjectType the resource object type ({@link ResourceObject}.*) * @throws IOException if an I/O error occurs while loading the resource */ - public void createIncludedResource(String resourceName, ResourceAccessor accessor, + public void createIncludedResource(String resourceName, AFPResourceAccessor accessor, byte resourceObjectType) throws IOException { URI uri; try { @@ -373,9 +375,9 @@ public class AFPResourceManager { * @param resourceObjectType the resource object type ({@link ResourceObject}.*) * @throws IOException if an I/O error occurs while loading the resource */ - public void createIncludedResource(String resourceName, URI uri, ResourceAccessor accessor, + public void createIncludedResource(String resourceName, URI uri, AFPResourceAccessor accessor, byte resourceObjectType) throws IOException { - AFPResourceLevel resourceLevel = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE); + AFPResourceLevel resourceLevel = new AFPResourceLevel(ResourceType.PRINT_FILE); AFPResourceInfo resourceInfo = new AFPResourceInfo(); resourceInfo.setLevel(resourceLevel); @@ -416,9 +418,9 @@ public class AFPResourceManager { * @throws IOException if an I/O error occurs while loading the resource */ public void createIncludedResourceFromExternal(final String resourceName, - final URI uri, final ResourceAccessor accessor) throws IOException { + final URI uri, final AFPResourceAccessor accessor) throws IOException { - AFPResourceLevel resourceLevel = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE); + AFPResourceLevel resourceLevel = new AFPResourceLevel(ResourceType.PRINT_FILE); AFPResourceInfo resourceInfo = new AFPResourceInfo(); resourceInfo.setLevel(resourceLevel); diff --git a/src/java/org/apache/fop/afp/AFPStreamer.java b/src/java/org/apache/fop/afp/AFPStreamer.java index 65686b92a..072dc1796 100644 --- a/src/java/org/apache/fop/afp/AFPStreamer.java +++ b/src/java/org/apache/fop/afp/AFPStreamer.java @@ -20,20 +20,22 @@ package org.apache.fop.afp; import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; -import java.io.RandomAccessFile; +import java.net.URI; +import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.afp.modca.ResourceGroup; import org.apache.fop.afp.modca.StreamedResourceGroup; +import org.apache.fop.apps.io.InternalResourceResolver; +import org.apache.fop.apps.io.TempResourceURIGenerator; /** * Manages the streaming of the AFP output @@ -42,43 +44,45 @@ public class AFPStreamer implements Streamable { /** Static logging instance */ private static final Log LOG = LogFactory.getLog(AFPStreamer.class); - private static final String AFPDATASTREAM_TEMP_FILE_PREFIX = "AFPDataStream_"; - - private static final int BUFFER_SIZE = 4096; // 4k writing buffer - private static final String DEFAULT_EXTERNAL_RESOURCE_FILENAME = "resources.afp"; + private static final TempResourceURIGenerator TEMP_URI_GENERATOR + = new TempResourceURIGenerator("AFPDataStream_"); private final Factory factory; + private final InternalResourceResolver resourceResolver; + /** A mapping of external resource destinations to resource groups */ - private final Map/*<String,AFPExternalResourceGroup>*/pathResourceGroupMap - = new java.util.HashMap/*<String,AFPExternalResourceGroup>*/(); + private final Map<URI, ResourceGroup> pathResourceGroupMap = new HashMap<URI, ResourceGroup>(); private StreamedResourceGroup printFileResourceGroup; /** Sets the default resource group file path */ - private String defaultResourceGroupFilePath = DEFAULT_EXTERNAL_RESOURCE_FILENAME; + private URI defaultResourceGroupUri; - private File tempFile; + private final URI tempUri; /** temporary document outputstream */ - private OutputStream documentOutputStream; + private OutputStream tempOutputStream; /** the final outputstream */ private OutputStream outputStream; - private RandomAccessFile documentFile; - private DataStream dataStream; /** * Main constructor * * @param factory a factory + * @param resourceResolver resource resolver */ - public AFPStreamer(Factory factory) { + public AFPStreamer(Factory factory, InternalResourceResolver resourceResolver) { this.factory = factory; + this.resourceResolver = resourceResolver; + this.tempUri = TEMP_URI_GENERATOR.generate(); + defaultResourceGroupUri = URI.create(DEFAULT_EXTERNAL_RESOURCE_FILENAME); + } /** @@ -89,11 +93,8 @@ public class AFPStreamer implements Streamable { * @throws IOException thrown if an I/O exception of some sort has occurred */ public DataStream createDataStream(AFPPaintingState paintingState) throws IOException { - this.tempFile = File.createTempFile(AFPDATASTREAM_TEMP_FILE_PREFIX, null); - this.documentFile = new RandomAccessFile(tempFile, "rw"); - this.documentOutputStream = new BufferedOutputStream( - new FileOutputStream(documentFile.getFD())); - this.dataStream = factory.createDataStream(paintingState, documentOutputStream); + this.tempOutputStream = new BufferedOutputStream(resourceResolver.getOutputStream(tempUri)); + this.dataStream = factory.createDataStream(paintingState, tempOutputStream); return dataStream; } @@ -102,8 +103,8 @@ public class AFPStreamer implements Streamable { * * @param filePath the default resource group file path */ - public void setDefaultResourceGroupFilePath(String filePath) { - this.defaultResourceGroupFilePath = filePath; + public void setDefaultResourceGroupUri(URI uri) { + this.defaultResourceGroupUri = uri; } /** @@ -118,23 +119,23 @@ public class AFPStreamer implements Streamable { return null; } if (level.isExternal()) { - String filePath = level.getExternalFilePath(); - if (filePath == null) { + URI uri = level.getExternalURI(); + if (uri == null) { LOG.warn("No file path provided for external resource, using default."); - filePath = defaultResourceGroupFilePath; + uri = defaultResourceGroupUri; } - resourceGroup = (ResourceGroup)pathResourceGroupMap.get(filePath); + resourceGroup = pathResourceGroupMap.get(uri); if (resourceGroup == null) { OutputStream os = null; try { - os = new BufferedOutputStream(new FileOutputStream(filePath)); - } catch (FileNotFoundException fnfe) { - LOG.error("Failed to create/open external resource group file '" - + filePath + "'"); + os = new BufferedOutputStream(resourceResolver.getOutputStream(uri)); + } catch (IOException ioe) { + LOG.error("Failed to create/open external resource group for uri '" + + uri + "'"); } finally { if (os != null) { resourceGroup = factory.createStreamedResourceGroup(os); - pathResourceGroupMap.put(filePath, resourceGroup); + pathResourceGroupMap.put(uri, resourceGroup); } } } @@ -156,34 +157,20 @@ public class AFPStreamer implements Streamable { * * @throws IOException if an an I/O exception of some sort has occurred */ - // write out any external resource groups + // write out any external resource groups public void close() throws IOException { Iterator it = pathResourceGroupMap.values().iterator(); while (it.hasNext()) { StreamedResourceGroup resourceGroup = (StreamedResourceGroup)it.next(); resourceGroup.close(); } - // close any open print-file resource group if (printFileResourceGroup != null) { printFileResourceGroup.close(); } - // write out document writeToStream(outputStream); - outputStream.close(); - - - if (documentOutputStream != null) { - documentOutputStream.close(); - } - - if (documentFile != null) { - documentFile.close(); - } - // delete temporary file - tempFile.delete(); } /** @@ -197,28 +184,11 @@ public class AFPStreamer implements Streamable { /** {@inheritDoc} */ public void writeToStream(OutputStream os) throws IOException { -// long start = System.currentTimeMillis(); - int len = (int)documentFile.length(); - int numChunks = len / BUFFER_SIZE; - int remainingChunkSize = len % BUFFER_SIZE; - byte[] buffer; - - documentFile.seek(0); - if (numChunks > 0) { - buffer = new byte[BUFFER_SIZE]; - for (int i = 0; i < numChunks; i++) { - documentFile.read(buffer, 0, BUFFER_SIZE); - os.write(buffer, 0, BUFFER_SIZE); - } - } else { - buffer = new byte[remainingChunkSize]; - } - if (remainingChunkSize > 0) { - documentFile.read(buffer, 0, remainingChunkSize); - os.write(buffer, 0, remainingChunkSize); - } + tempOutputStream.close(); + InputStream tempInputStream = resourceResolver.getResource(tempUri); + IOUtils.copy(tempInputStream, os); + //TODO this should notify the stream provider that it is safe to delete the temp data + tempInputStream.close(); os.flush(); -// long end = System.currentTimeMillis(); -// log.debug("writing time " + (end - start) + "ms"); } } 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/CharacterSet.java b/src/java/org/apache/fop/afp/fonts/CharacterSet.java index fad5e95e6..49e7f99ba 100644 --- a/src/java/org/apache/fop/afp/fonts/CharacterSet.java +++ b/src/java/org/apache/fop/afp/fonts/CharacterSet.java @@ -30,7 +30,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.fop.afp.AFPConstants; import org.apache.fop.afp.AFPEventProducer; import org.apache.fop.afp.fonts.CharactersetEncoder.EncodedChars; -import org.apache.fop.afp.util.ResourceAccessor; +import org.apache.fop.afp.util.AFPResourceAccessor; import org.apache.fop.afp.util.StringUtils; /** @@ -77,7 +77,7 @@ public class CharacterSet { protected final String name; /** The path to the installed fonts */ - private final ResourceAccessor accessor; + private final AFPResourceAccessor accessor; /** The current orientation (currently only 0 is supported by FOP) */ private final String currentOrientation = "0"; @@ -100,7 +100,7 @@ public class CharacterSet { * @param eventProducer for handling AFP related events */ CharacterSet(String codePage, String encoding, CharacterSetType charsetType, String name, - ResourceAccessor accessor, AFPEventProducer eventProducer) { + AFPResourceAccessor accessor, AFPEventProducer eventProducer) { if (name.length() > MAX_NAME_LEN) { String msg = "Character set name '" + name + "' must be a maximum of " + MAX_NAME_LEN + " characters"; @@ -115,7 +115,7 @@ public class CharacterSet { } this.codePage = codePage; this.encoding = encoding; - this.encoder = CharactersetEncoder.newInstance(encoding, charsetType); + this.encoder = charsetType.getEncoder(encoding); this.accessor = accessor; this.characterSetOrientations = new HashMap<String, CharacterSetOrientation>(4); @@ -211,7 +211,7 @@ public class CharacterSet { * Returns the resource accessor to load the font resources with. * @return the resource accessor to load the font resources with */ - public ResourceAccessor getResourceAccessor() { + public AFPResourceAccessor getResourceAccessor() { return this.accessor; } diff --git a/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java b/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java index 7da2d71ca..7331178f5 100644 --- a/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java +++ b/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java @@ -19,9 +19,9 @@ package org.apache.fop.afp.fonts; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; @@ -38,8 +38,9 @@ import org.apache.xmlgraphics.image.loader.util.SoftMapCache; import org.apache.fop.afp.AFPConstants; import org.apache.fop.afp.AFPEventProducer; -import org.apache.fop.afp.util.ResourceAccessor; +import org.apache.fop.afp.util.AFPResourceAccessor; import org.apache.fop.afp.util.StructuredFieldReader; +import org.apache.fop.apps.io.InternalResourceResolver; import org.apache.fop.fonts.Typeface; /** @@ -138,28 +139,24 @@ public abstract class CharacterSetBuilder { * Returns an InputStream to a given file path and filename * * * @param accessor the resource accessor - * @param filename the file name + * @param uriStr the URI * @param eventProducer for handling AFP related events * @return an inputStream - * * @throws IOException in the event that an I/O exception of some sort has occurred */ - protected InputStream openInputStream(ResourceAccessor accessor, String filename, + private InputStream openInputStream(AFPResourceAccessor accessor, String uriStr, AFPEventProducer eventProducer) throws IOException { URI uri; try { - uri = new URI(filename.trim()); + uri = InternalResourceResolver.cleanURI(uriStr.trim()); } catch (URISyntaxException e) { - throw new FileNotFoundException("Invalid filename: " - + filename + " (" + e.getMessage() + ")"); + throw new MalformedURLException("Invalid uri: " + uriStr + " (" + e.getMessage() + ")"); } - if (LOG.isDebugEnabled()) { LOG.debug("Opening " + uri); } - InputStream inputStream = accessor.createInputStream(uri); - return inputStream; + return accessor.createInputStream(uri); } /** @@ -167,7 +164,7 @@ public abstract class CharacterSetBuilder { * * @param inputStream the inputstream to close */ - protected void closeInputStream(InputStream inputStream) { + private void closeInputStream(InputStream inputStream) { try { if (inputStream != null) { inputStream.close(); @@ -191,7 +188,7 @@ public abstract class CharacterSetBuilder { * @throws IOException if an I/O error occurs */ public CharacterSet buildSBCS(String characterSetName, String codePageName, String encoding, - ResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { + AFPResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { return processFont(characterSetName, codePageName, encoding, CharacterSetType.SINGLE_BYTE, accessor, eventProducer); } @@ -211,7 +208,7 @@ public abstract class CharacterSetBuilder { * @throws IOException if an I/O error occurs */ public CharacterSet buildDBCS(String characterSetName, String codePageName, String encoding, - CharacterSetType charsetType, ResourceAccessor accessor, AFPEventProducer eventProducer) + CharacterSetType charsetType, AFPResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { return processFont(characterSetName, codePageName, encoding, charsetType, accessor, eventProducer); @@ -236,7 +233,7 @@ public abstract class CharacterSetBuilder { } private CharacterSet processFont(String characterSetName, String codePageName, String encoding, - CharacterSetType charsetType, ResourceAccessor accessor, AFPEventProducer eventProducer) + CharacterSetType charsetType, AFPResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { // check for cached version of the characterset String descriptor = characterSetName + "_" + encoding + "_" + codePageName; @@ -329,7 +326,7 @@ public abstract class CharacterSetBuilder { * @throws IOException if an I/O exception of some sort has occurred. */ protected Map<String, String> loadCodePage(String codePage, String encoding, - ResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { + AFPResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { // Create the HashMap to store code page information Map<String, String> codePages = new HashMap<String, String>(); @@ -337,7 +334,11 @@ public abstract class CharacterSetBuilder { InputStream inputStream = null; try { inputStream = openInputStream(accessor, codePage.trim(), eventProducer); - + } catch (IOException e) { + eventProducer.codePageNotFound(this, e); + throw e; + } + try { StructuredFieldReader structuredFieldReader = new StructuredFieldReader(inputStream); byte[] data = structuredFieldReader.getNext(CHARACTER_TABLE_SF); @@ -367,8 +368,6 @@ public abstract class CharacterSetBuilder { position++; } } - } catch (FileNotFoundException e) { - eventProducer.codePageNotFound(this, e); } finally { closeInputStream(inputStream); } @@ -383,9 +382,8 @@ public abstract class CharacterSetBuilder { * @return a class representing the font descriptor * @throws IOException if an I/O exception of some sort has occurred. */ - protected static FontDescriptor processFontDescriptor( - StructuredFieldReader structuredFieldReader) - throws IOException { + private static FontDescriptor processFontDescriptor( + StructuredFieldReader structuredFieldReader) throws IOException { byte[] fndData = structuredFieldReader.getNext(FONT_DESCRIPTOR_SF); return new FontDescriptor(fndData); @@ -399,8 +397,8 @@ public abstract class CharacterSetBuilder { * @return the FontControl * @throws IOException if an I/O exception of some sort has occurred. */ - protected FontControl processFontControl(StructuredFieldReader structuredFieldReader) - throws IOException { + private FontControl processFontControl(StructuredFieldReader structuredFieldReader) + throws IOException { byte[] fncData = structuredFieldReader.getNext(FONT_CONTROL_SF); @@ -431,7 +429,7 @@ public abstract class CharacterSetBuilder { * @return CharacterSetOrientation array * @throws IOException if an I/O exception of some sort has occurred. */ - protected CharacterSetOrientation[] processFontOrientation( + private CharacterSetOrientation[] processFontOrientation( StructuredFieldReader structuredFieldReader) throws IOException { byte[] data = structuredFieldReader.getNext(FONT_ORIENTATION_SF); @@ -464,7 +462,6 @@ public abstract class CharacterSetBuilder { } } - return orientations.toArray(EMPTY_CSO_ARRAY); } @@ -480,7 +477,7 @@ public abstract class CharacterSetBuilder { * font metric values * @throws IOException if an I/O exception of some sort has occurred. */ - protected void processFontPosition(StructuredFieldReader structuredFieldReader, + private void processFontPosition(StructuredFieldReader structuredFieldReader, CharacterSetOrientation[] characterSetOrientations, double metricNormalizationFactor) throws IOException { @@ -537,7 +534,7 @@ public abstract class CharacterSetBuilder { * font metric values * @throws IOException if an I/O exception of some sort has occurred. */ - protected void processFontIndex(StructuredFieldReader structuredFieldReader, + private void processFontIndex(StructuredFieldReader structuredFieldReader, CharacterSetOrientation cso, Map<String, String> codepage, double metricNormalizationFactor) throws IOException { @@ -709,22 +706,23 @@ public abstract class CharacterSetBuilder { return INSTANCE; } + @Override protected Map<String, String> loadCodePage(String codePage, String encoding, - ResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { - + AFPResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { // Create the HashMap to store code page information Map<String, String> codePages = new HashMap<String, String>(); - InputStream inputStream = null; try { - inputStream = openInputStream(accessor, codePage.trim(), eventProducer); - - StructuredFieldReader structuredFieldReader - = new StructuredFieldReader(inputStream); + inputStream = super.openInputStream(accessor, codePage.trim(), eventProducer); + } catch (IOException e) { + eventProducer.codePageNotFound(this, e); + throw e; + } + try { + StructuredFieldReader structuredFieldReader = new StructuredFieldReader(inputStream); byte[] data; while ((data = structuredFieldReader.getNext(CHARACTER_TABLE_SF)) != null) { int position = 0; - byte[] gcgiBytes = new byte[8]; byte[] charBytes = new byte[2]; // Read data, ignoring bytes 0 - 2 @@ -752,12 +750,9 @@ public abstract class CharacterSetBuilder { } } } - } catch (FileNotFoundException e) { - eventProducer.codePageNotFound(this, e); } finally { - closeInputStream(inputStream); + super.closeInputStream(inputStream); } - return codePages; } diff --git a/src/java/org/apache/fop/afp/fonts/CharacterSetType.java b/src/java/org/apache/fop/afp/fonts/CharacterSetType.java index 8eaaa089b..060d949ac 100644 --- a/src/java/org/apache/fop/afp/fonts/CharacterSetType.java +++ b/src/java/org/apache/fop/afp/fonts/CharacterSetType.java @@ -19,13 +19,39 @@ package org.apache.fop.afp.fonts; +import org.apache.fop.afp.fonts.CharactersetEncoder.DefaultEncoder; +import org.apache.fop.afp.fonts.CharactersetEncoder.EbcdicDoubleByteLineDataEncoder; + /** * An enumeration of AFP characterset types. */ public enum CharacterSetType { /** Double byte character sets; these do NOT have the shift-in;shift-out operators */ - DOUBLE_BYTE, + DOUBLE_BYTE { + @Override + CharactersetEncoder getEncoder(String encoding) { + return new DefaultEncoder(encoding, true); + } + }, /** Double byte character sets; these can have the shift-in;shift-out operators */ - DOUBLE_BYTE_LINE_DATA, - SINGLE_BYTE; + DOUBLE_BYTE_LINE_DATA { + @Override + CharactersetEncoder getEncoder(String encoding) { + return new EbcdicDoubleByteLineDataEncoder(encoding); + } + }, + SINGLE_BYTE { + @Override + CharactersetEncoder getEncoder(String encoding) { + return new DefaultEncoder(encoding, false); + } + }; + + /** + * Returns the character-set encoder + * + * @param encoding + * @return + */ + abstract CharactersetEncoder getEncoder(String encoding); } diff --git a/src/java/org/apache/fop/afp/fonts/CharactersetEncoder.java b/src/java/org/apache/fop/afp/fonts/CharactersetEncoder.java index f101bdab4..983c308cd 100644 --- a/src/java/org/apache/fop/afp/fonts/CharactersetEncoder.java +++ b/src/java/org/apache/fop/afp/fonts/CharactersetEncoder.java @@ -87,7 +87,7 @@ public abstract class CharactersetEncoder { */ public static EncodedChars encodeSBCS(CharSequence chars, String encoding) throws CharacterCodingException { - CharactersetEncoder encoder = newInstance(encoding, CharacterSetType.SINGLE_BYTE); + CharactersetEncoder encoder = CharacterSetType.SINGLE_BYTE.getEncoder(encoding); return encoder.encode(chars); } @@ -97,8 +97,8 @@ public abstract class CharactersetEncoder { * sequence it will return its EBCDIC code-point, however, the "Shift In - Shift Out" operators * are removed from the sequence of bytes. These are only used in Line Data. */ - private static final class EbcdicDoubleByteLineDataEncoder extends CharactersetEncoder { - private EbcdicDoubleByteLineDataEncoder(String encoding) { + static final class EbcdicDoubleByteLineDataEncoder extends CharactersetEncoder { + EbcdicDoubleByteLineDataEncoder(String encoding) { super(encoding); } @Override @@ -115,10 +115,10 @@ public abstract class CharactersetEncoder { * the primary format for most Latin character sets. This can also be used for Unicode double- * byte character sets (DBCS). */ - private static final class DefaultEncoder extends CharactersetEncoder { + static final class DefaultEncoder extends CharactersetEncoder { private final boolean isDBCS; - private DefaultEncoder(String encoding, boolean isDBCS) { + DefaultEncoder(String encoding, boolean isDBCS) { super(encoding); this.isDBCS = isDBCS; } @@ -130,24 +130,6 @@ public abstract class CharactersetEncoder { } /** - * Returns an new instance of a {@link CharactersetEncoder}. - * - * @param encoding the encoding for the underlying character encoder - * @param isEbcdicDBCS whether or not this wraps a double-byte EBCDIC code page. - * @return the CharactersetEncoder - */ - static CharactersetEncoder newInstance(String encoding, CharacterSetType charsetType) { - switch (charsetType) { - case DOUBLE_BYTE_LINE_DATA: - return new EbcdicDoubleByteLineDataEncoder(encoding); - case DOUBLE_BYTE: - return new DefaultEncoder(encoding, true); - default: - return new DefaultEncoder(encoding, false); - } - } - - /** * A container for encoded character bytes */ // CSOFF: FinalClass - disabling "final" modifier so that this class can be mocked 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/FopCharacterSet.java b/src/java/org/apache/fop/afp/fonts/FopCharacterSet.java index f83c38621..7c2b68506 100644 --- a/src/java/org/apache/fop/afp/fonts/FopCharacterSet.java +++ b/src/java/org/apache/fop/afp/fonts/FopCharacterSet.java @@ -20,7 +20,7 @@ package org.apache.fop.afp.fonts; import org.apache.fop.afp.AFPEventProducer; -import org.apache.fop.afp.util.ResourceAccessor; +import org.apache.fop.afp.util.AFPResourceAccessor; import org.apache.fop.fonts.Typeface; /** @@ -42,7 +42,7 @@ public class FopCharacterSet extends CharacterSet { */ public FopCharacterSet(String codePage, String encoding, String name, Typeface charSet, AFPEventProducer eventProducer) { - super(codePage, encoding, CharacterSetType.SINGLE_BYTE, name, (ResourceAccessor) null, + super(codePage, encoding, CharacterSetType.SINGLE_BYTE, name, (AFPResourceAccessor) null, eventProducer); this.charSet = charSet; } 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/modca/IncludedResourceObject.java b/src/java/org/apache/fop/afp/modca/IncludedResourceObject.java index dc841bd40..9ab84a640 100644 --- a/src/java/org/apache/fop/afp/modca/IncludedResourceObject.java +++ b/src/java/org/apache/fop/afp/modca/IncludedResourceObject.java @@ -26,16 +26,15 @@ import java.net.URI; import org.apache.commons.io.IOUtils; +import org.apache.fop.afp.util.AFPResourceAccessor; import org.apache.fop.afp.util.AFPResourceUtil; -import org.apache.fop.afp.util.ResourceAccessor; - /** * Encapsulates an included resource object that is loaded from an external file. */ public class IncludedResourceObject extends AbstractNamedAFPObject { - private ResourceAccessor resourceAccessor; + private AFPResourceAccessor resourceAccessor; private URI uri; /** @@ -45,7 +44,7 @@ public class IncludedResourceObject extends AbstractNamedAFPObject { * @param uri the URI of the external file */ public IncludedResourceObject(String name, - ResourceAccessor resourceAccessor, URI uri) { + AFPResourceAccessor resourceAccessor, URI uri) { super(name); this.resourceAccessor = resourceAccessor; this.uri = uri; diff --git a/src/java/org/apache/fop/afp/util/AFPResourceAccessor.java b/src/java/org/apache/fop/afp/util/AFPResourceAccessor.java new file mode 100644 index 000000000..02691527e --- /dev/null +++ b/src/java/org/apache/fop/afp/util/AFPResourceAccessor.java @@ -0,0 +1,76 @@ +/* + * 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.afp.util; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; + +import org.apache.fop.apps.io.InternalResourceResolver; + +/** + * Defines an interface through which external resource objects can be accessed. + */ +public final class AFPResourceAccessor { + + private final InternalResourceResolver resourceResolver; + private final String baseURI; + + /** + * Constructor for resource to be accessed via the {@link org.apache.fop.apps.FOUserAgent}. This + * contructor takes a base URI for resolving font resource URIs. So, if fonts need to be + * accessed, you can set the {@link FontManager}'s base URI instead of the one on the + * {@link org.apache.fop.apps.FopFactory}. + * + * @param InternalResourceResolver resource resolver + * @param baseURI the custom base URI to resolve relative URIs against (may be null) + */ + public AFPResourceAccessor(InternalResourceResolver resourceResolver, String baseURI) { + this.resourceResolver = resourceResolver; + this.baseURI = baseURI; + } + + /** + * Constructor for resource to be accessed via the {@link org.apache.fop.apps.FOUserAgent}. + * + * @param InternalResourceResolver resource resolver + */ + public AFPResourceAccessor(InternalResourceResolver resourceResolver) { + this(resourceResolver, null); + } + + private URI getResourceURI(URI uri) { + if (baseURI == null) { + return uri; + } + try { + URI baseURI = InternalResourceResolver.getBaseURI(this.baseURI); + return baseURI.resolve(uri); + } catch (URISyntaxException use) { + return uri; + } + } + + /** {@inheritDoc} */ + public InputStream createInputStream(URI uri) throws IOException { + return resourceResolver.getResource(getResourceURI(uri)); + } +} diff --git a/src/java/org/apache/fop/afp/util/AFPResourceUtil.java b/src/java/org/apache/fop/afp/util/AFPResourceUtil.java index 538f2b880..979376b3e 100644 --- a/src/java/org/apache/fop/afp/util/AFPResourceUtil.java +++ b/src/java/org/apache/fop/afp/util/AFPResourceUtil.java @@ -92,13 +92,10 @@ public final class AFPResourceUtil { throws UnsupportedEncodingException { //The first 8 bytes of the field data represent the resource name byte[] nameBytes = new byte[8]; - - byte[] fieldData = field.getData(); - if (fieldData.length < 8) { - throw new IllegalArgumentException("Field data does not contain a resource name"); - } - System.arraycopy(fieldData, 0, nameBytes, 0, 8); - return new String(nameBytes, AFPConstants.EBCIDIC_ENCODING); + System.arraycopy(field.getData(), 0, nameBytes, 0, 8); + String asciiName; + asciiName = new String(nameBytes, AFPConstants.EBCIDIC_ENCODING); + return asciiName; } /** @@ -131,13 +128,12 @@ public final class AFPResourceUtil { public static void copyNamedResource(String name, final InputStream in, final OutputStream out) throws IOException { final MODCAParser parser = new MODCAParser(in); - Collection<String> resourceNames = new java.util.HashSet<String>(); + Collection resourceNames = new java.util.HashSet(); //Find matching "Begin" field final UnparsedStructuredField fieldBegin; while (true) { - final UnparsedStructuredField field = parser.readNextStructuredField(); - + UnparsedStructuredField field = parser.readNextStructuredField(); if (field == null) { throw new IOException("Requested resource '" + name + "' not found. Encountered resource names: " + resourceNames); @@ -146,10 +142,8 @@ public final class AFPResourceUtil { if (field.getSfTypeCode() != TYPE_CODE_BEGIN) { //0xA8=Begin continue; //Not a "Begin" field } - final String resourceName = getResourceName(field); - + String resourceName = getResourceName(field); resourceNames.add(resourceName); - if (resourceName.equals(name)) { if (LOG.isDebugEnabled()) { LOG.debug("Start of requested structured field found:\n" @@ -176,35 +170,45 @@ public final class AFPResourceUtil { if (wrapInResource) { ResourceObject resourceObject = new ResourceObject(name) { protected void writeContent(OutputStream os) throws IOException { - copyNamedStructuredFields(name, fieldBegin, parser, out); + copyStructuredFields(name, fieldBegin, parser, out); } }; resourceObject.setType(ResourceObject.TYPE_PAGE_SEGMENT); resourceObject.writeToStream(out); } else { - copyNamedStructuredFields(name, fieldBegin, parser, out); + copyStructuredFields(name, fieldBegin, parser, out); } } - private static void copyNamedStructuredFields(final String name, - UnparsedStructuredField fieldBegin, MODCAParser parser, - OutputStream out) throws IOException { + private static void copyStructuredFields(String name, UnparsedStructuredField fieldBegin, + MODCAParser parser, OutputStream out) throws IOException { + boolean inRequestedResource; - UnparsedStructuredField field = fieldBegin; + //The "Begin" field first + out.write(MODCAParser.CARRIAGE_CONTROL_CHAR); + fieldBegin.writeTo(out); + UnparsedStructuredField field; - while (true) { + //Then the rest of the fields until the corresponding "End" field + inRequestedResource = true; + do { + field = parser.readNextStructuredField(); if (field == null) { - throw new IOException("Ending structured field not found for resource " + name); + break; //Unexpected EOF } - out.write(MODCAParser.CARRIAGE_CONTROL_CHAR); - field.writeTo(out); - if (field.getSfTypeCode() == TYPE_CODE_END - && fieldBegin.getSfCategoryCode() == field.getSfCategoryCode() - && name.equals(getResourceName(field))) { - break; + if (field.getSfTypeCode() == TYPE_CODE_END) { + String resourceName = getResourceName(field); + if (resourceName.equals(name)) { + inRequestedResource = false; //Signal end of loop + } } - field = parser.readNextStructuredField(); + out.write(MODCAParser.CARRIAGE_CONTROL_CHAR); + field.writeTo(out); + } while (inRequestedResource); + if (inRequestedResource) { + throw new IOException("Ending structured field not found for resource " + name); } } + } diff --git a/src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java b/src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java deleted file mode 100644 index 2872976b6..000000000 --- a/src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java +++ /dev/null @@ -1,87 +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.afp.util; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URL; - -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - -import org.apache.commons.io.IOUtils; - -import org.apache.fop.apps.FOUserAgent; - -/** - * Default implementation of the {@link ResourceAccessor} interface for use inside FOP. - */ -public class DefaultFOPResourceAccessor extends SimpleResourceAccessor { - - private FOUserAgent userAgent; - private String categoryBaseURI; - - /** - * Constructor for resource to be accessed via the {@link FOUserAgent}. This contructor - * can take two base URIs: the category base URI is the one to use when differentiating between - * normal resources (ex. images) and font resources. So, if fonts need to be accessed, you can - * set the {@link org.apache.fop.fonts.FontManager}'s base URI instead of the one on the - * {@link org.apache.fop.apps.FopFactory}. - * @param userAgent the FO user agent - * @param categoryBaseURI the category base URI (may be null) - * @param baseURI the custom base URI to resolve relative URIs against (may be null) - */ - public DefaultFOPResourceAccessor(FOUserAgent userAgent, String categoryBaseURI, URI baseURI) { - super(baseURI); - this.userAgent = userAgent; - this.categoryBaseURI = categoryBaseURI; - } - - /** {@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); - - 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()); - } - } - URL url = new URL(src.getSystemId()); - return url.openStream(); - } - -} diff --git a/src/java/org/apache/fop/afp/util/SimpleResourceAccessor.java b/src/java/org/apache/fop/afp/util/SimpleResourceAccessor.java deleted file mode 100644 index 7a963928b..000000000 --- a/src/java/org/apache/fop/afp/util/SimpleResourceAccessor.java +++ /dev/null @@ -1,76 +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.afp.util; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URL; - -/** - * Simple implementation of the {@link ResourceAccessor} interface for access relative to a - * base URI. - */ -public class SimpleResourceAccessor implements ResourceAccessor { - - private URI baseURI; - - /** - * Creates a new simple resource accessor. - * @param baseURI the base URI to resolve relative URIs against (may be null) - */ - public SimpleResourceAccessor(URI baseURI) { - this.baseURI = baseURI; - } - - /** - * Creates a new simple resource accessor. - * @param baseDir the base directory to resolve relative filenames against (may be null) - */ - public SimpleResourceAccessor(File baseDir) { - this(baseDir != null ? baseDir.toURI() : null); - } - - /** - * Returns the base URI. - * @return the base URI (or null if no base URI was set) - */ - public URI getBaseURI() { - return this.baseURI; - } - - /** - * Resolve the given URI against the baseURI. - * @param uri the URI to resolve - * @return the resolved URI - */ - protected URI resolveAgainstBase(URI uri) { - return (getBaseURI() != null ? getBaseURI().resolve(uri) : uri); - } - - /** {@inheritDoc} */ - public InputStream createInputStream(URI uri) throws IOException { - URI resolved = resolveAgainstBase(uri); - URL url = resolved.toURL(); - return url.openStream(); - } - -} diff --git a/src/java/org/apache/fop/hyphenation/HyphenationTreeResolver.java b/src/java/org/apache/fop/apps/EnvironmentProfile.java index c9d9ed179..c35219353 100644 --- a/src/java/org/apache/fop/hyphenation/HyphenationTreeResolver.java +++ b/src/java/org/apache/fop/apps/EnvironmentProfile.java @@ -17,22 +17,36 @@ /* $Id$ */ -package org.apache.fop.hyphenation; +package org.apache.fop.apps; -import javax.xml.transform.Source; +import java.net.URI; + +import org.apache.fop.apps.io.ResourceResolver; +import org.apache.fop.fonts.FontManager; /** - * <p>This interface is used to resolve relative URIs pointing to hyphenation tree files.</p> + * The environment profile represents the restrictions and allowances that FOP is */ -public interface HyphenationTreeResolver { +public interface EnvironmentProfile { + + /** + * Returns resource resolver for this environment. + * + * @return the resource resolver + */ + ResourceResolver getResourceResolver(); /** - * Called to resolve an URI to a Source instance. The base URI needed by the URIResolver's - * resolve() method is defined to be implicitely available in this case. If the URI cannot - * be resolved, null is returned. - * @param href An href attribute, which may be relative or absolute. - * @return A Source object, or null if the href could not resolved. + * Returns the font manager with restrictions/allowances set for this environment. + * + * @return the font manager */ - Source resolve(String href); + 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..374074b8a --- /dev/null +++ b/src/java/org/apache/fop/apps/EnvironmentalProfileFactory.java @@ -0,0 +1,113 @@ +/* + * 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.InternalResourceResolver; +import org.apache.fop.apps.io.ResourceResolver; +import org.apache.fop.apps.io.ResourceResolverFactory; +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) { + InternalResourceResolver internalResolver = ResourceResolverFactory.createInternalResourceResolver( + defaultBaseUri, resourceResolver); + return new FontManager(internalResolver, fontDetector, fontCacheManager); + } +} diff --git a/src/java/org/apache/fop/apps/FOURIResolver.java b/src/java/org/apache/fop/apps/FOURIResolver.java deleted file mode 100644 index a1d7fd673..000000000 --- a/src/java/org/apache/fop/apps/FOURIResolver.java +++ /dev/null @@ -1,376 +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.ByteArrayOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; - -import javax.xml.transform.Source; -import javax.xml.transform.TransformerException; -import javax.xml.transform.URIResolver; -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.xmlgraphics.util.io.Base64EncodeStream; -import org.apache.xmlgraphics.util.uri.CommonURIResolver; - -/** - * Provides FOP specific URI resolution. This is the default URIResolver - * {@link FOUserAgent} will use unless overridden. - * - * @see javax.xml.transform.URIResolver - */ -public class FOURIResolver implements javax.xml.transform.URIResolver { - - // log - private Log log = LogFactory.getLog("FOP"); - - /** Common URIResolver */ - private CommonURIResolver commonURIResolver = new CommonURIResolver(); - - /** A user settable URI Resolver */ - private URIResolver uriResolver = null; - - /** true if exceptions are to be thrown if the URIs cannot be resolved. */ - private boolean throwExceptions = false; - - /** - * Checks if the given base URL is acceptable. It also normalizes the URL. - * @param base the base URL to check - * @return the normalized URL - * @throws MalformedURLException if there's a problem with a file URL - */ - public String checkBaseURL(String base) throws MalformedURLException { - // replace back slash with forward slash to ensure windows file:/// URLS are supported - base = base.replace('\\', '/'); - if (!base.endsWith("/")) { - // The behavior described by RFC 3986 regarding resolution of relative - // references may be misleading for normal users: - // file://path/to/resources + myResource.res -> file://path/to/myResource.res - // file://path/to/resources/ + myResource.res -> file://path/to/resources/myResource.res - // We assume that even when the ending slash is missing, users have the second - // example in mind - base += "/"; - } - File dir = new File(base); - if (dir.isDirectory()) { - return dir.toURI().toASCIIString(); - } else { - URI baseURI; - try { - baseURI = new URI(base); - String scheme = baseURI.getScheme(); - boolean directoryExists = true; - if ("file".equals(scheme)) { - dir = FileUtils.toFile(baseURI.toURL()); - directoryExists = dir.isDirectory(); - } - if (scheme == null || !directoryExists) { - String message = "base " + base + " is not a valid directory"; - if (throwExceptions) { - throw new MalformedURLException(message); - } - log.error(message); - } - return baseURI.toASCIIString(); - } catch (URISyntaxException e) { - //TODO not ideal: our base URLs are actually base URIs. - throw new MalformedURLException(e.getMessage()); - } - } - } - - /** - * Default constructor - */ - public FOURIResolver() { - this(false); - } - - /** - * Additional constructor - * - * @param throwExceptions - * true if exceptions are to be thrown if the URIs cannot be - * resolved. - */ - public FOURIResolver(boolean throwExceptions) { - this.throwExceptions = throwExceptions; - } - - /** - * Handles resolve exceptions appropriately. - * - * @param e - * the exception - * @param errorStr - * error string - * @param strict - * strict user config - */ - private void handleException(Exception e, String errorStr, boolean strict) - throws TransformerException { - if (strict) { - throw new TransformerException(errorStr, e); - } - log.error(e.getMessage()); - } - - /** - * Called by the processor through {@link FOUserAgent} when it encounters an - * uri in an external-graphic element. (see also - * {@link javax.xml.transform.URIResolver#resolve(String, String)} This - * resolver will allow URLs without a scheme, i.e. it assumes 'file:' as the - * default scheme. It also allows relative URLs with scheme, e.g. - * file:../../abc.jpg which is not strictly RFC compliant as long as the - * scheme is the same as the scheme of the base URL. If the base URL is null - * a 'file:' URL referencing the current directory is used as the base URL. - * If the method is successful it will return a Source of type - * {@link javax.xml.transform.stream.StreamSource} with its SystemID set to - * the resolved URL used to open the underlying InputStream. - * - * @param href - * An href attribute, which may be relative or absolute. - * @param base - * The base URI against which the first argument will be made - * absolute if the absolute URI is required. - * @return A {@link javax.xml.transform.Source} object, or null if the href - * cannot be resolved. - * @throws javax.xml.transform.TransformerException - * Never thrown by this implementation. - * @see javax.xml.transform.URIResolver#resolve(String, String) - */ - public Source resolve(String href, String base) throws TransformerException { - Source source = null; - - // data URLs can be quite long so evaluate early and don't try to build a File - // (can lead to problems) - source = commonURIResolver.resolve(href, base); - - // Custom uri resolution - if (source == null && uriResolver != null) { - source = uriResolver.resolve(href, base); - } - - // Fallback to default resolution mechanism - if (source == null) { - URL absoluteURL = null; - int hashPos = href.indexOf('#'); - String fileURL; - String fragment; - if (hashPos >= 0) { - fileURL = href.substring(0, hashPos); - fragment = href.substring(hashPos); - } else { - fileURL = href; - fragment = null; - } - File file = new File(fileURL); - if (file.canRead() && file.isFile()) { - try { - if (fragment != null) { - absoluteURL = new URL(file.toURI().toURL().toExternalForm() + fragment); - } else { - absoluteURL = file.toURI().toURL(); - } - } catch (MalformedURLException mfue) { - handleException(mfue, "Could not convert filename '" + href - + "' to URL", throwExceptions); - } - } else { - // no base provided - if (base == null) { - // We don't have a valid file protocol based URL - try { - absoluteURL = new URL(href); - } catch (MalformedURLException mue) { - try { - // the above failed, we give it another go in case - // the href contains only a path then file: is - // assumed - absoluteURL = new URL("file:" + href); - } catch (MalformedURLException mfue) { - handleException(mfue, "Error with URL '" + href - + "'", throwExceptions); - } - } - - // try and resolve from context of base - } else { - URL baseURL = null; - try { - baseURL = new URL(base); - } catch (MalformedURLException mfue) { - handleException(mfue, "Error with base URL '" + base - + "'", throwExceptions); - } - - /* - * This piece of code is based on the following statement in - * RFC2396 section 5.2: - * - * 3) If the scheme component is defined, indicating that - * the reference starts with a scheme name, then the - * reference is interpreted as an absolute URI and we are - * done. Otherwise, the reference URI's scheme is inherited - * from the base URI's scheme component. - * - * Due to a loophole in prior specifications [RFC1630], some - * parsers allow the scheme name to be present in a relative - * URI if it is the same as the base URI scheme. - * Unfortunately, this can conflict with the correct parsing - * of non-hierarchical URI. For backwards compatibility, an - * implementation may work around such references by - * removing the scheme if it matches that of the base URI - * and the scheme is known to always use the <hier_part> - * syntax. - * - * The URL class does not implement this work around, so we - * do. - */ - assert (baseURL != null); - String scheme = baseURL.getProtocol() + ":"; - if (href.startsWith(scheme) && "file:".equals(scheme)) { - href = href.substring(scheme.length()); - int colonPos = href.indexOf(':'); - int slashPos = href.indexOf('/'); - if (slashPos >= 0 && colonPos >= 0 - && colonPos < slashPos) { - href = "/" + href; // Absolute file URL doesn't - // have a leading slash - } - } - try { - absoluteURL = new URL(baseURL, href); - } catch (MalformedURLException mfue) { - handleException(mfue, "Error with URL; base '" + base - + "' " + "href '" + href + "'", throwExceptions); - } - } - } - - if (absoluteURL != null) { - String effURL = absoluteURL.toExternalForm(); - try { - URLConnection connection = absoluteURL.openConnection(); - connection.setAllowUserInteraction(false); - connection.setDoInput(true); - updateURLConnection(connection, href); - connection.connect(); - return new StreamSource(connection.getInputStream(), effURL); - } catch (FileNotFoundException fnfe) { - // Note: This is on "debug" level since the caller is - // supposed to handle this - log.debug("File not found: " + effURL); - } catch (java.io.IOException ioe) { - log.error("Error with opening URL '" + effURL + "': " - + ioe.getMessage()); - } - } - } - return source; - } - - /** - * This method allows you to set special values on a URLConnection just - * before the connect() method is called. Subclass FOURIResolver and - * override this method to do things like adding the user name and password - * for HTTP basic authentication. - * - * @param connection - * the URLConnection instance - * @param href - * the original URI - */ - protected void updateURLConnection(URLConnection connection, String href) { - // nop - } - - /** - * This is a convenience method for users who want to override - * updateURLConnection for HTTP basic authentication. Simply call it using - * the right username and password. - * - * @param connection - * the URLConnection to set up for HTTP basic authentication - * @param username - * the username - * @param password - * the password - */ - protected void applyHttpBasicAuthentication(URLConnection connection, - String username, String password) { - String combined = username + ":" + password; - try { - ByteArrayOutputStream baout = new ByteArrayOutputStream(combined - .length() * 2); - Base64EncodeStream base64 = new Base64EncodeStream(baout); - // TODO Not sure what charset/encoding can be used with basic - // authentication - base64.write(combined.getBytes("UTF-8")); - base64.close(); - connection.setRequestProperty("Authorization", "Basic " - + new String(baout.toByteArray(), "UTF-8")); - } catch (IOException e) { - // won't happen. We're operating in-memory. - throw new RuntimeException( - "Error during base64 encodation of username/password"); - } - } - - /** - * Sets the custom 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 resolver - * the new URI resolver - */ - public void setCustomURIResolver(URIResolver resolver) { - this.uriResolver = resolver; - } - - /** - * Returns the custom URI Resolver. - * - * @return the URI Resolver or null, if none is set - */ - public URIResolver getCustomURIResolver() { - return this.uriResolver; - } - - /** - * @param throwExceptions - * Whether or not to throw exceptions on resolution error - */ - public void setThrowExceptions(boolean throwExceptions) { - this.throwExceptions = throwExceptions; - } -} diff --git a/src/java/org/apache/fop/apps/FOUserAgent.java b/src/java/org/apache/fop/apps/FOUserAgent.java index 035b6f1a1..488b62474 100644 --- a/src/java/org/apache/fop/apps/FOUserAgent.java +++ b/src/java/org/apache/fop/apps/FOUserAgent.java @@ -21,18 +21,22 @@ 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.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; @@ -41,17 +45,27 @@ 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.InternalResourceResolver; 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.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.RendererConfigOption; 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 +89,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 InternalResourceResolver resourceResolver; - 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 +134,7 @@ public class FOUserAgent { private ImageSessionContext imageSessionContext = new AbstractImageSessionContext() { public ImageContext getParentContext() { - return getFactory(); + return factory; } public float getTargetResolution() { @@ -148,21 +151,59 @@ public class FOUserAgent { * Main constructor. <b>This constructor should not be called directly. Please use the * methods from FopFactory to construct FOUserAgent instances!</b> * @param factory the factory that provides environment-level information + * @param resourceResolver the resolver used to acquire resources * @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, InternalResourceResolver resourceResolver) { this.factory = factory; - setBaseURL(factory.getBaseURL()); + this.resourceResolver = resourceResolver; 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 resource resolver. + * + * @return the resource resolver + */ + public InternalResourceResolver getResourceResolver() { + return resourceResolver; } // ---------------------------------------------- rendering-run dependent stuff @@ -177,7 +218,6 @@ public class FOUserAgent { setStructureTreeEventHandler(documentHandler.getStructureTreeEventHandler()); } this.documentHandlerOverride = documentHandler; - } /** @@ -345,48 +385,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 org.apache.fop.fonts.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(RendererConfigOption option) { + return rendererOptions.get(option.getName()); } /** @@ -396,39 +401,20 @@ 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 */ - 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); + public StreamSource resolveURI(String uri) { + // TODO: What do we want to do when resources aren't found??? We also need to remove this + // method entirely + try { + // Have to do this so we can resolve data URIs + StreamSource src = new StreamSource(resourceResolver.getResource(uri)); + src.setSystemId(uri); + return src; + } catch (URISyntaxException use) { + return null; + } catch (IOException ioe) { + return null; } - return source; } /** @@ -498,29 +484,18 @@ public class FOUserAgent { // (convenience access to FopFactory methods) /** - * Returns the font base URL. - * @return the font base URL - * @deprecated Use {@link org.apache.fop.fonts.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(); } /** @@ -531,7 +506,7 @@ public class FOUserAgent { * @see FopFactory#getPageHeight() */ public String getPageHeight() { - return getFactory().getPageHeight(); + return factory.getPageHeight(); } /** @@ -542,7 +517,7 @@ public class FOUserAgent { * @see FopFactory#getPageWidth() */ public String getPageWidth() { - return getFactory().getPageWidth(); + return factory.getPageWidth(); } /** @@ -551,7 +526,7 @@ public class FOUserAgent { * @see FopFactory#validateStrictly() */ public boolean validateStrictly() { - return getFactory().validateStrictly(); + return factory.validateStrictly(); } /** @@ -560,21 +535,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(); } /** @@ -663,12 +638,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; } /** @@ -714,5 +730,69 @@ 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(); + } + + 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..bf39a53f0 --- /dev/null +++ b/src/java/org/apache/fop/apps/FopConfParser.java @@ -0,0 +1,348 @@ +/* + * 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.Locale; +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.InternalResourceResolver; +import org.apache.fop.apps.io.ResourceResolver; +import org.apache.fop.apps.io.ResourceResolverFactory; +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 resourceResolver 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 resourceResolver) throws SAXException, IOException { + this(fopConfStream, EnvironmentalProfileFactory.createDefault(defaultBaseURI, resourceResolver)); + } + + /** + * 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, ResourceResolverFactory.createDefaultResourceResolver()); + } + + /** + * 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, ResourceResolverFactory.createDefaultResourceResolver()); + } + + /** + * Constructor that parses the FOP conf and uses the URI resolver given. + * + * @param fopConfFile the FOP conf file + * @param resourceResolver 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 resourceResolver) + throws SAXException, IOException { + this(new FileInputStream(fopConfFile), + fopConfFile.getAbsoluteFile().getParentFile().toURI(), resourceResolver); + } + + private void configure(final URI defaultBaseURI, final ResourceResolver resourceResolver, + 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 = InternalResourceResolver.getBaseURI(cfg.getChild("base").getValue(null)); + fopFactoryBuilder.setBaseURI(defaultBaseURI.resolve(confUri)); + } 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(), resourceResolver).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(Locale.getDefault()); + + 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(Locale.getDefault()); + } + + 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(Locale.getDefault()).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..ec7266957 100644 --- a/src/java/org/apache/fop/apps/FopFactory.java +++ b/src/java/org/apache/fop/apps/FopFactory.java @@ -21,19 +21,13 @@ 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; import org.apache.avalon.framework.configuration.Configuration; @@ -44,13 +38,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.InternalResourceResolver; +import org.apache.fop.apps.io.ResourceResolverFactory; 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 +55,49 @@ 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(); - - /** The resolver for user-supplied hyphenation patterns */ - private HyphenationTreeResolver hyphResolver = null; + private final ContentHandlerFactoryRegistry contentHandlerFactoryRegistry + = new ContentHandlerFactoryRegistry(); - private ColorSpaceCache colorSpaceCache = null; + private final ColorSpaceCache colorSpaceCache; - /** Image manager for loading and caching image objects */ - private ImageManager imageManager; + private final FopFactoryConfig config; - /** Font manager for font substitution, autodetection and caching **/ - private FontManager fontManager; + private final InternalResourceResolver resolver; - /** Configuration layer used to configure fop */ - private FopFactoryConfigurator config = null; + private final Map<String, RendererConfig> rendererConfig; - /** - * 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.resolver = ResourceResolverFactory.createInternalResourceResolver(config.getBaseURI(), + config.getResourceResolver()); + this.elementMappingRegistry = new ElementMappingRegistry(this); + this.colorSpaceCache = new ColorSpaceCache(resolver); + 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 +109,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 +165,12 @@ public class FopFactory implements ImageContext { * @throws FOPException */ public FOUserAgent newFOUserAgent() { - FOUserAgent userAgent = new FOUserAgent(this); + FOUserAgent userAgent = new FOUserAgent(this, resolver); 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 +184,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 +201,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 +216,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 +235,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 +285,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 +318,32 @@ 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 - */ - 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 + * Returns whether accessibility is enabled. + * @return true if accessibility is enabled */ - @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; - } - - /** - * 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 - */ - public void setURIResolver(URIResolver uriResolver) { - foURIResolver.setCustomURIResolver(uriResolver); + boolean isAccessibilityEnabled() { + return config.isAccessibilityEnabled(); } /** - * Returns the URI Resolver. - * @return the URI Resolver + * Returns the image manager. + * @return the image manager */ - public URIResolver getURIResolver() { - return foURIResolver; + public ImageManager getImageManager() { + return config.getImageManager(); } /** - * Returns the FO URI Resolver. - * @return the FO URI Resolver + * Returns the overriding LayoutManagerMaker instance, if any. + * @return the overriding LayoutManagerMaker or null */ - public FOURIResolver getFOURIResolver() { - return foURIResolver; - } - - /** @return the HyphenationTreeResolver for resolving user-supplied hyphenation patterns. */ - public HyphenationTreeResolver getHyphenationTreeResolver() { - return this.hyphResolver; + public LayoutManagerMaker getLayoutManagerMakerOverride() { + return config.getLayoutManagerMakerOverride(); } - /** - * 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; - } - /** - * 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 +351,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 +359,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 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 config.isBreakIndentInheritanceOnReferenceAreaBoundary(); } - /** @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 +377,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 +389,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 +399,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 +409,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 +418,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,79 +438,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; - } - - /** - * 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 baseUri the base URI to resolve against - * @return A {@link javax.xml.transform.Source} object, or null if the URI - * cannot be resolved. - * @see org.apache.fop.apps.FOURIResolver - */ - public Source resolveURI(String href, String baseUri) { - Source source = null; - try { - source = foURIResolver.resolve(href, baseUri); - } catch (TransformerException e) { - log.error("Attempt to resolve URI '" + href + "' failed: ", e); - } - return source; + return config.getFontManager(); } /** @@ -825,5 +463,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..44c44c119 --- /dev/null +++ b/src/java/org/apache/fop/apps/FopFactoryBuilder.java @@ -0,0 +1,648 @@ +/* + * 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 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.ResourceResolver; +import org.apache.fop.apps.io.ResourceResolverFactory; +import org.apache.fop.fonts.FontManager; +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, ResourceResolverFactory.createDefaultResourceResolver()); + } + + /** + * A builder class for {@link FopFactory} which can be used for setting configuration. + * + * @param defaultBaseURI the default base URI for resolving URIs against + * @param resourceResolver the URI resolver + */ + public FopFactoryBuilder(URI defaultBaseURI, ResourceResolver resourceResolver) { + this(EnvironmentalProfileFactory.createDefault(defaultBaseURI, resourceResolver)); + } + + /** + * 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 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 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 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 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)); + } + + /** {@inheritDoc} */ + public boolean isAccessibilityEnabled() { + return accessibility; + } + + /** {@inheritDoc} */ + public LayoutManagerMaker getLayoutManagerMakerOverride() { + return layoutManagerMaker; + } + + /** {@inheritDoc} */ + public ResourceResolver getResourceResolver() { + return enviro.getResourceResolver(); + } + + /** {@inheritDoc} */ + public URI getBaseURI() { + return baseURI; + } + + /** {@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 setBaseURI(URI baseURI); + + 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 setBaseURI(URI baseURI) { + 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 setBaseURI(URI baseURI) { + config.baseURI = baseURI; + } + + 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..1ef958fae --- /dev/null +++ b/src/java/org/apache/fop/apps/FopFactoryConfig.java @@ -0,0 +1,130 @@ +/* + * 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 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.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 getResourceResolver(); + + /** + * The base URI from which URIs are resolved against. + * + * @return the base URI + */ + URI getBaseURI(); + + /** @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/MimeConstants.java b/src/java/org/apache/fop/apps/MimeConstants.java index 851690db1..75b05c8b7 100644 --- a/src/java/org/apache/fop/apps/MimeConstants.java +++ b/src/java/org/apache/fop/apps/MimeConstants.java @@ -32,4 +32,6 @@ public interface MimeConstants extends org.apache.xmlgraphics.util.MimeConstants String MIME_FOP_AREA_TREE = "application/X-fop-areatree"; /** Apache FOP's intermediate format XML */ String MIME_FOP_IF = "application/X-fop-intermediate-format"; + /** Bitmap images */ + String MIME_BITMAP = "image/x-bitmap"; } diff --git a/src/java/org/apache/fop/apps/io/InternalResourceResolver.java b/src/java/org/apache/fop/apps/io/InternalResourceResolver.java new file mode 100644 index 000000000..4d664c8f5 --- /dev/null +++ b/src/java/org/apache/fop/apps/io/InternalResourceResolver.java @@ -0,0 +1,153 @@ +/* + * 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; + +import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; +import javax.xml.transform.stream.StreamSource; + +import org.apache.xmlgraphics.util.uri.DataURIResolver; + +/** + * This object holds the base URI from which to resolve URIs against as well as the resolver for + * resource acquisition. It also does some URI sanitization of common URI syntactical errors. This + * class takes in a {@link org.apache.fop.apps.io.ResourceResolver} and delegates all relevant + * URIs to it. + */ +public class InternalResourceResolver { + private final URI baseUri; + private final ResourceResolver resourceResolver; + private final DataURIResolver dataSchemeResolver = new DataURIResolver(); + + /** + * @param baseUri the base URI from which to resolve relative URIs + * @param resourceResolver the resolver to delegate to + */ + InternalResourceResolver(URI baseUri, ResourceResolver resourceResolver) { + this.baseUri = baseUri; + this.resourceResolver = resourceResolver; + } + + /** + * Returns the base URI from which to resolve all URIs against. + * + * @return the base URI + */ + public URI getBaseURI() { + return baseUri; + } + + /** + * Retrieve a resource given a URI in String form. This also does some syntactical sanitaion on + * the URI. + * + * @param stringUri the URI in String form + * @return the resource + * @throws IOException if an I/O error occurred + * @throws URISyntaxException if the URI syntax was invalid + */ + public Resource getResource(String stringUri) throws IOException, URISyntaxException { + if (stringUri.startsWith("data:")) { + return new Resource(resolveDataURI(stringUri)); + } + return getResource(cleanURI(stringUri)); + } + + /** + * Retrieve a resource given a URI in String form. + * + * @param uri the resource URI + * @return the resource + * @throws IOException if an I/O error occurred + */ + public Resource getResource(URI uri) throws IOException { + if (uri.getScheme() != null && uri.getScheme().startsWith("data")) { + return new Resource(resolveDataURI(uri.toASCIIString())); + } + return resourceResolver.getResource(resolveFromBase(uri)); + } + + /** + * Returns the OutputStream for a given URI. + * + * @param uri the URI for the inteded stream + * @return the output stream + * @throws IOException if an I/O error occurrred + */ + public OutputStream getOutputStream(URI uri) throws IOException { + return resourceResolver.getOutputStream(resolveFromBase(uri)); + } + + /** + * Resolves a URI against the base URI. + * + * @param uri the URI that requires resolution + * @return the resolved URI + */ + public URI resolveFromBase(URI uri) { + return baseUri.resolve(uri); + } + + /** + * Performs some sanitation for some of the most common URI syntax mistakes. + * + * @param uriStr the URI in String form + * @return a valid URI + * @throws URISyntaxException if the given String was too erroneous to validate + */ + public static URI cleanURI(String uriStr) throws URISyntaxException { + // replace back slash with forward slash to ensure windows file:/// URLS are supported + if (uriStr == null) { + return null; + } + String fixedUri = uriStr.replace('\\', '/'); + fixedUri = fixedUri.replace(" ", "%20"); + URI baseURI = new URI(fixedUri); + return baseURI; + } + + /** + * Performs some sanitation for some of the most common URI syntax mistakes but returns a + * directory URI rather than a file URI. + * + * @param base the directory URI in String form + * @return the directory URI + * @throws URISyntaxException if the given String was too erroneous to validate + */ + public static URI getBaseURI(String base) throws URISyntaxException { + String path = base + (base.endsWith("/") ? "" : "/"); + return cleanURI(path); + } + + private InputStream resolveDataURI(String dataURI) { + try { + Source src = dataSchemeResolver.resolve(dataURI, ""); + return src == null ? null : ((StreamSource) src).getInputStream(); + } catch (TransformerException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/java/org/apache/fop/render/DefaultFontResolver.java b/src/java/org/apache/fop/apps/io/Resource.java index 0642537c4..0a8b8c22a 100644 --- a/src/java/org/apache/fop/render/DefaultFontResolver.java +++ b/src/java/org/apache/fop/apps/io/Resource.java @@ -17,36 +17,43 @@ /* $Id$ */ -package org.apache.fop.render; +package org.apache.fop.apps.io; -import javax.xml.transform.Source; - -import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.fonts.FontResolver; +import java.io.FilterInputStream; +import java.io.InputStream; /** - * Default FontResolver implementation which uses the FOUserAgent to resolve font URIs. + * This class represents a resolved resource. The type property is used by FOP to identify the resource + * content. + * */ -public class DefaultFontResolver implements FontResolver { +public class Resource extends FilterInputStream { - private FOUserAgent userAgent; + private final String type; /** - * Main constructor. - * @param userAgent the user agent + * @param type resource type + * @param inputStream input stream of the resource */ - public DefaultFontResolver(FOUserAgent userAgent) { - this.userAgent = userAgent; + public Resource(String type, InputStream inputStream) { + super(inputStream); + this.type = type; } - /** {@inheritDoc} */ - public Source resolve(String href) { - return userAgent.resolveURI(href, userAgent.getFactory().getFontManager().getFontBaseURL()); + /** + * Constructs a resource of 'unknown' type. + * + * @param inputStream input stream of the resource + */ + public Resource(InputStream inputStream) { + this("unknown", inputStream); } - /** {@inheritDoc} */ - public boolean isComplexScriptFeaturesEnabled() { - return userAgent.isComplexScriptFeaturesEnabled(); + /** + * @return the resource type + */ + public String getType() { + return this.type; } } diff --git a/src/java/org/apache/fop/apps/io/ResourceResolver.java b/src/java/org/apache/fop/apps/io/ResourceResolver.java new file mode 100644 index 000000000..a3a9cf0c3 --- /dev/null +++ b/src/java/org/apache/fop/apps/io/ResourceResolver.java @@ -0,0 +1,51 @@ +/* + * 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.OutputStream; +import java.net.URI; + +/** + * Implementations of this resource resolver allow FOP users to control the URI resolution + * mechanism. All resource and output stream acquisition goes through this when its implementation + * is given to the {@link org.apache.fop.apps.EnvironmentProfile}. + */ +public interface ResourceResolver { + + /** + * Get a resource given the URI pointing to said resource. + * + * @param uri the resource URI + * @return the resource + * @throws IOException if an I/O error occured during resource acquisition + */ + Resource getResource(URI uri) throws IOException; + + /** + * Gets an output stream of a given URI. + * + * @param uri the output stream URI + * @return the output stream + * @throws IOException if an I/O error occured while creating an output stream + */ + OutputStream getOutputStream(URI uri) throws IOException; + +} diff --git a/src/java/org/apache/fop/apps/io/ResourceResolverFactory.java b/src/java/org/apache/fop/apps/io/ResourceResolverFactory.java new file mode 100644 index 000000000..2c8300fb9 --- /dev/null +++ b/src/java/org/apache/fop/apps/io/ResourceResolverFactory.java @@ -0,0 +1,276 @@ +/* + * 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.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * A factory class for {@link ResourceResolver}s. + */ +public final class ResourceResolverFactory { + + private ResourceResolverFactory() { + } + + /** + * Returns the default resource resolver, this is most basic resolver which can be used when + * no there are no I/O or file access restrictions. + * + * @return the default resource resolver + */ + public static ResourceResolver createDefaultResourceResolver() { + return DefaultResourceResolver.INSTANCE; + } + + /** + * A helper merthod that creates an internal resource resolver using the default resover: + * {@link ResourceResolverFactory#createDefaultResourceResolver()}. + * + * @param baseURI the base URI from which to resolve URIs + * @return the default internal resource resolver + */ + public static InternalResourceResolver createDefaultInternalResourceResolver(URI baseURI) { + return new InternalResourceResolver(baseURI, createDefaultResourceResolver()); + } + + /** + * Creates an interal resource resolver given a base URI and a resource resolver. + * + * @param baseURI the base URI from which to resolve URIs + * @param resolver the resource resolver + * @return the internal resource resolver + */ + public static InternalResourceResolver createInternalResourceResolver(URI baseURI, + ResourceResolver resolver) { + return new InternalResourceResolver(baseURI, resolver); + } + + /** + * Creates a temporary-resource-schema aware resource resolver. Temporary resource URIs are + * created by {@link TempResourceURIGenerator}. + * + * @param tempResourceResolver the temporary-resource-schema resolver to use + * @param defaultResourceResolver the default resource resolver to use + * @return the ressource resolver + */ + public static ResourceResolver createTempAwareResourceResolver( + TempResourceResolver tempResourceResolver, + ResourceResolver defaultResourceResolver) { + return new TempAwareResourceResolver(tempResourceResolver, defaultResourceResolver); + } + + public static SchemaAwareResourceResolverBuilder createSchemaAwareResourceResolverBuilder( + ResourceResolver defaultResolver) { + return new SchemaAwareResourceResolverBuilderImpl(defaultResolver); + } + + private static final class DefaultResourceResolver implements ResourceResolver { + + private static final ResourceResolver INSTANCE = new DefaultResourceResolver(); + + private final TempAwareResourceResolver delegate; + + private DefaultResourceResolver() { + delegate = new TempAwareResourceResolver(new DefaultTempResourceResolver(), + new NormalResourceResolver()); + } + + public Resource getResource(URI uri) throws IOException { + return delegate.getResource(uri); + } + + public OutputStream getOutputStream(URI uri) throws IOException { + return delegate.getOutputStream(uri); + } + + } + + private static final class TempAwareResourceResolver implements ResourceResolver { + + private final TempResourceResolver tempResourceResolver; + + private final ResourceResolver defaultResourceResolver; + + public TempAwareResourceResolver(TempResourceResolver tempResourceHandler, + ResourceResolver defaultResourceResolver) { + this.tempResourceResolver = tempResourceHandler; + this.defaultResourceResolver = defaultResourceResolver; + } + + private static boolean isTempUri(URI uri) { + return TempResourceURIGenerator.isTempUri(uri); + } + + public Resource getResource(URI uri) throws IOException { + if (isTempUri(uri)) { + return tempResourceResolver.getResource(uri.getPath()); + } else { + return defaultResourceResolver.getResource(uri); + } + } + + public OutputStream getOutputStream(URI uri) throws IOException { + if (isTempUri(uri)) { + return tempResourceResolver.getOutputStream(uri.getPath()); + } else { + return defaultResourceResolver.getOutputStream(uri); + } + } + + } + + private static class DefaultTempResourceResolver implements TempResourceResolver { + private static File getTempFile(String path) throws IOException { + File file = new File(System.getProperty("java.io.tmpdir"), path); + file.deleteOnExit(); + return file; + } + + public Resource getResource(String id) throws IOException { + return new Resource(getTempFile(id).toURI().toURL().openStream()); + } + + public OutputStream getOutputStream(String id) throws IOException { + File file = getTempFile(id); + if (file.createNewFile()) { + return new FileOutputStream(file); + } else { + throw new IOException("Filed to create temporary file: " + id); + } + } + } + + private static class NormalResourceResolver implements ResourceResolver { + public Resource getResource(URI uri) throws IOException { + return new Resource(uri.toURL().openStream()); + } + + public OutputStream getOutputStream(URI uri) throws IOException { + return new FileOutputStream(new File(uri)); + } + } + + private static final class SchemaAwareResourceResolver implements ResourceResolver { + + private final Map<String, ResourceResolver> schemaHandlingResourceResolvers; + + private final ResourceResolver defaultResolver; + + private SchemaAwareResourceResolver( + Map<String, ResourceResolver> schemaHandlingResourceResolvers, + ResourceResolver defaultResolver) { + this.schemaHandlingResourceResolvers = schemaHandlingResourceResolvers; + this.defaultResolver = defaultResolver; + } + + private ResourceResolver getResourceResolverForSchema(URI uri) { + String schema = uri.getScheme(); + if (schemaHandlingResourceResolvers.containsKey(schema)) { + return schemaHandlingResourceResolvers.get(schema); + } else { + return defaultResolver; + } + } + + public Resource getResource(URI uri) throws IOException { + return getResourceResolverForSchema(uri).getResource(uri); + } + + public OutputStream getOutputStream(URI uri) throws IOException { + return getResourceResolverForSchema(uri).getOutputStream(uri); + } + } + + public interface SchemaAwareResourceResolverBuilder { + + void registerResourceResolverForSchema(String schema, ResourceResolver resourceResolver); + + ResourceResolver build(); + } + + private static final class CompletedSchemaAwareResourceResolverBuilder + implements SchemaAwareResourceResolverBuilder { + + private static final SchemaAwareResourceResolverBuilder INSTANCE + = new CompletedSchemaAwareResourceResolverBuilder(); + + public ResourceResolver build() { + throw new IllegalStateException("Resource resolver already built"); + } + + public void registerResourceResolverForSchema(String schema, + ResourceResolver resourceResolver) { + throw new IllegalStateException("Resource resolver already built"); + } + } + + private static final class ActiveSchemaAwareResourceResolverBuilder + implements SchemaAwareResourceResolverBuilder { + + private final Map<String, ResourceResolver> schemaHandlingResourceResolvers + = new HashMap<String, ResourceResolver>(); + + private final ResourceResolver defaultResolver; + + private ActiveSchemaAwareResourceResolverBuilder(ResourceResolver defaultResolver) { + this.defaultResolver = defaultResolver; + } + + public void registerResourceResolverForSchema(String schema, + ResourceResolver resourceResolver) { + schemaHandlingResourceResolvers.put(schema, resourceResolver); + } + + public ResourceResolver build() { + return new SchemaAwareResourceResolver( + Collections.unmodifiableMap(schemaHandlingResourceResolvers), defaultResolver); + } + + } + + private static final class SchemaAwareResourceResolverBuilderImpl + implements SchemaAwareResourceResolverBuilder { + + private SchemaAwareResourceResolverBuilder delegate; + + private SchemaAwareResourceResolverBuilderImpl(ResourceResolver defaultResolver) { + this.delegate = new ActiveSchemaAwareResourceResolverBuilder(defaultResolver); + } + + public void registerResourceResolverForSchema(String schema, + ResourceResolver resourceResolver) { + delegate.registerResourceResolverForSchema(schema, resourceResolver); + } + + public ResourceResolver build() { + ResourceResolver resourceResolver = delegate.build(); + delegate = CompletedSchemaAwareResourceResolverBuilder.INSTANCE; + return resourceResolver; + } + } + +} diff --git a/src/java/org/apache/fop/apps/io/TempResourceResolver.java b/src/java/org/apache/fop/apps/io/TempResourceResolver.java new file mode 100644 index 000000000..b17630a1d --- /dev/null +++ b/src/java/org/apache/fop/apps/io/TempResourceResolver.java @@ -0,0 +1,48 @@ +/* + * 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.OutputStream; + +/** + * Implementations of this interface resolve URIs for temporary files used by FOP. The temporary- + * resource URI scheme comes from {@link TempResourceURIGenerator#TMP_SCHEMA}. + */ +public interface TempResourceResolver { + + /** + * Get a temporary-resource given the URI pointing to said resource. + * + * @param uri the resource URI + * @return the resource + * @throws IOException if an I/O error occured during resource acquisition + */ + Resource getResource(String id) throws IOException; + + /** + * Gets an temporary-output stream of a given URI. + * + * @param uri the output stream URI + * @return the output stream + * @throws IOException if an I/O error occured while creating an output stream + */ + OutputStream getOutputStream(String id) throws IOException; +} diff --git a/src/java/org/apache/fop/apps/io/TempResourceURIGenerator.java b/src/java/org/apache/fop/apps/io/TempResourceURIGenerator.java new file mode 100644 index 000000000..8e6c3606c --- /dev/null +++ b/src/java/org/apache/fop/apps/io/TempResourceURIGenerator.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. + */ + +package org.apache.fop.apps.io; + +import java.net.URI; +import java.util.concurrent.atomic.AtomicLong; + +/** + * Creates a URI for any temporary resource used within FOP. + */ +public final class TempResourceURIGenerator { + + public static final String TMP_SCHEMA = "tmp"; + + private final String tempURIPrefix; + + private final AtomicLong counter; + + /** + * @param uriPrefix a prefix used to name the unique URI + */ + public TempResourceURIGenerator(String uriPrefix) { + counter = new AtomicLong(); + tempURIPrefix = URI.create(TMP_SCHEMA + ":///" + uriPrefix).toASCIIString(); + } + + /** + * Generate a unique URI for a temporary resource + * @return the URI + */ + public URI generate() { + return URI.create(tempURIPrefix + getUniqueId()); + } + + private String getUniqueId() { + return Long.toHexString(counter.getAndIncrement()); + } + + public static boolean isTempUri(URI uri) { + return TMP_SCHEMA.equals(uri.getScheme()); + } +} 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/area/CachedRenderPagesModel.java b/src/java/org/apache/fop/area/CachedRenderPagesModel.java index 288884a55..fcc82cdd3 100644 --- a/src/java/org/apache/fop/area/CachedRenderPagesModel.java +++ b/src/java/org/apache/fop/area/CachedRenderPagesModel.java @@ -21,13 +21,12 @@ package org.apache.fop.area; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; +import java.net.URI; import java.util.HashMap; import java.util.Iterator; import java.util.Map; @@ -36,9 +35,9 @@ import org.xml.sax.SAXException; import org.apache.commons.io.IOUtils; -import org.apache.fop.ResourceEventProducer; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.io.TempResourceURIGenerator; import org.apache.fop.fonts.FontInfo; /** @@ -49,10 +48,12 @@ import org.apache.fop.fonts.FontInfo; */ public class CachedRenderPagesModel extends RenderPagesModel { - private Map<PageViewport, String> pageMap = new HashMap<PageViewport, String>(); + private Map<PageViewport, URI> pageMap = new HashMap<PageViewport, URI>(); /** Base directory to save temporary file in, typically points to the user's temp dir. */ - protected File baseDir; + private final URI tempBaseURI; + private static final TempResourceURIGenerator TEMP_URI_GENERATOR + = new TempResourceURIGenerator("cached-pages"); /** * Main Constructor @@ -65,8 +66,7 @@ public class CachedRenderPagesModel extends RenderPagesModel { public CachedRenderPagesModel (FOUserAgent userAgent, String outputFormat, FontInfo fontInfo, OutputStream stream) throws FOPException { super(userAgent, outputFormat, fontInfo, stream); - //TODO: Avoid System.getProperty()? - this.baseDir = new File(System.getProperty("java.io.tmpdir")); + tempBaseURI = TEMP_URI_GENERATOR.generate(); } /** {@inheritDoc} */ @@ -78,27 +78,19 @@ public class CachedRenderPagesModel extends RenderPagesModel { if (pageViewport != newpage) { try { // load page from cache - String name = pageMap.get(pageViewport); - File tempFile = new File(baseDir, name); - log.debug("Loading page from: " + tempFile); - ObjectInputStream in = new ObjectInputStream( - new BufferedInputStream( - new FileInputStream(tempFile))); + URI tempURI = pageMap.get(pageViewport); + log.debug("Loading page from: " + tempURI); + InputStream inStream = renderer.getUserAgent().getResourceResolver().getResource(tempURI); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(inStream)); try { pageViewport.loadPage(in); } finally { + IOUtils.closeQuietly(inStream); IOUtils.closeQuietly(in); } - if (!tempFile.delete()) { - ResourceEventProducer eventProducer - = ResourceEventProducer.Provider.get( - renderer.getUserAgent().getEventBroadcaster()); - eventProducer.cannotDeleteTempFile(this, tempFile); - } pageMap.remove(pageViewport); } catch (Exception e) { - AreaEventProducer eventProducer - = AreaEventProducer.Provider.get( + AreaEventProducer eventProducer = AreaEventProducer.Provider.get( renderer.getUserAgent().getEventBroadcaster()); eventProducer.pageLoadError(this, pageViewport.getPageNumberString(), e); } @@ -131,18 +123,17 @@ public class CachedRenderPagesModel extends RenderPagesModel { // save page to cache ObjectOutputStream tempstream; String fname = "fop-page-" + page.getPageIndex() + ".ser"; - File tempFile = new File(baseDir, fname); - tempFile.deleteOnExit(); - tempstream = new ObjectOutputStream(new BufferedOutputStream( - new FileOutputStream(tempFile))); + URI tempURI = tempBaseURI.resolve(fname); + OutputStream outStream = renderer.getUserAgent().getResourceResolver().getOutputStream(tempURI); + tempstream = new ObjectOutputStream(new BufferedOutputStream(outStream)); try { page.savePage(tempstream); } finally { IOUtils.closeQuietly(tempstream); } - pageMap.put(page, fname); + pageMap.put(page, tempURI); if (log.isDebugEnabled()) { - log.debug("Page saved to temporary file: " + tempFile); + log.debug("Page saved to temporary file: " + tempURI); } } catch (IOException ioe) { AreaEventProducer eventProducer diff --git a/src/java/org/apache/fop/cli/CommandLineOptions.java b/src/java/org/apache/fop/cli/CommandLineOptions.java index 7d5752d6d..aa402aa6a 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,7 +52,7 @@ 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.pdf.PDFEncryptionOption; import org.apache.fop.render.print.PagesMode; import org.apache.fop.render.print.PrintRenderer; import org.apache.fop.render.xml.XMLRenderer; @@ -116,12 +117,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 +186,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 +229,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 +290,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 +821,14 @@ public class CommandLineOptions { } private PDFEncryptionParams getPDFEncryptionParams() throws FOPException { - PDFEncryptionParams params = (PDFEncryptionParams)renderingOptions.get( - PDFConfigurationConstants.ENCRYPTION_PARAMS); + PDFEncryptionParams params = (PDFEncryptionParams) renderingOptions.get(PDFEncryptionOption.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(PDFEncryptionOption.ENCRYPTION_PARAMS, params); } return params; } @@ -860,7 +861,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 +869,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 +1028,19 @@ 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); + fopFactoryBuilder.setComplexScriptFeatures(useComplexScriptFeatures); } + 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..577efcdf4 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,7 @@ 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.net.URI; import org.w3c.dom.Element; @@ -71,12 +71,10 @@ 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().getResourceResolver().getBaseURI(); + 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 050da71bb..f7053f8ee 100644 --- a/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java +++ b/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java @@ -426,7 +426,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..82213dd65 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.InternalResourceResolver; + //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 resourceResolver the URI resolver for controlling file access + */ + public CIDFont(InternalResourceResolver resourceResolver) { + super(resourceResolver); + } + // ---- 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 89f515205..70961a55c 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.InternalResourceResolver; /** @@ -35,27 +37,27 @@ 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 String fontName; + private String fullName; + private Set<String> familyNames; + private String fontSubName; + private URI embedFileURI; + private String embedResourceName; + private final InternalResourceResolver resourceResolver; private EmbeddingMode embeddingMode = EmbeddingMode.AUTO; - private int capHeight = 0; - private int xHeight = 0; - private int ascender = 0; - private int descender = 0; + 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; @@ -63,6 +65,12 @@ public abstract class CustomFont extends Typeface private boolean useKerning = true; private boolean useAdvanced = true; + /** + * @param resourceResolver the URI resource resolver for controlling file access + */ + public CustomFont(InternalResourceResolver resourceResolver) { + this.resourceResolver = resourceResolver; + } /** the character map, mapping Unicode ranges to glyph indices. */ protected CMapSegment[] cmap; @@ -107,15 +115,16 @@ 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 the embedding mode for this font. * @return embedding mode */ @@ -124,20 +133,13 @@ public abstract class CustomFont extends Typeface } /** - * 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 resourceResolver.getResource(embedFileURI); } /** @@ -335,8 +337,8 @@ public abstract class CustomFont extends Typeface /** * {@inheritDoc} */ - public void setEmbedFileName(String path) { - this.embedFileName = path; + public void setEmbedURI(URI path) { + this.embedFileURI = path; } /** @@ -463,14 +465,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 fc8c947e4..35231e224 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.InternalResourceResolver; + /** * Sets up a set of custom (embedded) fonts */ public class CustomFontCollection implements FontCollection { - private FontResolver fontResolver; private final List<EmbedFontInfo> embedFontInfoList; + private final InternalResourceResolver 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(InternalResourceResolver fontResolver, + List<EmbedFontInfo> customFonts, boolean useComplexScriptFeatures) { + this.uriResolver = fontResolver; this.embedFontInfoList = customFonts; + this.useComplexScripts = useComplexScriptFeatures; } /** {@inheritDoc} */ @@ -52,22 +52,14 @@ 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(); 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..6c5cebb42 --- /dev/null +++ b/src/java/org/apache/fop/fonts/DefaultFontConfig.java @@ -0,0 +1,343 @@ +/* + * 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 { + + private static final 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()), + fontCfg.getAttribute("embedding-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; + + private final String embeddingMode; + + 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, String embeddingMode) { + this.metrics = metrics; + this.embedUri = embed; + this.subFont = subFont; + this.kerning = kerning; + this.advanced = advanced; + this.encodingMode = encodingMode; + this.embeddingMode = embeddingMode; + } + + /** + * 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; + } + + public String getEmbeddingMode() { + return embeddingMode; + } + } +} 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..2c60cf4bf --- /dev/null +++ b/src/java/org/apache/fop/fonts/DefaultFontConfigurator.java @@ -0,0 +1,186 @@ +/* + * 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.InternalResourceResolver; +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 final Log log = LogFactory.getLog(DefaultFontConfigurator.class); + + private final FontManager fontManager; + private final InternalResourceResolver resourceResolver; + 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.resourceResolver = fontManager.getResourceResolver(); + 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>(); + if (fontInfoConfig != null) { + assert fontInfoConfig instanceof DefaultFontConfig; + DefaultFontConfig adobeFontInfoConfig = (DefaultFontConfig) fontInfoConfig; + long start = 0; + if (log.isDebugEnabled()) { + log.debug("Starting font configuration..."); + start = System.currentTimeMillis(); + } + FontAdder fontAdder = new FontAdder(fontManager, resourceResolver, 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 : InternalResourceResolver.cleanURI(metrics); + URI embedUri = InternalResourceResolver.cleanURI(embed); + + List<FontTriplet> tripletList = font.getTripletList(); + + // no font triplet info + if (tripletList.size() == 0) { + URI fontUri = resourceResolver.resolveFromBase(embedUri); + FontInfoFinder finder = new FontInfoFinder(); + finder.setEventListener(listener); + EmbedFontInfo[] infos = finder.find(fontUri, resourceResolver, fontCache); + return infos[0]; //When subFont is set, only one font is returned + } + EncodingMode encodingMode = EncodingMode.getValue(font.getEncodingMode()); + EmbeddingMode embeddingMode = EmbeddingMode.getValue(font.getEmbeddingMode()); + EmbedFontInfo embedFontInfo = new EmbedFontInfo(metricsUri, font.isKerning(), + font.isAdvanced(), tripletList, embedUri, subFont, encodingMode, embeddingMode); + if (fontCache != null) { + if (!fontCache.containsFont(embedFontInfo)) { + fontCache.addFont(embedFontInfo, resourceResolver); + } + } + + 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 64bd200be..5af3fc5ba 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; /** @@ -33,62 +34,66 @@ 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 requested embedding mode for this font */ - protected EmbeddingMode embeddingMode = EmbeddingMode.AUTO; + private final EmbeddingMode embeddingMode; /** 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, + EncodingMode encodingMode, EmbeddingMode embeddingMode) { + this.metricsURI = metricsURI; + this.embedURI = embedURI; this.kerning = kerning; this.advanced = advanced; this.fontTriplets = fontTriplets; this.subFontName = subFontName; + this.encodingMode = encodingMode; + this.embeddingMode = embeddingMode; } /** - * 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; } /** @@ -145,7 +150,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; @@ -176,28 +181,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; - } - - /** - * Sets the embedding mode for this font, currently not supported for Type 1 fonts. - * @param embeddingMode the new embedding mode. - */ - public void setEmbeddingMode(EmbeddingMode embeddingMode) { - if (embeddingMode == null) { - throw new NullPointerException("embeddingMode must not be null"); - } - this.embeddingMode = embeddingMode; - } - private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); @@ -206,7 +189,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..f585dbfa5 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.InternalResourceResolver; import org.apache.fop.fonts.autodetect.FontInfoFinder; /** @@ -29,18 +31,19 @@ import org.apache.fop.fonts.autodetect.FontInfoFinder; */ public class FontAdder { private final FontEventListener listener; - private final FontResolver resolver; + private final InternalResourceResolver resourceResolver; private final FontManager manager; /** * Main constructor * @param manager a font manager - * @param resolver a font resolver + * @param resourceResolver a font resolver * @param listener a font event handler */ - public FontAdder(FontManager manager, FontResolver resolver, FontEventListener listener) { + public FontAdder(FontManager manager, InternalResourceResolver resourceResolver, + FontEventListener listener) { this.manager = manager; - this.resolver = resolver; + this.resourceResolver = resourceResolver; this.listener = listener; } @@ -48,14 +51,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(), resourceResolver, 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..35997f3d7 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.InternalResourceResolver; 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, InternalResourceResolver resourceResolver) { String cacheKey = getCacheKey(fontInfo); synchronized (changeLock) { CachedFontFile cachedFontFile; @@ -329,10 +331,9 @@ 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); + URI fontUri = resourceResolver.resolveFromBase(fontInfo.getEmbedURI()); + File fontFile = new File(fontUri); + long lastModified = fontFile.lastModified(); cachedFontFile = new CachedFontFile(lastModified); if (log.isTraceEnabled()) { log.trace("Font added to cache: " + cacheKey); @@ -467,8 +468,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/afp/util/ResourceAccessor.java b/src/java/org/apache/fop/fonts/FontConfigurator.java index 6b9995c44..c1ddb4296 100644 --- a/src/java/org/apache/fop/afp/util/ResourceAccessor.java +++ b/src/java/org/apache/fop/fonts/FontConfigurator.java @@ -17,24 +17,23 @@ /* $Id$ */ -package org.apache.fop.afp.util; +package org.apache.fop.fonts; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; +import java.util.List; + +import org.apache.fop.apps.FOPException; /** - * Defines an interface through which external resource objects can be accessed. + * An abstract FontInfo configurator */ -public interface ResourceAccessor { +// TODO: Make T extends some interface to make the font info type explicit +public interface FontConfigurator<T> { /** - * Creates a new {@link InputStream} for the given URI that allows read access to an external - * resource. - * @param uri the URI of an external resource. - * @return the new input stream - * @throws IOException if an I/O error occurs while opening the resource + * Initializes font info settings from the user configuration + * @return a font info list + * @throws FOPException if an exception occurs while processing the configuration */ - InputStream createInputStream(URI uri) throws IOException; + 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..dd96e4a1a --- /dev/null +++ b/src/java/org/apache/fop/fonts/FontDetectorFactory.java @@ -0,0 +1,119 @@ +/* + * 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.getResourceResolver().getBaseURI(); + 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 042709884..000000000 --- a/src/java/org/apache/fop/fonts/FontInfoConfigurator.java +++ /dev/null @@ -1,328 +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.getValue( - fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName())); - EmbeddingMode embeddingMode = EmbeddingMode.getValue( - fontCfg.getAttribute("embedding-mode", EmbeddingMode.AUTO.toString())); - EmbedFontInfo embedFontInfo - = new EmbedFontInfo(metricsUrl, useKerning, useAdvanced, tripletList, embedUrl, - subFont); - embedFontInfo.setEncodingMode(encodingMode); - embedFontInfo.setEmbeddingMode(embeddingMode); - - 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 9bdbcd350..f7ee24cbc 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.InternalResourceResolver; 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; - /** the FontResolver to use for font URI resolution */ - protected FontResolver resolver; + protected final URI fontFileURI; + /** the resource resolver to use for font URI resolution */ + protected final InternalResourceResolver resourceResolver; /** the loaded font */ protected CustomFont returnFont; @@ -65,56 +60,19 @@ public abstract class FontLoader { * @param useKerning indicates whether kerning information shall be loaded if available * @param useAdvanced indicates whether advanced typographic information shall be loaded if * available - * @param resolver the font resolver used to resolve URIs + * @param resourceResolver 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, InternalResourceResolver resourceResolver) { this.fontFileURI = fontFileURI; this.embedded = embedded; this.useKerning = useKerning; this.useAdvanced = useAdvanced; - this.resolver = resolver; + this.resourceResolver = resourceResolver; } - 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 embeddingMode the embedding mode - * @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, EmbeddingMode embeddingMode, EncodingMode encodingMode, - FontResolver resolver) throws IOException { - return loadFont(fontFile.toURI().toURL(), subFontName, - embedded, embeddingMode, 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 embeddingMode the embedding mode of the font - * @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, EmbeddingMode embeddingMode, EncodingMode encodingMode, - FontResolver resolver) throws IOException { - return loadFont(fontUrl.toExternalForm(), subFontName, - embedded, embeddingMode, encodingMode, true, true, - resolver); + private static boolean isType1(URI fontURI) { + return fontURI.toASCIIString().toLowerCase().endsWith(".pfb"); } /** @@ -127,14 +85,13 @@ public abstract class FontLoader { * @param useKerning indicates whether kerning information should be loaded if available * @param useAdvanced indicates whether advanced typographic information shall be loaded if * available - * @param resolver the font resolver to use when resolving URIs + * @param resourceResolver 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(String fontFileURI, String subFontName, + public static CustomFont loadFont(URI fontFileURI, String subFontName, boolean embedded, EmbeddingMode embeddingMode, EncodingMode encodingMode, - boolean useKerning, boolean useAdvanced, FontResolver resolver) throws IOException { - fontFileURI = fontFileURI.trim(); + boolean useKerning, boolean useAdvanced, InternalResourceResolver resourceResolver) throws IOException { boolean type1 = isType1(fontFileURI); FontLoader loader; if (type1) { @@ -146,50 +103,15 @@ public abstract class FontLoader { throw new IllegalArgumentException( "Subset embedding for Type 1 fonts is not supported"); } - loader = new Type1FontLoader(fontFileURI, embedded, useKerning, resolver); + loader = new Type1FontLoader(fontFileURI, embedded, useKerning, resourceResolver); } else { - loader = new TTFFontLoader(fontFileURI, subFontName, - embedded, embeddingMode, encodingMode, useKerning, useAdvanced, resolver); + loader = new TTFFontLoader(fontFileURI, subFontName, embedded, embeddingMode, + encodingMode, useKerning, useAdvanced, resourceResolver); } return loader.getFont(); } /** - * 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..e9b021978 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.InternalResourceResolver; 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; + /** The resource resolver */ + private InternalResourceResolver resourceResolver; + + 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 resourceResolver the URI resolver + * @param fontDetector the font detector + * @param fontCacheManager the font cache manager */ - public FontManager() { + public FontManager(InternalResourceResolver resourceResolver, FontDetector fontDetector, + FontCacheManager fontCacheManager) { + this.resourceResolver = resourceResolver; + 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 resource resolver + * @param resourceResolver resource resolver */ - public void setFontBaseURL(String fontBase) throws MalformedURLException { - this.fontBase = fontBase; + public void setResourceResolver(InternalResourceResolver resourceResolver) { + this.resourceResolver = resourceResolver; } - /** - * Returns the font base URL. - * @return the font base URL (or null if none was set) - */ - public String getFontBaseURL() { - return this.fontBase; + public InternalResourceResolver getResourceResolver() { + return this.resourceResolver; } /** @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,21 @@ public class FontManager { } } } + + /** + * Detect fonts from the operating system via FOPs autodetect mechanism. + * + * @param autoDetectFonts if autodetect has been enabled + * @param fontAdder the font adding mechanism + * @param strict whether to enforce strict validation + * @param listener the listener for font related events + * @param fontInfoList a list of font info objects + * @throws FOPException if an exception was thrown auto-detecting fonts + */ + 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..c4fe19444 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,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.io.InternalResourceResolver; +import org.apache.fop.apps.io.ResourceResolver; +import org.apache.fop.apps.io.ResourceResolverFactory; import org.apache.fop.fonts.substitute.FontSubstitutions; import org.apache.fop.fonts.substitute.FontSubstitutionsConfigurator; import org.apache.fop.util.LogUtil; @@ -45,24 +48,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 resourceResolver; /** * 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 resourceResolver the resource resolver */ - public FontManagerConfigurator(Configuration cfg, URI baseURI) { + public FontManagerConfigurator(Configuration cfg, URI defaultBaseUri, + ResourceResolver resourceResolver) { this.cfg = cfg; - this.baseURI = baseURI; + this.defaultBaseUri = defaultBaseUri; + this.resourceResolver = resourceResolver; } /** @@ -75,28 +75,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); + 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 = InternalResourceResolver.getBaseURI(cfg.getChild("font-base").getValue( + null)); + fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver( + defaultBaseUri.resolve(fontBase), resourceResolver)); + } catch (URISyntaxException use) { + LogUtil.handleException(log, use, true); } + } else { + fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver( + defaultBaseUri, resourceResolver)); } // [GA] permit configuration control over base14 kerning; without this, @@ -114,7 +115,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 +122,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 +129,6 @@ public class FontManagerConfigurator { referencedFontsCfg, strict); fontManager.setReferencedFontsMatcher(matcher); } - } } @@ -159,6 +157,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 46ea9123d..68c5c7177 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.InternalResourceResolver; 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 InternalResourceResolver resourceResolver; 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<CMapSegment> bfranges = null; + private List<CMapSegment> 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, InternalResourceResolver resourceResolver) throws FOPException { + this.resourceResolver = resourceResolver; + 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} */ @Override @@ -161,45 +153,41 @@ public class FontReader extends DefaultHandler { /** * {@inheritDoc} */ - @Override - public void setDocumentLocator(Locator locator) { - // this.locator = locator; // not used at present - } - - /** - * {@inheritDoc} - */ - @Override - 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(resourceResolver); returnFont = multiFont; isCID = true; TTFReader.checkMetricsVersion(attributes); } else if ("TRUETYPE".equals(attributes.getValue("type"))) { - singleFont = new SingleByteFont(); + singleFont = new SingleByteFont(resourceResolver); singleFont.setFontType(FontType.TRUETYPE); returnFont = singleFont; isCID = false; TTFReader.checkMetricsVersion(attributes); } else { - singleFont = new SingleByteFont(); + singleFont = new SingleByteFont(resourceResolver); singleFont.setFontType(FontType.TYPE1); returnFont = singleFont; isCID = false; } } else if ("embed".equals(localName)) { - returnFont.setEmbedFileName(attributes.getValue("file")); + try { + returnFont.setEmbedURI(InternalResourceResolver.cleanURI(attributes.getValue("file"))); + } catch (URISyntaxException e) { + throw new SAXException("URI syntax error in metrics file: " + e.getMessage(), e); + } 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<CMapSegment>(); } else if ("bf".equals(localName)) { @@ -208,20 +196,19 @@ public class FontReader extends DefaultHandler { 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"))); } } @@ -319,5 +306,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..f9bae3332 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.InternalResourceResolver; import org.apache.fop.fonts.base14.Courier; import org.apache.fop.fonts.base14.CourierBold; import org.apache.fop.fonts.base14.CourierBoldOblique; @@ -71,11 +69,11 @@ public final class FontSetup { * * @param fontInfo the font info object to set up * @param embedFontInfoList a list of EmbedFontInfo objects - * @param resolver the font resolver + * @param resourceResolver 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, + InternalResourceResolver resourceResolver, boolean base14Kerning) { fontInfo.addMetrics("F1", new Helvetica(base14Kerning)); fontInfo.addMetrics("F2", new HelveticaOblique(base14Kerning)); fontInfo.addMetrics("F3", new HelveticaBold(base14Kerning)); @@ -181,7 +179,7 @@ public final class FontSetup { final int startNum = 15; /* Add configured fonts */ - addConfiguredFonts(fontInfo, embedFontInfoList, startNum, resolver, base14Kerning); + addConfiguredFonts(fontInfo, embedFontInfoList, startNum, resourceResolver, base14Kerning); } /** @@ -189,21 +187,16 @@ public final class FontSetup { * @param fontInfo the font info to set up * @param embedFontInfoList a list of EmbedFontInfo objects * @param num starting index for internal font numbering - * @param resolver the font resolver + * @param resourceResolver the font resolver */ private static void addConfiguredFonts(FontInfo fontInfo, - List<EmbedFontInfo> embedFontInfoList, int num, FontResolver resolver, + List<EmbedFontInfo> embedFontInfoList, int num, + InternalResourceResolver resourceResolver, 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 resourceResolver != null; String internalName = null; @@ -211,7 +204,7 @@ public final class FontSetup { internalName = "F" + num; num++; - LazyFont font = new LazyFont(embedFontInfo, resolver); + LazyFont font = new LazyFont(embedFontInfo, resourceResolver, false); fontInfo.addMetrics(internalName, font); List<FontTriplet> triplets = embedFontInfo.getFontTriplets(); @@ -221,32 +214,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..2c1d89088 100644 --- a/src/java/org/apache/fop/fonts/FontTriplet.java +++ b/src/java/org/apache/fop/fonts/FontTriplet.java @@ -27,6 +27,8 @@ import java.io.Serializable; */ public class FontTriplet implements Comparable<FontTriplet>, Serializable { + public static final FontTriplet DEFAULT_FONT_TRIPLET = new FontTriplet("any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); + /** serial version UID */ private static final long serialVersionUID = 1168991106658033508L; @@ -39,14 +41,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 +58,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; @@ -143,6 +137,5 @@ public class FontTriplet implements Comparable<FontTriplet>, Serializable { */ boolean matches(FontTriplet triplet); } - } diff --git a/src/java/org/apache/fop/fonts/LazyFont.java b/src/java/org/apache/fop/fonts/LazyFont.java index dfad4ffce..4c42387f2 100644 --- a/src/java/org/apache/fop/fonts/LazyFont.java +++ b/src/java/org/apache/fop/fonts/LazyFont.java @@ -20,19 +20,17 @@ 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.InternalResourceResolver; import org.apache.fop.complexscripts.fonts.Positionable; import org.apache.fop.complexscripts.fonts.Substitutable; @@ -43,49 +41,50 @@ 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 EmbeddingMode embeddingMode = EmbeddingMode.AUTO; - private boolean embedded = true; - 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 EmbeddingMode embeddingMode; + private final String subFontName; + private final boolean embedded; + private final InternalResourceResolver resourceResolver; 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 + * @param resourceResolver 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, InternalResourceResolver resourceResolver, + boolean useComplexScripts) { + this.metricsURI = fontInfo.getMetricsURI(); + this.fontEmbedURI = fontInfo.getEmbedURI(); this.useKerning = fontInfo.getKerning(); - if ( resolver != null ) { - this.useAdvanced = resolver.isComplexScriptFeaturesEnabled(); + if (resourceResolver != null) { + this.useAdvanced = useComplexScripts; } else { this.useAdvanced = fontInfo.getAdvanced(); } - this.encodingMode = fontInfo.getEncodingMode(); - this.embeddingMode = fontInfo.getEmbeddingMode(); + this.encodingMode = fontInfo.getEncodingMode() != null ? fontInfo.getEncodingMode() + : EncodingMode.AUTO; + this.embeddingMode = fontInfo.getEmbeddingMode() != null ? fontInfo.getEmbeddingMode() + : EmbeddingMode.AUTO; this.subFontName = fontInfo.getSubFontName(); this.embedded = fontInfo.isEmbedded(); - this.resolver = resolver; + this.resourceResolver = resourceResolver; } /** {@inheritDoc} */ 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('}'); @@ -95,75 +94,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 = resourceResolver.getResource(metricsURI); + InputSource src = new InputSource(in); + src.setSystemId(metricsURI.toASCIIString()); + reader = new FontReader(src, resourceResolver); 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, subFontName, - embedded, embeddingMode, encodingMode, - useKerning, useAdvanced, resolver); + realFont = FontLoader.loadFont(fontEmbedURI, subFontName, embedded, + embeddingMode, encodingMode, useKerning, useAdvanced, resourceResolver); } 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 54b772b2e..a460140cb 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.InternalResourceResolver; import org.apache.fop.complexscripts.fonts.GlyphDefinitionTable; import org.apache.fop.complexscripts.fonts.GlyphPositioningTable; import org.apache.fop.complexscripts.fonts.GlyphSubstitutionTable; @@ -68,7 +69,8 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl /** * Default constructor */ - public MultiByteFont() { + public MultiByteFont(InternalResourceResolver resourceResolver) { + super(resourceResolver); subset.setupFirstGlyph(); setFontType(FontType.TYPE0); } @@ -123,7 +125,7 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl /** {@inheritDoc} */ public boolean isEmbeddable() { - return !(getEmbedFileName() == null && getEmbedResourceName() == null); + return !(getEmbedFileURI() == null && getEmbedResourceName() == null); } public boolean isSubsetEmbedded() { @@ -553,7 +555,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 3ebc3c465..9ea323ebf 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 1aed72d69..cd11c7849 100644 --- a/src/java/org/apache/fop/fonts/SingleByteFont.java +++ b/src/java/org/apache/fop/fonts/SingleByteFont.java @@ -31,6 +31,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.xmlgraphics.fonts.Glyphs; +import org.apache.fop.apps.io.InternalResourceResolver; import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; /** @@ -53,15 +54,16 @@ public class SingleByteFont extends CustomFont { private PostScriptVersion ttPostScriptVersion; /** - * Main constructor. + * @param resourceResolver the URI resolver for controlling file access */ - public SingleByteFont() { + public SingleByteFont(InternalResourceResolver resourceResolver) { + super(resourceResolver); 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 224c8de2f..25b9e3924 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.Map; import java.util.Set; @@ -219,12 +221,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( @@ -465,7 +472,7 @@ public class TTFReader extends AbstractFontReader { if (isCid || kpx2.intValue() < 256) { el2 = doc.createElement("pair"); el2.setAttribute("kpx2", kpx2.toString()); - Integer val = (Integer)h2.get(kpx2); + Integer val = h2.get(kpx2); el2.setAttribute("kern", val.toString()); el.appendChild(el2); } diff --git a/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java b/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java index deee4b018..e115264bb 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.InternalResourceResolver; import org.apache.fop.fonts.CustomFont; import org.apache.fop.fonts.EmbedFontInfo; import org.apache.fop.fonts.EmbeddingMode; @@ -38,7 +39,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; @@ -134,26 +134,25 @@ 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, InternalResourceResolver resourceResolver) { 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, + EncodingMode.AUTO, EmbeddingMode.AUTO); fontInfo.setPostScriptName(customFont.getFontName()); if (fontCache != null) { - fontCache.addFont(fontInfo); + fontCache.addFont(fontInfo, resourceResolver); } return fontInfo; } @@ -161,32 +160,31 @@ public class FontInfoFinder { /** * Attempts to determine EmbedFontInfo from a given font file. * - * @param fontURL font URL. Assumed to be local. - * @param resolver font resolver used to resolve font + * @param fontURI the URI of the font resource + * @param resourceResolver 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, InternalResourceResolver resourceResolver, FontCache fontCache) { + URI embedUri = resourceResolver.resolveFromBase(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; } @@ -195,19 +193,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 = resourceResolver.getResource(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 { @@ -222,23 +220,25 @@ public class FontInfoFinder { log.debug("Loading " + fontName); } try { - TTFFontLoader ttfLoader = new TTFFontLoader( - fontFileURL, fontName, true, EmbeddingMode.AUTO, EncodingMode.AUTO, - useKerning, useAdvanced, resolver); + TTFFontLoader ttfLoader = new TTFFontLoader(fontURI, fontName, true, + EmbeddingMode.AUTO, EncodingMode.AUTO, useKerning, useAdvanced, + resourceResolver); 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, + resourceResolver); if (fi != null) { embedFontInfoList.add(fi); } @@ -248,21 +248,22 @@ public class FontInfoFinder { } else { // The normal case try { - customFont = FontLoader.loadFont(fontURL, null, true, EmbeddingMode.AUTO, - EncodingMode.AUTO, resolver); + customFont = FontLoader.loadFont(fontURI, null, true, EmbeddingMode.AUTO, + EncodingMode.AUTO, useKerning, useAdvanced, resourceResolver); 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, resourceResolver); 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 5da25e4b4..790e885bc 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; } @@ -152,9 +124,9 @@ public class FontFileReader { final byte buf = read(); if (buf < 0) { - return (int)(256 + buf); + return (256 + buf); } else { - return (int)buf; + return buf; } } @@ -178,7 +150,7 @@ public class FontFileReader { */ public final int readTTFUShort() throws IOException { final int ret = (readTTFUByte() << 8) + readTTFUByte(); - return (int)ret; + return ret; } /** diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFile.java b/src/java/org/apache/fop/fonts/truetype/TTFFile.java index bc979f277..878af1124 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFile.java @@ -19,7 +19,9 @@ package org.apache.fop.fonts.truetype; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.BitSet; import java.util.Comparator; @@ -33,6 +35,7 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -1672,7 +1675,7 @@ public class TTFFile { for (Integer unicodeKey2 : ckpx.keySet()) { Integer cidKey2 = unicodeToGlyph(unicodeKey2.intValue()); - Integer kern = (Integer)ckpx.get(unicodeKey2); + Integer kern = ckpx.get(unicodeKey2); Iterator uniMap = mtxTab[cidKey2.intValue()].getUnicodeIndex().listIterator(); while (uniMap.hasNext()) { @@ -1838,6 +1841,8 @@ public class TTFFile { * @throws IOException In case of an I/O problem */ public final List<String> getTTCnames(FontFileReader in) throws IOException { + this.fontFile = in; + List<String> fontNames = new ArrayList<String>(); String tag = in.readTTFString(4); @@ -2011,12 +2016,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; TTFFile ttfFile = new TTFFile(useKerning, useAdvanced); - FontFileReader reader = new FontFileReader(args[0]); + stream = new FileInputStream(args[0]); + FontFileReader reader = new FontFileReader(stream); String name = null; if (args.length >= 2) { @@ -2029,6 +2036,8 @@ 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 1410239ee..c97b17211 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java @@ -21,17 +21,18 @@ package org.apache.fop.fonts.truetype; import java.io.IOException; import java.io.InputStream; +import java.net.URI; import java.util.Map; import java.util.Set; import org.apache.commons.io.IOUtils; +import org.apache.fop.apps.io.InternalResourceResolver; import org.apache.fop.fonts.CIDFontType; import org.apache.fop.fonts.CMapSegment; import org.apache.fop.fonts.EmbeddingMode; 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; @@ -53,10 +54,10 @@ public class TTFFontLoader extends FontLoader { /** * Default constructor * @param fontFileURI the URI representing the font file - * @param resolver the FontResolver for font URI resolution + * @param resourceResolver the resource resolver for font URI resolution */ - public TTFFontLoader(String fontFileURI, FontResolver resolver) { - this(fontFileURI, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO, true, true, resolver); + public TTFFontLoader(URI fontFileURI, InternalResourceResolver resourceResolver) { + this(fontFileURI, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO, true, true, resourceResolver); } /** @@ -71,9 +72,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, - boolean embedded, EmbeddingMode embeddingMode, EncodingMode encodingMode, - boolean useKerning, boolean useAdvanced, FontResolver resolver) { + public TTFFontLoader(URI fontFileURI, String subFontName, boolean embedded, + EmbeddingMode embeddingMode, EncodingMode encodingMode, boolean useKerning, + boolean useAdvanced, InternalResourceResolver resolver) { super(fontFileURI, embedded, useKerning, useAdvanced, resolver); this.subFontName = subFontName; this.encodingMode = encodingMode; @@ -98,7 +99,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 = resourceResolver.getResource(this.fontFileURI); try { TTFFile ttf = new TTFFile(useKerning, useAdvanced); FontFileReader reader = new FontFileReader(in); @@ -126,14 +127,13 @@ public class TTFFontLoader extends FontLoader { } if (isCid) { - multiFont = new MultiByteFont(); + multiFont = new MultiByteFont(resourceResolver); returnFont = multiFont; multiFont.setTTCName(ttcFontName); } else { - singleFont = new SingleByteFont(); + singleFont = new SingleByteFont(resourceResolver); returnFont = singleFont; } - returnFont.setResolver(resolver); returnFont.setFontName(ttf.getPostScriptName()); returnFont.setFullName(ttf.getFullName()); @@ -172,7 +172,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..853e23eb5 100644 --- a/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java +++ b/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java @@ -22,15 +22,19 @@ 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.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.apps.io.InternalResourceResolver; 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; @@ -40,6 +44,8 @@ import org.apache.fop.fonts.SingleByteFont; */ public class Type1FontLoader extends FontLoader { + private static final Log log = LogFactory.getLog(Type1FontLoader.class); + private SingleByteFont singleFont; /** @@ -47,12 +53,12 @@ public class Type1FontLoader extends FontLoader { * @param fontFileURI the URI to the PFB file of a Type 1 font * @param embedded indicates whether the font is embedded or referenced * @param useKerning indicates whether to load kerning information if available - * @param resolver the font resolver used to resolve URIs + * @param resourceResolver 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 { - super(fontFileURI, embedded, useKerning, true, resolver); + public Type1FontLoader(URI fontFileURI, boolean embedded, boolean useKerning, + InternalResourceResolver resourceResolver) throws IOException { + super(fontFileURI, embedded, useKerning, true, resourceResolver); } private String getPFMURI(String pfbURI) { @@ -71,17 +77,20 @@ 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++) { + for (String afmExtension : AFM_EXTENSIONS) { try { - afmUri = this.fontFileURI.substring(0, this.fontFileURI.length() - 4) - + AFM_EXTENSIONS[i]; - afmIn = openFontUri(resolver, afmUri); + afmUri = partialAfmUri + afmExtension; + afmIn = resourceResolver.getResource(afmUri); if (afmIn != null) { break; } } catch (IOException ioe) { // Ignore, AFM probably not available under the URI + } catch (URISyntaxException e) { + // Ignore, AFM probably not available under the URI } } if (afmIn != null) { @@ -93,12 +102,14 @@ public class Type1FontLoader extends FontLoader { } } - String pfmUri = getPFMURI(this.fontFileURI); + String pfmUri = getPFMURI(fontFileStr); InputStream pfmIn = null; try { - pfmIn = openFontUri(resolver, pfmUri); + pfmIn = resourceResolver.getResource(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 +137,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(resourceResolver); 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/hyphenation/Hyphenator.java b/src/java/org/apache/fop/hyphenation/Hyphenator.java index 062b0e922..31cf8e1c8 100644 --- a/src/java/org/apache/fop/hyphenation/Hyphenator.java +++ b/src/java/org/apache/fop/hyphenation/Hyphenator.java @@ -20,21 +20,20 @@ package org.apache.fop.hyphenation; import java.io.BufferedInputStream; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; +import java.net.URISyntaxException; import java.util.Map; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - import org.xml.sax.InputSource; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.apps.io.InternalResourceResolver; + /** * <p>This class is the main entry point to the hyphenation package. * You can use only the static methods or create an instance.</p> @@ -75,7 +74,7 @@ public final class Hyphenator { * @return the hyphenation tree */ public static HyphenationTree getHyphenationTree(String lang, - String country, HyphenationTreeResolver resolver, Map hyphPatNames) { + String country, InternalResourceResolver resolver, Map hyphPatNames) { String llccKey = HyphenationTreeCache.constructLlccKey(lang, country); HyphenationTreeCache cache = getHyphenationTreeCache(); @@ -126,12 +125,12 @@ public final class Hyphenator { * The hyphenation trees are cached. * @param lang the language * @param country the country (may be null or "none") - * @param resolver resolver to find the hyphenation files + * @param resourceResolver resolver to find the hyphenation files * @param hyphPatNames the map with user-configured hyphenation pattern file names * @return the hyphenation tree */ - private static HyphenationTree getHyphenationTree2(String lang, - String country, HyphenationTreeResolver resolver, Map hyphPatNames) { + public static HyphenationTree getHyphenationTree2(String lang, + String country, InternalResourceResolver resourceResolver, Map hyphPatNames) { String llccKey = HyphenationTreeCache.constructLlccKey(lang, country); HyphenationTreeCache cache = getHyphenationTreeCache(); @@ -147,8 +146,8 @@ public final class Hyphenator { key = llccKey; } - if (resolver != null) { - hTree = getUserHyphenationTree(key, resolver); + if (resourceResolver != null) { + hTree = getUserHyphenationTree(key, resourceResolver); } if (hTree == null) { hTree = getFopHyphenationTree(key); @@ -230,30 +229,11 @@ public final class Hyphenator { * Load tree from serialized file or xml file * using configuration settings * @param key language key for the requested hyphenation file - * @param hyphenDir base directory to find hyphenation files in - * @return the requested HypenationTree or null if it is not available - */ - public static HyphenationTree getUserHyphenationTree(String key, - String hyphenDir) { - final File baseDir = new File(hyphenDir); - HyphenationTreeResolver resolver = new HyphenationTreeResolver() { - public Source resolve(String href) { - File f = new File(baseDir, href); - return new StreamSource(f); - } - }; - return getUserHyphenationTree(key, resolver); - } - - /** - * Load tree from serialized file or xml file - * using configuration settings - * @param key language key for the requested hyphenation file - * @param resolver resolver to find the hyphenation files + * @param resourceResolver resource resolver to find the hyphenation files * @return the requested HypenationTree or null if it is not available */ public static HyphenationTree getUserHyphenationTree(String key, - HyphenationTreeResolver resolver) { + InternalResourceResolver resourceResolver) { HyphenationTree hTree = null; // I use here the following convention. The file name specified in // the configuration is taken as the base name. First we try @@ -262,93 +242,63 @@ public final class Hyphenator { // first try serialized object String name = key + ".hyp"; - Source source = resolver.resolve(name); - if (source != null) { + try { + InputStream in = getHyphenationTreeStream(name, resourceResolver); try { - InputStream in = null; - if (source instanceof StreamSource) { - in = ((StreamSource) source).getInputStream(); - } - if (in == null) { - if (source.getSystemId() != null) { - in = new java.net.URL(source.getSystemId()).openStream(); - } else { - throw new UnsupportedOperationException - ("Cannot load hyphenation pattern file" - + " with the supplied Source object: " + source); - } - } - in = new BufferedInputStream(in); - try { - hTree = readHyphenationTree(in); - } finally { - IOUtils.closeQuietly(in); - } - return hTree; - } catch (IOException ioe) { - if (log.isDebugEnabled()) { - log.debug("I/O problem while trying to load " + name, ioe); - } + hTree = readHyphenationTree(in); + } finally { + IOUtils.closeQuietly(in); + } + return hTree; + } catch (IOException ioe) { + if (log.isDebugEnabled()) { + log.debug("I/O problem while trying to load " + name, ioe); } } // try the raw XML file name = key + ".xml"; - source = resolver.resolve(name); - if (source != null) { - hTree = new HyphenationTree(); + hTree = new HyphenationTree(); + try { + InputStream in = getHyphenationTreeStream(name, resourceResolver); try { - InputStream in = null; - if (source instanceof StreamSource) { - in = ((StreamSource) source).getInputStream(); - } - if (in == null) { - if (source.getSystemId() != null) { - in = new java.net.URL(source.getSystemId()).openStream(); - } else { - throw new UnsupportedOperationException( - "Cannot load hyphenation pattern file" - + " with the supplied Source object: " + source); - } - } - if (!(in instanceof BufferedInputStream)) { - in = new BufferedInputStream(in); - } - try { - InputSource src = new InputSource(in); - src.setSystemId(source.getSystemId()); - hTree.loadPatterns(src); - } finally { - IOUtils.closeQuietly(in); - } - if (statisticsDump) { - System.out.println("Stats: "); - hTree.printStats(); - } - return hTree; - } catch (HyphenationException ex) { - log.error("Can't load user patterns from XML file " + source.getSystemId() - + ": " + ex.getMessage()); - return null; - } catch (IOException ioe) { - if (log.isDebugEnabled()) { - log.debug("I/O problem while trying to load " + name, ioe); - } - return null; + InputSource src = new InputSource(in); + src.setSystemId(name); + hTree.loadPatterns(src); + } finally { + IOUtils.closeQuietly(in); + } + if (statisticsDump) { + System.out.println("Stats: "); + hTree.printStats(); } - } else { + return hTree; + } catch (HyphenationException ex) { + log.error("Can't load user patterns from XML file " + name + ": " + ex.getMessage()); + return null; + } catch (IOException ioe) { if (log.isDebugEnabled()) { - log.debug("Could not load user hyphenation file for '" + key + "'."); + log.debug("I/O problem while trying to load " + name, ioe); } return null; } } + private static InputStream getHyphenationTreeStream(String name, + InternalResourceResolver resourceResolver) throws IOException { + try { + return new BufferedInputStream(resourceResolver.getResource(name)); + } catch (URISyntaxException use) { + log.debug("An exception was thrown while attempting to load " + name, use); + } + return null; + } + /** * Hyphenates a word. * @param lang the language * @param country the optional country code (may be null or "none") - * @param resolver resolver to find the hyphenation files + * @param resourceResolver resolver to find the hyphenation files * @param hyphPatNames the map with user-configured hyphenation pattern file names * @param word the word to hyphenate * @param leftMin the minimum number of characters before the hyphenation point @@ -356,15 +306,12 @@ public final class Hyphenator { * @return the hyphenation result */ public static Hyphenation hyphenate(String lang, String country, - HyphenationTreeResolver resolver, - Map hyphPatNames, - String word, - int leftMin, int rightMin) { - HyphenationTree hTree = getHyphenationTree(lang, country, resolver, hyphPatNames); + InternalResourceResolver resourceResolver, Map hyphPatNames, String word, int leftMin, + int rightMin) { + HyphenationTree hTree = getHyphenationTree(lang, country, resourceResolver, hyphPatNames); if (hTree == null) { return null; } return hTree.hyphenate(word, leftMin, rightMin); } - } 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..56c534f90 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java @@ -1396,11 +1396,10 @@ public class LineLayoutManager extends InlineStackingLayoutManager // TextLM which generate the hyphenation buffer, // since these properties inherit and could be specified // on an inline or wrapper below the block level. - Hyphenation hyph - = Hyphenator.hyphenate(hyphenationProperties.language.getString(), + Hyphenation hyph = Hyphenator.hyphenate(hyphenationProperties.language.getString(), hyphenationProperties.country.getString(), - getFObj().getUserAgent().getFactory().getHyphenationTreeResolver(), - getFObj().getUserAgent().getFactory().getHyphPatNames(), + getFObj().getUserAgent().getResourceResolver(), + 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/PDFDocument.java b/src/java/org/apache/fop/pdf/PDFDocument.java index 9850c605e..dad404d11 100644 --- a/src/java/org/apache/fop/pdf/PDFDocument.java +++ b/src/java/org/apache/fop/pdf/PDFDocument.java @@ -21,7 +21,6 @@ package org.apache.fop.pdf; // Java import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; @@ -719,24 +718,6 @@ public class PDFDocument { } /** - * Resolve a URI. - * - * @param uri the uri to resolve - * @throws java.io.FileNotFoundException if the URI could not be resolved - * @return the InputStream from the URI. - */ - protected InputStream resolveURI(String uri) - throws java.io.FileNotFoundException { - try { - /* TODO: Temporary hack to compile, improve later */ - return new java.net.URL(uri).openStream(); - } catch (Exception e) { - throw new java.io.FileNotFoundException( - "URI could not be resolved (" + e.getMessage() + "): " + uri); - } - } - - /** * Get an image from the image map. * * @param key the image key to look for 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 beb384dcf..633ce9dd1 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; @@ -1637,79 +1632,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(); - subset.readFont(reader, mbfont.getTTCName(), mbfont.getUsedGlyphs()); - byte[] subsetFont = subset.getFontSubset(); - // 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(); + subset.readFont(reader, mbfont.getTTCName(), mbfont.getUsedGlyphs()); + byte[] subsetFont = subset.getFontSubset(); + // 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/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/pdf/StreamCacheFactory.java b/src/java/org/apache/fop/pdf/StreamCacheFactory.java index 4e2d12eb2..aa4d665da 100644 --- a/src/java/org/apache/fop/pdf/StreamCacheFactory.java +++ b/src/java/org/apache/fop/pdf/StreamCacheFactory.java @@ -24,56 +24,24 @@ import java.io.IOException; /** * This class is serves as a factory from */ -public class StreamCacheFactory { +public final class StreamCacheFactory { - private static boolean defaultCacheToFile = false; - private static StreamCacheFactory fileInstance = null; - private static StreamCacheFactory memoryInstance = null; - - private boolean cacheToFile = false; + private static StreamCacheFactory memoryInstance = new StreamCacheFactory(); /** * Returns an instance of a StreamCacheFactory with the requested features. * @param cacheToFile True if file shall be cached using a temporary file * @return StreamCacheFactory the requested factory */ - public static StreamCacheFactory getInstance(boolean cacheToFile) { - if (cacheToFile) { - if (fileInstance == null) { - fileInstance = new StreamCacheFactory(true); - } - return fileInstance; - } else { - if (memoryInstance == null) { - memoryInstance = new StreamCacheFactory(false); - } - return memoryInstance; - } - } - - /** - * Returns an instance of a StreamCacheFactory depending on the default - * setting for cacheToFile. - * @return StreamCacheFactory the requested factory - */ public static StreamCacheFactory getInstance() { - return getInstance(defaultCacheToFile); - } - - /** - * Sets the global default for cacheToFile - * @param cacheToFile True if stream caches should be held in files. - */ - public static void setDefaultCacheToFile(boolean cacheToFile) { - defaultCacheToFile = cacheToFile; + return memoryInstance; } /** * Creates a new StreamCacheFactory. * @param cacheToFile True if file shall be cached using a temporary file */ - public StreamCacheFactory(boolean cacheToFile) { - this.cacheToFile = cacheToFile; + private StreamCacheFactory() { } /** @@ -83,11 +51,7 @@ public class StreamCacheFactory { * @return a new StreamCache for caching streams */ public StreamCache createStreamCache() throws IOException { - if (this.cacheToFile) { - return new TempFileStreamCache(); - } else { - return new InMemoryStreamCache(); - } + return new InMemoryStreamCache(); } /** @@ -98,20 +62,6 @@ public class StreamCacheFactory { * @return a new StreamCache for caching streams */ public StreamCache createStreamCache(int hintSize) throws IOException { - if (this.cacheToFile) { - return new TempFileStreamCache(); - } else { - return new InMemoryStreamCache(hintSize); - } - } - - /** - * Get the value of the global cacheToFile flag. - * @return the current cache to file flag - */ - public boolean getCacheToFile() { - return this.cacheToFile; + return new InMemoryStreamCache(hintSize); } - - } 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/DefaultRendererConfigurator.java b/src/java/org/apache/fop/render/DefaultRendererConfigurator.java new file mode 100644 index 000000000..061c25709 --- /dev/null +++ b/src/java/org/apache/fop/render/DefaultRendererConfigurator.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render; + +import java.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.RendererConfig.RendererConfigParser; + +/** + * This object represents the default renderer configurator and contains the methods for most the + * RendererConfigurators. + */ +public class DefaultRendererConfigurator extends PrintRendererConfigurator { + + public DefaultRendererConfigurator(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/PrintRenderer.java b/src/java/org/apache/fop/render/PrintRenderer.java index 96a62cb11..b1ff59c84 100644 --- a/src/java/org/apache/fop/render/PrintRenderer.java +++ b/src/java/org/apache/fop/render/PrintRenderer.java @@ -36,7 +36,6 @@ 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; @@ -53,9 +52,6 @@ public abstract class PrintRenderer extends AbstractRenderer { /** Font configuration */ protected FontInfo fontInfo; - /** Font resolver */ - protected FontResolver fontResolver = null; - /** list of fonts */ protected List<EmbedFontInfo> embedFontInfoList = null; @@ -88,11 +84,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.getResourceResolver(), getFontList(), + userAgent.isComplexScriptFeaturesEnabled()) }; fontManager.setup(getFontInfo(), fontCollections); } @@ -107,7 +103,7 @@ public abstract class PrintRenderer extends AbstractRenderer { String key = fontInfo.getInternalFontKey(triplet); if (key == null) { //Find a default fallback font as last resort - triplet = new FontTriplet("any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); + triplet = FontTriplet.DEFAULT_FONT_TRIPLET; key = fontInfo.getInternalFontKey(triplet); } return key; @@ -180,18 +176,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..8de2d1a92 100644 --- a/src/java/org/apache/fop/render/PrintRendererConfigurator.java +++ b/src/java/org/apache/fop/render/PrintRendererConfigurator.java @@ -19,124 +19,158 @@ 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.InternalResourceResolver; 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 { + + private final RendererConfigParser rendererConfigParser; - /** logger instance */ - protected static final Log log = LogFactory.getLog(PrintRendererConfigurator.class); + private final FontConfigurator<EmbedFontInfo> fontInfoConfigurator; /** * Default constructor * @param userAgent user agent */ - public PrintRendererConfigurator(FOUserAgent userAgent) { + 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, RendererConfigParser rendererConfigParser, + FontConfigurator<EmbedFontInfo> fontInfoConfigurator) { super(userAgent); + this.rendererConfigParser = rendererConfigParser; + this.fontInfoConfigurator = fontInfoConfigurator; } /** - * Builds a list of EmbedFontInfo objects for use with the setup() method. + * Returns the renderer configuration data for a specific renderer. * - * @param renderer print renderer - * @throws FOPException if something's wrong with the config data + * @param documentHandler the document handler + * @return the renderer configuration data + * @throws FOPException if an error occurs */ - 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(); + protected RendererConfig getRendererConfig(IFDocumentHandler documentHandler) throws FOPException { + return getRendererConfig(documentHandler.getMimeType()); + } - FontEventListener listener = new FontEventAdapter( - renderer.getUserAgent().getEventBroadcaster()); - List<EmbedFontInfo> embedFontInfoList = buildFontList(cfg, fontResolver, listener); - printRenderer.addFontList(embedFontInfoList); + /** + * gets the renderer configuration data for a specific renderer. + * + * @param mimeType the MIME type + * @return the renderer configuration data + * @throws FOPException if an error occurs + */ + protected RendererConfig getRendererConfig(String mimeType) throws FOPException { + return userAgent.getRendererConfig(mimeType, rendererConfigParser); } /** - * 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 + * gets the renderer configuration data for a specific renderer. + * + * @param renderer the renderer + * @return the renderer configuration data + * @throws FOPException if an error occurs */ - 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() ); - } + protected RendererConfig getRendererConfig(Renderer renderer) throws FOPException { + return getRendererConfig(renderer.getMimeType()); + } - 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; + /** + * Builds a list of EmbedFontInfo objects for use with the setup() method. + * + * @param renderer print renderer + * @throws FOPException if something's wrong with the config data + */ + public void configure(Renderer renderer) throws FOPException { + PrintRenderer printRenderer = (PrintRenderer) renderer; + List<EmbedFontInfo> embedFontInfoList = buildFontList(renderer.getMimeType()); + printRenderer.addFontList(embedFontInfoList); } - // ---=== 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.getResourceResolver(), mimeType)); + fontManager.setup(fontInfo, fontCollections.toArray(new FontCollection[fontCollections.size()])); + } + + protected abstract List<FontCollection> getDefaultFontCollection(); + + /** + * Returns the font collection for custom configured fonts. + * + * @param resolver the resource resolver + * @param mimeType the renderer MIME type + * @return the font collection + * @throws FOPException if an error occurs + */ + protected FontCollection getCustomFontCollection(InternalResourceResolver resolver, String mimeType) + throws FOPException { + List<EmbedFontInfo> fontList; + if (rendererConfigParser == null) { + fontList = Collections.<EmbedFontInfo>emptyList(); + } else { + fontList = fontInfoConfigurator.configure(getRendererConfig(mimeType).getFontInfoConfig()); } + return createCollectionFromFontList(resolver, fontList); + } + + /*** + * Creates the font collection given a list of embedded font infomation. + * + * @param resolver the resource resolver + * @param fontList the embedded font infomation + * @return the font collection + */ + protected FontCollection createCollectionFromFontList(InternalResourceResolver resolver, + List<EmbedFontInfo> fontList) { + return new CustomFontCollection(resolver, fontList, + userAgent.isComplexScriptFeaturesEnabled()); + } + + private List<EmbedFontInfo> buildFontList(String mimeType) throws FOPException { + return fontInfoConfigurator.configure(getRendererConfig(mimeType).getFontInfoConfig()); + } - fontManager.setup(fontInfo, - (FontCollection[])fontCollections.toArray( - new FontCollection[fontCollections.size()])); - documentHandler.setFontInfo(fontInfo); + public static PrintRendererConfigurator createDefaultInstance(FOUserAgent userAgent) { + return new PrintRendererConfigurator(userAgent, null) { + @Override + protected List<FontCollection> getDefaultFontCollection() { + throw new UnsupportedOperationException(); + } + }; } } diff --git a/src/java/org/apache/fop/render/RendererConfig.java b/src/java/org/apache/fop/render/RendererConfig.java new file mode 100644 index 000000000..4b3b63a51 --- /dev/null +++ b/src/java/org/apache/fop/render/RendererConfig.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render; + +import org.apache.avalon.framework.configuration.Configuration; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.fonts.FontConfig; + +/** + * Implementations of this interface have all the renderer-specific configuration data found in the + * FOP-conf. This object is just a data object that is created by the {@link RendererConfigParser} + * when the FOP conf is parsed. + */ +public interface RendererConfig { + + /** + * Returns the render-specific font configuration information. + * @return the font config + */ + FontConfig getFontInfoConfig(); + + /** + * Implementations of this interface parse the relevant renderer-specific configuration data + * within the FOP-conf and create a {@link RendererConfig}. + */ + public interface RendererConfigParser { + + /** + * Builds the object that contains the renderer configuration data. + * + * @param userAgent the user agent + * @param rendererConfiguration the Avalon config object for parsing the data + * @return the configuration data object + * @throws FOPException if an error occurs while parsing the fop conf + */ + RendererConfig build(FOUserAgent userAgent, Configuration rendererConfiguration) throws FOPException; + + /** + * The MIME type of the renderer. + * + * @return the mime type + */ + String getMimeType(); + } +} diff --git a/src/java/org/apache/fop/render/RendererConfigurator.java b/src/java/org/apache/fop/render/RendererConfigOption.java index 6dceeb74d..5b670d07a 100644 --- a/src/java/org/apache/fop/render/RendererConfigurator.java +++ b/src/java/org/apache/fop/render/RendererConfigOption.java @@ -19,16 +19,11 @@ package org.apache.fop.render; -import org.apache.fop.apps.FOPException; - /** - * Renderer configurator interface + * Implementations of this interface enumerate the various renderer configuration options available + * to users in the FOP conf. */ -public interface RendererConfigurator { - /** - * Configures a renderer - * @param renderer renderer - * @throws FOPException fop exception - */ - void configure(Renderer renderer) throws FOPException; +public interface RendererConfigOption { + /** The name of the option. */ + 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/afp/AFPCustomizable.java b/src/java/org/apache/fop/render/afp/AFPCustomizable.java index e0924c0d0..1bdb18cf2 100644 --- a/src/java/org/apache/fop/render/afp/AFPCustomizable.java +++ b/src/java/org/apache/fop/render/afp/AFPCustomizable.java @@ -19,6 +19,8 @@ package org.apache.fop.render.afp; +import java.net.URI; + import org.apache.fop.afp.AFPResourceLevelDefaults; /** @@ -152,10 +154,10 @@ public interface AFPCustomizable { boolean isStrokeGOCAText(); /** - * Sets the default resource group file path - * @param filePath the default resource group file path + * Sets the default resource group URI + * @param uri the default resource group URI */ - void setDefaultResourceGroupFilePath(String filePath); + void setDefaultResourceGroupUri(URI uri); /** * Sets the resource level defaults. The object passed in provides information which resource diff --git a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java index d427f9d7f..9c786acf5 100644 --- a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java +++ b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java @@ -24,6 +24,7 @@ import java.awt.Dimension; import java.awt.geom.AffineTransform; import java.io.IOException; import java.util.HashMap; +import java.net.URI; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -39,13 +40,13 @@ import org.apache.fop.afp.DataStream; import org.apache.fop.afp.fonts.AFPFontCollection; import org.apache.fop.afp.fonts.AFPPageFonts; import org.apache.fop.afp.modca.ResourceObject; -import org.apache.fop.afp.util.DefaultFOPResourceAccessor; -import org.apache.fop.afp.util.ResourceAccessor; +import org.apache.fop.afp.util.AFPResourceAccessor; import org.apache.fop.apps.MimeConstants; 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; @@ -54,13 +55,14 @@ 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.IFDocumentHandlerConfigurator; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFPainter; /** - * {@link org.apache.fop.render.intermediate.IFDocumentHandler} implementation that - * produces AFP (MO:DCA). + * {@link org.apache.fop.render.intermediate.IFDocumentHandler} implementation that produces AFP + * (MO:DCA). */ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler implements AFPCustomizable { @@ -109,8 +111,9 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler /** * Default constructor. */ - public AFPDocumentHandler() { - this.resourceManager = new AFPResourceManager(); + public AFPDocumentHandler(IFContext context) { + super(context); + this.resourceManager = new AFPResourceManager(context.getUserAgent().getResourceResolver()); this.paintingState = new AFPPaintingState(); this.unitConv = paintingState.getUnitConverter(); } @@ -127,13 +130,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) }; @@ -391,8 +394,8 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler } } else if (extension instanceof AFPIncludeFormMap) { AFPIncludeFormMap formMap = (AFPIncludeFormMap)extension; - ResourceAccessor accessor = new DefaultFOPResourceAccessor( - getUserAgent(), null, null); + AFPResourceAccessor accessor = new AFPResourceAccessor( + getUserAgent().getResourceResolver()); try { getResourceManager().createIncludedResource(formMap.getName(), formMap.getSrc(), accessor, @@ -546,9 +549,8 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler return paintingState.getFS45(); } - /** {@inheritDoc} */ - public void setDefaultResourceGroupFilePath(String filePath) { - resourceManager.setDefaultResourceGroupFilePath(filePath); + public void setDefaultResourceGroupUri(URI uri) { + resourceManager.setDefaultResourceGroupUri(uri); } /** {@inheritDoc} */ 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..eca76078f --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPFontConfig.java @@ -0,0 +1,442 @@ +/* + * 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.AFPResourceAccessor; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.io.InternalResourceResolver; +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(InternalResourceResolver resourceResolver, + AFPEventProducer eventProducer) throws IOException; + + AFPResourceAccessor getAccessor(InternalResourceResolver resourceResolver) { + return new AFPResourceAccessor(resourceResolver, 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(InternalResourceResolver resourceResolver, AFPEventProducer eventProducer) + throws IOException { + AFPResourceAccessor accessor = getAccessor(resourceResolver); + 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(InternalResourceResolver resourceResolver, AFPEventProducer eventProducer) + throws IOException { + CharacterSet characterSet = null; + if (base14 != null) { + try { + Typeface tf = getTypeFace(base14); + characterSet = CharacterSetBuilder.getSingleByteInstance() + .build(characterset, super.codePage, + super.encoding, tf, eventProducer); + } catch (ClassNotFoundException cnfe) { + String msg = "The base 14 font class for " + characterset + + " could not be found"; + LOG.error(msg); + } + } else { + AFPResourceAccessor accessor = getAccessor(resourceResolver); + characterSet = CharacterSetBuilder.getSingleByteInstance().buildSBCS( + characterset, super.codePage, super.encoding, accessor, eventProducer); + } + return getFontInfo(new OutlineFont(super.name, super.embeddable, characterSet), this); + } + } + + private static Typeface getTypeFace(String base14Name) throws ClassNotFoundException { + try { + Class<? extends Typeface> clazz = Class.forName("org.apache.fop.fonts.base14." + + base14Name).asSubclass(Typeface.class); + return clazz.newInstance(); + } catch (IllegalAccessException iae) { + LOG.error(iae.getMessage()); + } catch (ClassNotFoundException cnfe) { + LOG.error(cnfe.getMessage()); + } catch (InstantiationException ie) { + LOG.error(ie.getMessage()); + } + throw new ClassNotFoundException("Couldn't load file for AFP font with base14 name: " + + base14Name); + } + + 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(InternalResourceResolver resourceResolver, AFPEventProducer eventProducer) + throws IOException { + RasterFont rasterFont = new RasterFont(super.name, super.embeddable); + for (RasterCharactersetData charset : charsets) { + if (charset.base14 != null) { + try { + Typeface tf = getTypeFace(charset.base14); + rasterFont.addCharacterSet(charset.size, + CharacterSetBuilder.getSingleByteInstance().build( + charset.characterset, super.codePage, super.encoding, + tf, eventProducer)); + + } catch (ClassNotFoundException cnfe) { + String msg = "The base 14 font class for " + charset.characterset + + " could not be found"; + LOG.error(msg); + } catch (IOException ie) { + String msg = "The base 14 font class " + charset.characterset + + " could not be instantiated"; + LOG.error(msg); + } + } else { + AFPResourceAccessor accessor = getAccessor(resourceResolver); + 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/AFPForeignAttributeReader.java b/src/java/org/apache/fop/render/afp/AFPForeignAttributeReader.java index a03aaf816..5f155e277 100644 --- a/src/java/org/apache/fop/render/afp/AFPForeignAttributeReader.java +++ b/src/java/org/apache/fop/render/afp/AFPForeignAttributeReader.java @@ -19,7 +19,7 @@ package org.apache.fop.render.afp; -import java.io.File; +import java.net.URI; import java.util.Map; import org.apache.commons.logging.Log; @@ -46,7 +46,7 @@ public class AFPForeignAttributeReader { AFPElementMapping.NAMESPACE, "afp:resource-level"); /** the resource-group-file attribute */ - public static final QName RESOURCE_GROUP_FILE = new QName( + public static final QName RESOURCE_GROUP_URI = new QName( AFPElementMapping.NAMESPACE, "afp:resource-group-file"); /** @@ -64,7 +64,7 @@ public class AFPForeignAttributeReader { public AFPResourceInfo getResourceInfo(Map/*<QName, String>*/ foreignAttributes) { AFPResourceInfo resourceInfo = new AFPResourceInfo(); if (foreignAttributes != null && !foreignAttributes.isEmpty()) { - String resourceName = (String)foreignAttributes.get(RESOURCE_NAME); + String resourceName = (String) foreignAttributes.get(RESOURCE_NAME); if (resourceName != null) { resourceInfo.setName(resourceName); } @@ -82,45 +82,20 @@ public class AFPForeignAttributeReader { * @param foreignAttributes the foreign attributes * @return the resource level */ - public AFPResourceLevel getResourceLevel(Map/*<QName, String>*/ foreignAttributes) { + public AFPResourceLevel getResourceLevel(Map<QName, String> foreignAttributes) { AFPResourceLevel resourceLevel = null; if (foreignAttributes != null && !foreignAttributes.isEmpty()) { if (foreignAttributes.containsKey(RESOURCE_LEVEL)) { - String levelString = (String)foreignAttributes.get(RESOURCE_LEVEL); + String levelString = foreignAttributes.get(RESOURCE_LEVEL); resourceLevel = AFPResourceLevel.valueOf(levelString); // if external get resource group file attributes if (resourceLevel != null && resourceLevel.isExternal()) { - String resourceGroupFile - = (String)foreignAttributes.get(RESOURCE_GROUP_FILE); - if (resourceGroupFile == null) { - String msg = RESOURCE_GROUP_FILE + " not specified"; - LOG.error(msg); + String resourceGroupUri = foreignAttributes.get(RESOURCE_GROUP_URI); + if (resourceGroupUri == null) { + String msg = RESOURCE_GROUP_URI + " not specified"; throw new UnsupportedOperationException(msg); } - File resourceExternalGroupFile = new File(resourceGroupFile); - SecurityManager security = System.getSecurityManager(); - try { - if (security != null) { - security.checkWrite(resourceExternalGroupFile.getPath()); - } - } catch (SecurityException ex) { - String msg = "unable to gain write access to external resource file: " - + resourceGroupFile; - LOG.error(msg); - } - - try { - boolean exists = resourceExternalGroupFile.exists(); - if (exists) { - LOG.warn("overwriting external resource file: " - + resourceGroupFile); - } - resourceLevel.setExternalFilePath(resourceGroupFile); - } catch (SecurityException ex) { - String msg = "unable to gain read access to external resource file: " - + resourceGroupFile; - LOG.error(msg); - } + resourceLevel.setExternalUri(URI.create(resourceGroupUri)); } } } diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerSVG.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerSVG.java index 834304f6b..68d806a1c 100644 --- a/src/java/org/apache/fop/render/afp/AFPImageHandlerSVG.java +++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerSVG.java @@ -42,6 +42,7 @@ import org.apache.fop.afp.AFPObjectAreaInfo; import org.apache.fop.afp.AFPPaintingState; import org.apache.fop.afp.AFPResourceInfo; import org.apache.fop.afp.AFPResourceLevel; +import org.apache.fop.afp.AFPResourceLevel.ResourceType; import org.apache.fop.afp.AFPResourceManager; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.image.loader.batik.BatikImageFlavors; @@ -142,7 +143,7 @@ public class AFPImageHandlerSVG implements ImageHandler { //level not explicitly set/changed so default to inline for GOCA graphic objects // (due to a bug in the IBM AFP Workbench Viewer (2.04.01.07), hard copy works just fine) if (!resourceInfo.levelChanged()) { - resourceInfo.setLevel(new AFPResourceLevel(AFPResourceLevel.INLINE)); + resourceInfo.setLevel(new AFPResourceLevel(ResourceType.INLINE)); } } diff --git a/src/java/org/apache/fop/render/afp/AFPPainter.java b/src/java/org/apache/fop/render/afp/AFPPainter.java index 5d8c1a93f..47ff5dba1 100644 --- a/src/java/org/apache/fop/render/afp/AFPPainter.java +++ b/src/java/org/apache/fop/render/afp/AFPPainter.java @@ -51,6 +51,7 @@ import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; import org.apache.fop.afp.AFPBorderPainter; +import org.apache.fop.afp.AFPEventProducer; import org.apache.fop.afp.AFPObjectAreaInfo; import org.apache.fop.afp.AFPPaintingState; import org.apache.fop.afp.AFPResourceInfo; @@ -67,17 +68,14 @@ import org.apache.fop.afp.modca.AbstractPageObject; import org.apache.fop.afp.modca.PresentationTextObject; import org.apache.fop.afp.ptoca.PtocaBuilder; import org.apache.fop.afp.ptoca.PtocaProducer; -import org.apache.fop.afp.util.DefaultFOPResourceAccessor; -import org.apache.fop.afp.util.ResourceAccessor; +import org.apache.fop.afp.util.AFPResourceAccessor; import org.apache.fop.fonts.Font; -import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontTriplet; import org.apache.fop.fonts.Typeface; import org.apache.fop.render.ImageHandlerUtil; import org.apache.fop.render.RenderingContext; import org.apache.fop.render.intermediate.AbstractIFPainter; import org.apache.fop.render.intermediate.BorderPainter; -import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFState; import org.apache.fop.render.intermediate.IFUtil; @@ -88,7 +86,7 @@ import org.apache.fop.util.CharUtilities; /** * IFPainter implementation that produces AFP (MO:DCA). */ -public class AFPPainter extends AbstractIFPainter { +public class AFPPainter extends AbstractIFPainter<AFPDocumentHandler> { @@ -99,8 +97,6 @@ public class AFPPainter extends AbstractIFPainter { private static final int X = 0; private static final int Y = 1; - private final AFPDocumentHandler documentHandler; - /** the border painter */ private final AFPBorderPainterAdapter borderPainter; /** the rectangle painter */ @@ -109,37 +105,39 @@ public class AFPPainter extends AbstractIFPainter { /** unit converter */ private final AFPUnitConverter unitConv; + private final AFPEventProducer eventProducer; + /** * Default constructor. * @param documentHandler the parent document handler */ public AFPPainter(AFPDocumentHandler documentHandler) { - super(); - this.documentHandler = documentHandler; + super(documentHandler); this.state = IFState.create(); this.borderPainter = new AFPBorderPainterAdapter( new AFPBorderPainter(getPaintingState(), getDataStream()), this, documentHandler); this.rectanglePainter = documentHandler.createRectanglePainter(); this.unitConv = getPaintingState().getUnitConverter(); + this.eventProducer = AFPEventProducer.Provider.get(getUserAgent().getEventBroadcaster()); } - /** {@inheritDoc} */ - @Override - protected IFContext getContext() { - return this.documentHandler.getContext(); - } - - FontInfo getFontInfo() { - return this.documentHandler.getFontInfo(); + private AFPPaintingState getPaintingState() { + return getDocumentHandler().getPaintingState(); } - AFPPaintingState getPaintingState() { - return this.documentHandler.getPaintingState(); + private DataStream getDataStream() { + return getDocumentHandler().getDataStream(); } - DataStream getDataStream() { - return this.documentHandler.getDataStream(); + @Override + public String getFontKey(FontTriplet triplet) throws IFException { + try { + return super.getFontKey(triplet); + } catch (IFException e) { + eventProducer.invalidConfiguration(null, e); + return super.getFontKey(FontTriplet.DEFAULT_FONT_TRIPLET); + } } /** {@inheritDoc} */ @@ -205,7 +203,7 @@ public class AFPPainter extends AbstractIFPainter { protected RenderingContext createRenderingContext() { AFPRenderingContext renderingContext = new AFPRenderingContext( getUserAgent(), - documentHandler.getResourceManager(), + getDocumentHandler().getResourceManager(), getPaintingState(), getFontInfo(), getContext().getForeignAttributes()); @@ -214,7 +212,7 @@ public class AFPPainter extends AbstractIFPainter { /** {@inheritDoc} */ public void drawImage(String uri, Rectangle rect) throws IFException { - PageSegmentDescriptor pageSegment = documentHandler.getPageSegmentNameFor(uri); + PageSegmentDescriptor pageSegment = getDocumentHandler().getPageSegmentNameFor(uri); if (pageSegment != null) { float[] srcPts = {rect.x, rect.y}; @@ -227,11 +225,11 @@ 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); + AFPResourceAccessor accessor = new AFPResourceAccessor( + getDocumentHandler().getUserAgent().getResourceResolver()); try { URI resourceUri = new URI(pageSegment.getURI()); - documentHandler.getResourceManager().createIncludedResourceFromExternal( + getDocumentHandler().getResourceManager().createIncludedResourceFromExternal( pageSegment.getName(), resourceUri, accessor); } catch (URISyntaxException urie) { @@ -1186,14 +1184,10 @@ public class AFPPainter extends AbstractIFPainter { FontTriplet triplet = new FontTriplet( state.getFontFamily(), state.getFontStyle(), state.getFontWeight()); //TODO Ignored: state.getFontVariant() - String fontKey = getFontInfo().getInternalFontKey(triplet); - if (fontKey == null) { - triplet = new FontTriplet("any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontKey = getFontInfo().getInternalFontKey(triplet); - } + String fontKey = getFontKey(triplet); // register font as necessary - Map<String, Typeface> fontMetricMap = documentHandler.getFontInfo().getFonts(); + Map<String, Typeface> fontMetricMap = getFontInfo().getFonts(); final AFPFont afpFont = (AFPFont)fontMetricMap.get(fontKey); final Font font = getFontInfo().getFontInstance(triplet, fontSize); AFPPageFonts pageFonts = getPaintingState().getPageFonts(); @@ -1207,7 +1201,7 @@ public class AFPPainter extends AbstractIFPainter { if (afpFont.isEmbeddable()) { try { - documentHandler.getResourceManager().embedFont(afpFont, charSet); + getDocumentHandler().getResourceManager().embedFont(afpFont, charSet); } catch (IOException ioe) { throw new IFException("Error while embedding font resources", ioe); } 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..90cc6e767 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPRendererConfig.java @@ -0,0 +1,375 @@ +/* + * 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.net.URI; +import java.net.URISyntaxException; +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.apps.io.InternalResourceResolver; +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.AFPRendererOption.DEFAULT_RESOURCE_LEVELS; +import static org.apache.fop.render.afp.AFPRendererOption.GOCA; +import static org.apache.fop.render.afp.AFPRendererOption.GOCA_TEXT; +import static org.apache.fop.render.afp.AFPRendererOption.IMAGES; +import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_DITHERING_QUALITY; +import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_FS45; +import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_JPEG; +import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_MAPPING_OPTION; +import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_MODE; +import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_NATIVE; +import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_WRAP_PSEG; +import static org.apache.fop.render.afp.AFPRendererOption.JPEG_ALLOW_JPEG_EMBEDDING; +import static org.apache.fop.render.afp.AFPRendererOption.JPEG_BITMAP_ENCODING_QUALITY; +import static org.apache.fop.render.afp.AFPRendererOption.LINE_WIDTH_CORRECTION; +import static org.apache.fop.render.afp.AFPRendererOption.RENDERER_RESOLUTION; +import static org.apache.fop.render.afp.AFPRendererOption.RESOURCE_GROUP_URI; +import static org.apache.fop.render.afp.AFPRendererOption.SHADING; + +/** + * The AFP renderer config object. + */ +public final class AFPRendererConfig implements RendererConfig { + + /** + * An enumeration for the various images modes available to the AFP renderer. + */ + 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); + } + } + + private final EnumMap<AFPRendererOption, Object> params = new EnumMap<AFPRendererOption, Object>(AFPRendererOption.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 URI getDefaultResourceGroupUri() { + return getParam(RESOURCE_GROUP_URI, URI.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(AFPRendererOption options, Class<T> type) { + assert options.getType().equals(type); + return type.cast(params.get(options)); + } + + private <T> void setParam(AFPRendererOption option, T value) { + assert option.getType().isInstance(value); + params.put(option, value); + } + + /** + * The parser for AFP renderer specific data in the FOP conf. + */ + public static final class AFPRendererConfigParser implements RendererConfigParser { + + private static final Log LOG = LogFactory.getLog(AFPRendererConfigParser.class); + + /** {@inheritDoc} */ + public AFPRendererConfig build(FOUserAgent userAgent, Configuration cfg) throws FOPException { + boolean strict = userAgent.validateUserConfigStrictly(); + 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; + } + + /** {@inheritDoc} */ + 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.getValueOf( + 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(AFPRendererOption 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(AFPRendererOption.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(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 resourceGroupUriCfg = cfg.getChild(RESOURCE_GROUP_URI.getName(), false); + if (resourceGroupUriCfg != null) { + URI resourceGroupUri = InternalResourceResolver.cleanURI(resourceGroupUriCfg.getValue()); + setParam(RESOURCE_GROUP_URI, resourceGroupUri); + } + } catch (ConfigurationException e) { + LogUtil.handleException(LOG, e, strict); + } catch (URISyntaxException use) { + LogUtil.handleException(LOG, use, strict); + } + } + + 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..3412c3d67 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.InternalResourceResolver; 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,104 @@ 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.isWrapPseg() != null) { + documentHandler.setWrapPSeg(config.isWrapPseg()); } - 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.isFs45() != null) { + documentHandler.setFS45(config.isFs45()); } - - // renderer resolution - Configuration lineWidthCorrectionCfg = cfg.getChild("line-width-correction", false); - if (lineWidthCorrectionCfg != null) { - customizable.setLineWidthCorrection(lineWidthCorrectionCfg - .getValueAsFloat(AFPConstants.LINE_WIDTH_CORRECTION)); + if (config.allowJpegEmbedding() != null) { + documentHandler.canEmbedJpeg(config.allowJpegEmbedding()); } - - // 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.getBitmapEncodingQuality() != null) { + documentHandler.setBitmapEncodingQuality(config.getBitmapEncodingQuality()); } - - 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.getLineWidthCorrection() != null) { + documentHandler.setLineWidthCorrection(config.getLineWidthCorrection()); + } + if (config.isGocaEnabled() != null) { + documentHandler.setGOCAEnabled(config.isGocaEnabled()); + } + if (config.isStrokeGocaText() != null) { + documentHandler.setStrokeGOCAText(config.isStrokeGocaText()); + } + if (config.getDefaultResourceGroupUri() != null) { + documentHandler.setDefaultResourceGroupUri(config.getDefaultResourceGroupUri()); + } + 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(InternalResourceResolver 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().getResourceResolver(), + eventProducer)); + } + return afpFonts; } } diff --git a/src/java/org/apache/fop/render/afp/AFPRendererOption.java b/src/java/org/apache/fop/render/afp/AFPRendererOption.java new file mode 100644 index 000000000..d573570d0 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPRendererOption.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package org.apache.fop.render.afp; + +import java.net.URI; + +import org.apache.fop.afp.AFPResourceLevelDefaults; +import org.apache.fop.render.RendererConfigOption; + +/** + * An enumeration of the configuration options available for the AFP renderer. + */ +public enum AFPRendererOption implements RendererConfigOption { + 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_URI("resource-group-file", URI.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 AFPRendererOption(String name, Class<?> type) { + this.name = name; + this.type = type; + } + + /** {@inheritDoc}}*/ + public String getName() { + return name; + } + + public Class<?> getType() { + return type; + } +} 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/afp/AFPShadingMode.java b/src/java/org/apache/fop/render/afp/AFPShadingMode.java index b45c33a8e..7e963148a 100644 --- a/src/java/org/apache/fop/render/afp/AFPShadingMode.java +++ b/src/java/org/apache/fop/render/afp/AFPShadingMode.java @@ -20,17 +20,13 @@ package org.apache.fop.render.afp; import java.io.ObjectStreamException; -import java.io.Serializable; - -/** Enumeration class for the AFP shading mode. */ -public final class AFPShadingMode implements Serializable { - - private static final long serialVersionUID = 8579867898716480779L; +/** Enumeration of the AFP shading modes. */ +public enum AFPShadingMode { /** the color mode (the default) */ - public static final AFPShadingMode COLOR = new AFPShadingMode("COLOR"); + COLOR("COLOR"), /** the dithered mode */ - public static final AFPShadingMode DITHERED = new AFPShadingMode("DITHERED"); + DITHERED("DITHERED"); private String name; @@ -52,7 +48,7 @@ public final class AFPShadingMode implements Serializable { * @param name the name of the enumeration value * @return the enumeration object */ - public static AFPShadingMode valueOf(String name) { + public static AFPShadingMode getValueOf(String name) { if (COLOR.getName().equalsIgnoreCase(name)) { return COLOR; } else if (DITHERED.getName().equalsIgnoreCase(name)) { @@ -70,5 +66,4 @@ public final class AFPShadingMode implements Serializable { public String toString() { return getClass().getName() + ":" + name; } - } 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 0c6ebde56..262caa53b 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; @@ -80,7 +80,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} */ @@ -98,18 +105,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(); /** @@ -228,7 +223,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..828f41d34 --- /dev/null +++ b/src/java/org/apache/fop/render/bitmap/BitmapRendererConfig.java @@ -0,0 +1,178 @@ +/* + * 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.BitmapRendererOption.ANTI_ALIASING; +import static org.apache.fop.render.bitmap.BitmapRendererOption.BACKGROUND_COLOR; +import static org.apache.fop.render.bitmap.BitmapRendererOption.COLOR_MODE; +import static org.apache.fop.render.bitmap.BitmapRendererOption.JAVA2D_TRANSPARENT_PAGE_BACKGROUND; +import static org.apache.fop.render.bitmap.BitmapRendererOption.RENDERING_QUALITY; +import static org.apache.fop.render.bitmap.BitmapRendererOption.RENDERING_QUALITY_ELEMENT; +import static org.apache.fop.render.bitmap.BitmapRendererOption.RENDERING_SPEED; + +/** + * The Bitmap renderer config data object. + */ +public class BitmapRendererConfig implements RendererConfig { + + private final EnumMap<BitmapRendererOption, Object> params + = new EnumMap<BitmapRendererOption, Object>(BitmapRendererOption.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(BitmapRendererOption option) { + return params.get(option); + } + + /** + * The parser for the Bitmap renderer configuration data. + */ + public static class BitmapRendererConfigParser implements RendererConfigParser { + + private final String mimeType; + + public BitmapRendererConfigParser(String mimeType) { + this.mimeType = mimeType; + } + + private void setParam(BitmapRendererConfig config, BitmapRendererOption option, + Object value) { + config.params.put(option, value != null ? value : option.getDefaultValue()); + } + + 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, BitmapRendererOption.ANTI_ALIASING, + getChild(cfg, ANTI_ALIASING).getValueAsBoolean( + (Boolean) ANTI_ALIASING.getDefaultValue())); + + String optimization = getValue(cfg, RENDERING_QUALITY_ELEMENT); + setParam(config, RENDERING_QUALITY, + !(BitmapRendererOption.getValue(optimization) == RENDERING_SPEED)); + + String color = getValue(cfg, COLOR_MODE); + setParam(config, COLOR_MODE, + getBufferedImageIntegerFromColor(BitmapRendererOption.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(BitmapRendererOption 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, BitmapRendererOption option) { + return cfg.getChild(option.getName()); + } + + private String getValue(Configuration cfg, BitmapRendererOption option) { + return cfg.getChild(option.getName()).getValue(null); + } + + public String getMimeType() { + return mimeType; + } + } +} diff --git a/src/java/org/apache/fop/render/bitmap/BitmapRendererConfigurator.java b/src/java/org/apache/fop/render/bitmap/BitmapRendererConfigurator.java index 2ca0a172b..f0e32a9d7 100644 --- a/src/java/org/apache/fop/render/bitmap/BitmapRendererConfigurator.java +++ b/src/java/org/apache/fop/render/bitmap/BitmapRendererConfigurator.java @@ -19,123 +19,84 @@ 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.apps.MimeConstants; +import org.apache.fop.apps.io.InternalResourceResolver; +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.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) { - super(userAgent); + public BitmapRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser) { + super(userAgent, rendererConfigParser); } // ---=== 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(); + configure(documentHandler, settings, + new BitmapRendererConfigParser(MimeConstants.MIME_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 FontCollection createCollectionFromFontList(InternalResourceResolver resourceResolver, + List<EmbedFontInfo> fontList) { + return new ConfiguredFontCollection(resourceResolver, fontList, userAgent.isComplexScriptFeaturesEnabled()); } + @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/BitmapRendererOption.java b/src/java/org/apache/fop/render/bitmap/BitmapRendererOption.java new file mode 100644 index 000000000..d6030b5ac --- /dev/null +++ b/src/java/org/apache/fop/render/bitmap/BitmapRendererOption.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.bitmap; + +import java.awt.Color; +import java.awt.image.BufferedImage; + +import org.apache.fop.render.RendererConfigOption; + +/** + * An enumeration of the Bitmap renderer configuration opetions available to the user via the FOP + * conf. + */ +public enum BitmapRendererOption implements RendererConfigOption { + 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 BitmapRendererOption(String name, Object defaultValue) { + this.name = name; + this.defaultValue = defaultValue; + } + + private BitmapRendererOption(String name) { + this(name, null); + } + + /** {@inheritDoc} */ + public String getName() { + return name; + } + + public Object getDefaultValue() { + return defaultValue; + } + + public static BitmapRendererOption getValue(String str) { + for (BitmapRendererOption opt : BitmapRendererOption.values()) { + if (opt.getName().equalsIgnoreCase(str)) { + return opt; + } + } + return null; + } +} diff --git a/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java b/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java index 278cd6c48..d239fe0fd 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.BitmapRendererOption.ANTI_ALIASING; +import static org.apache.fop.render.bitmap.BitmapRendererOption.COLOR_MODE; +import static org.apache.fop.render.bitmap.BitmapRendererOption.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 ed92b852f..c63cd3a4d 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.bitmap.PNGRendererConfig.PNGRendererConfigParser; +import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; /** @@ -28,6 +30,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; @@ -40,7 +47,7 @@ public class PNGDocumentHandler extends AbstractBitmapDocumentHandler { /** {@inheritDoc} */ public IFDocumentHandlerConfigurator getConfigurator() { - return new BitmapRendererConfigurator(getUserAgent()); + return new BitmapRendererConfigurator(getUserAgent(), new PNGRendererConfigParser()); } } 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/PNGRendererConfig.java b/src/java/org/apache/fop/render/bitmap/PNGRendererConfig.java new file mode 100644 index 000000000..699faea51 --- /dev/null +++ b/src/java/org/apache/fop/render/bitmap/PNGRendererConfig.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +package org.apache.fop.render.bitmap; + +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; + +/** + * The PNG renderer configuration data object. + */ +public final class PNGRendererConfig extends BitmapRendererConfig { + + private PNGRendererConfig(DefaultFontConfig fontConfig) { + super(fontConfig); + } + + /** + * The PNG renderer configuration parser. + */ + public static class PNGRendererConfigParser implements RendererConfigParser { + + public PNGRendererConfig build(FOUserAgent userAgent, Configuration cfg) + throws FOPException { + return new PNGRendererConfig(new DefaultFontConfigParser().parse(cfg, + userAgent.validateStrictly())); + } + + /** {@inheritDoc} */ + public String getMimeType() { + return MimeConstants.MIME_PNG; + } + } +} diff --git a/src/java/org/apache/fop/render/bitmap/PNGRendererMaker.java b/src/java/org/apache/fop/render/bitmap/PNGRendererMaker.java index da19b2986..fb38b61f6 100644 --- a/src/java/org/apache/fop/render/bitmap/PNGRendererMaker.java +++ b/src/java/org/apache/fop/render/bitmap/PNGRendererMaker.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.PNGRendererConfig.PNGRendererConfigParser; import org.apache.fop.render.java2d.Java2DRendererConfigurator; /** @@ -33,23 +34,22 @@ 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 { + new Java2DRendererConfigurator(userAgent, new PNGRendererConfigParser()).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 1c9a39bbe..48e79520f 100644 --- a/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java +++ b/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java @@ -20,6 +20,8 @@ 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.IFDocumentHandlerConfigurator; /** @@ -28,11 +30,16 @@ 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"; @@ -40,7 +47,6 @@ 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..5417ecc1e --- /dev/null +++ b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfig.java @@ -0,0 +1,102 @@ +/* + * 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.RendererConfigOption; + +/** + * The renderer configuration object for the TIFF renderer. + */ +public final class TIFFRendererConfig extends BitmapRendererConfig { + + public enum TIFFRendererOption implements RendererConfigOption { + COMPRESSION("compression", TIFFCompressionValues.PACKBITS); + + private final String name; + private final Object defaultValue; + + private TIFFRendererOption(String name, Object defaultValue) { + this.name = name; + this.defaultValue = defaultValue; + } + + public String getName() { + return name; + } + + public Object getDefaultValue() { + return defaultValue; + } + } + + private final EnumMap<TIFFRendererOption, Object> params + = new EnumMap<TIFFRendererOption, Object>(TIFFRendererOption.class); + + private TIFFRendererConfig(DefaultFontConfig fontConfig) { + super(fontConfig); + } + + public TIFFCompressionValues getCompressionType() { + return (TIFFCompressionValues) params.get(TIFFRendererOption.COMPRESSION); + } + + /** + * The TIFF renderer configuration parser. + */ + public static final class TIFFRendererConfigParser extends BitmapRendererConfigParser { + + public TIFFRendererConfigParser() { + super(MimeConstants.MIME_TIFF); + } + + private TIFFRendererConfig config; + + private void setParam(TIFFRendererOption option, Object value) { + config.params.put(option, value != null ? value : option.getDefaultValue()); + } + + private String getValue(Configuration cfg, TIFFRendererOption option) { + return cfg.getChild(option.getName()).getValue(null); + } + + /** {@inheritDoc} */ + 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(TIFFRendererOption.COMPRESSION, + TIFFCompressionValues.getValue(getValue(cfg, + TIFFRendererOption.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..e0ee5b3b3 100644 --- a/src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFDocumentHandler.java +++ b/src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFDocumentHandler.java @@ -19,15 +19,14 @@ package org.apache.fop.render.intermediate; -import java.io.File; +import java.io.BufferedOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.net.URL; +import java.net.URI; import javax.xml.transform.Result; import javax.xml.transform.stream.StreamResult; -import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.fop.fonts.FontCollection; @@ -49,10 +48,14 @@ 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) { - StreamResult streamResult = (StreamResult)result; + StreamResult streamResult = (StreamResult) result; OutputStream out = streamResult.getOutputStream(); if (out == null) { if (streamResult.getWriter() != null) { @@ -60,22 +63,13 @@ public abstract class AbstractBinaryWritingIFDocumentHandler extends AbstractIFD "FOP cannot use a Writer. Please supply an OutputStream!"); } try { - URL url = new URL(streamResult.getSystemId()); - File f = FileUtils.toFile(url); - if (f != null) { - out = new java.io.FileOutputStream(f); - } else { - out = url.openConnection().getOutputStream(); - } + URI resultURI = URI.create(streamResult.getSystemId()); + out = new BufferedOutputStream(getUserAgent().getResourceResolver().getOutputStream(resultURI)); } catch (IOException ioe) { throw new IFException("I/O error while opening output stream" , ioe); } - out = new java.io.BufferedOutputStream(out); this.ownOutputStream = true; } - if (out == null) { - throw new IllegalArgumentException("Need a StreamResult with an OutputStream"); - } this.outputStream = out; } else { throw new UnsupportedOperationException( @@ -95,7 +89,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..0a949e777 100644 --- a/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java +++ b/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java @@ -30,19 +30,16 @@ import org.apache.fop.apps.FOUserAgent; */ public abstract class AbstractIFDocumentHandler implements IFDocumentHandler { - private IFContext ifContext; + 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 9651cf446..2205aea4c 100644 --- a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java +++ b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java @@ -45,8 +45,9 @@ 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.fonts.FontInfo; +import org.apache.fop.fonts.FontTriplet; import org.apache.fop.render.ImageHandler; import org.apache.fop.render.ImageHandlerRegistry; import org.apache.fop.render.ImageHandlerUtil; @@ -57,7 +58,7 @@ import org.apache.fop.traits.RuleStyle; /** * Abstract base class for IFPainter implementations. */ -public abstract class AbstractIFPainter implements IFPainter { +public abstract class AbstractIFPainter<T extends IFDocumentHandler> implements IFPainter { /** logging instance */ private static Log log = LogFactory.getLog(AbstractIFPainter.class); @@ -68,18 +69,39 @@ public abstract class AbstractIFPainter implements IFPainter { /** Holds the intermediate format state */ protected IFState state; + private final T documentHandler; /** * Default constructor. */ - public AbstractIFPainter() { + public AbstractIFPainter(T documentHandler) { + this.documentHandler = documentHandler; + } + + protected String getFontKey(FontTriplet triplet) throws IFException { + String key = getFontInfo().getInternalFontKey(triplet); + if (key == null) { + throw new IFException("The font triplet is not available: \"" + triplet + "\" " + + "for the MIME type: \"" + documentHandler.getMimeType() + "\""); + } + return key; } /** * Returns the intermediate format context object. * @return the context object */ - protected abstract IFContext getContext(); + protected IFContext getContext() { + return documentHandler.getContext(); + } + + protected FontInfo getFontInfo() { + return documentHandler.getFontInfo(); + } + + protected T getDocumentHandler() { + return documentHandler; + } /** * Returns the user agent. @@ -89,14 +111,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 +145,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 +211,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 +250,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 +276,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 +304,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/IFException.java b/src/java/org/apache/fop/render/intermediate/IFException.java index 7e12c301b..5f35c3e3a 100644 --- a/src/java/org/apache/fop/render/intermediate/IFException.java +++ b/src/java/org/apache/fop/render/intermediate/IFException.java @@ -27,32 +27,27 @@ public class IFException extends Exception { private static final long serialVersionUID = 0L; /** - * Constructs a new exception with the specified detail message and - * cause. <p>Note that the detail message associated with - * <code>cause</code> is <i>not</i> automatically incorporated in + * Constructs a new exception with the specified detail message and cause. <p>Note that the + * detail message associated with <code>cause</code> is <i>not</i> automatically incorporated in * this exception's detail message. * - * @param message the detail message (which is saved for later retrieval - * by the {@link #getMessage()} method). - * @param cause the cause (which is saved for later retrieval by the - * {@link #getCause()} method). (A <code>null</code> value is - * permitted, and indicates that the cause is nonexistent or - * unknown.) + * @param message the detail message (which is saved for later retrieval by the + * {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} + * method). (A <code>null</code> value is permitted, and indicates that the cause is + * nonexistent or unknown.) */ public IFException(String message, Exception cause) { super(message, cause); } /** - * Constructs a new exception with the cause. + * Constructs a new exception with the specified detail message. * - * @param cause the cause (which is saved for later retrieval by the - * {@link #getCause()} method). (A <code>null</code> value is - * permitted, and indicates that the cause is nonexistent or - * unknown.) + * @param message the detail message (which is saved for later retrieval by the + * {@link #getMessage()} method). */ - /*public IFException( Exception cause) { - super(cause); - }*/ - + public IFException(String message) { + super(message); + } } diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java index 293487ac2..24b7a924c 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 45b0c3a93..47a53deca 100644 --- a/src/java/org/apache/fop/render/intermediate/IFRenderer.java +++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java @@ -231,9 +231,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..753d9ff30 --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/IFRendererConfig.java @@ -0,0 +1,63 @@ +/* + * 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; + +/** + * The Intermediate Format renderer configuration data object. + */ +public final class IFRendererConfig implements RendererConfig { + + private final DefaultFontConfig fontConfig; + + private IFRendererConfig(DefaultFontConfig fontConfig) { + this.fontConfig = fontConfig; + } + + public FontConfig getFontInfoConfig() { + return fontConfig; + } + + /** + * The Intermediate Format configuration data parser. + */ + public static final class IFRendererConfigParser implements RendererConfigParser { + + /** {@inheritDoc} */ + public RendererConfig build(FOUserAgent userAgent, Configuration cfg) + throws FOPException { + return new IFRendererConfig(new DefaultFontConfigParser().parse(cfg, + userAgent.validateStrictly())); + } + + /** {@inheritDoc} */ + 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 4c6781706..749f68d78 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.DefaultRendererConfigurator; import org.apache.fop.render.RenderingContext; +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 DefaultRendererConfigurator(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) { @@ -750,7 +755,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 c4f681936..bdd7eb8a0 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 9c404be3e..0b410873b 100644 --- a/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java +++ b/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java @@ -19,21 +19,19 @@ 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.InternalResourceResolver; 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 +42,21 @@ public class ConfiguredFontCollection implements FontCollection { private static Log log = LogFactory.getLog(ConfiguredFontCollection.class); - private FontResolver fontResolver; - private List/*<EmbedFontInfo>*/ embedFontInfoList; + private final InternalResourceResolver resourceResolver; + private final List<EmbedFontInfo> embedFontInfoList; + private final boolean useComplexScripts; /** * Main constructor - * @param fontResolver a font resolver + * @param resourceResolver 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(InternalResourceResolver resourceResolver, + List<EmbedFontInfo> customFonts, boolean useComplexScriptFeatures) { + this.resourceResolver = resourceResolver; this.embedFontInfoList = customFonts; + this.useComplexScripts = useComplexScriptFeatures; } /** {@inheritDoc} */ @@ -72,43 +68,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, resourceResolver, useComplexScripts); + InputStream fontSource = resourceResolver.getResource(fontURI); font = new CustomFontMetricsMapper(fontMetrics, fontSource); } else { - CustomFont fontMetrics = FontLoader.loadFont( - fontFile, null, true, configFontInfo.getEmbeddingMode(), - EncodingMode.AUTO, - configFontInfo.getKerning(), - configFontInfo.getAdvanced(), fontResolver); + CustomFont fontMetrics = FontLoader.loadFont(fontURI, null, true, + configFontInfo.getEmbeddingMode(), configFontInfo.getEncodingMode(), + configFontInfo.getKerning(), configFontInfo.getAdvanced(), + resourceResolver); 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 36df00f20..e821e635d 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/Java2DDocumentHandler.java b/src/java/org/apache/fop/render/java2d/Java2DDocumentHandler.java new file mode 100644 index 000000000..87003f077 --- /dev/null +++ b/src/java/org/apache/fop/render/java2d/Java2DDocumentHandler.java @@ -0,0 +1,156 @@ +/* + * 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. + */ + +package org.apache.fop.render.java2d; + +import java.awt.Dimension; +import java.util.Locale; + +import javax.xml.transform.Result; + +import org.apache.fop.accessibility.StructureTreeEventHandler; +import org.apache.fop.fonts.FontInfo; +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.IFDocumentNavigationHandler; +import org.apache.fop.render.intermediate.IFException; +import org.apache.fop.render.intermediate.IFPainter; + +/** + * {@link org.apache.fop.render.intermediate.IFDocumentHandler} implementation that produces + * Graphics2D instance. + */ +public class Java2DDocumentHandler implements IFDocumentHandler { + + public void setContext(IFContext context) { + throw new UnsupportedOperationException(); + } + + public IFContext getContext() { + throw new UnsupportedOperationException(); + } + + public void setResult(Result result) throws IFException { + throw new UnsupportedOperationException(); + } + + public void setFontInfo(FontInfo fontInfo) { + throw new UnsupportedOperationException(); + } + + public FontInfo getFontInfo() { + throw new UnsupportedOperationException(); + } + + public void setDefaultFontInfo(FontInfo fontInfo) { + throw new UnsupportedOperationException(); + } + + public IFDocumentHandlerConfigurator getConfigurator() { + throw new UnsupportedOperationException(); + } + + public StructureTreeEventHandler getStructureTreeEventHandler() { + throw new UnsupportedOperationException(); + } + + public IFDocumentNavigationHandler getDocumentNavigationHandler() { + throw new UnsupportedOperationException(); + } + + public boolean supportsPagesOutOfOrder() { + throw new UnsupportedOperationException(); + } + + public String getMimeType() { + throw new UnsupportedOperationException(); + } + + public void startDocument() throws IFException { + throw new UnsupportedOperationException(); + } + + public void endDocument() throws IFException { + throw new UnsupportedOperationException(); + } + + public void setDocumentLocale(Locale locale) { + throw new UnsupportedOperationException(); + } + + public void startDocumentHeader() throws IFException { + throw new UnsupportedOperationException(); + } + + public void endDocumentHeader() throws IFException { + throw new UnsupportedOperationException(); + } + + public void startDocumentTrailer() throws IFException { + throw new UnsupportedOperationException(); + } + + public void endDocumentTrailer() throws IFException { + throw new UnsupportedOperationException(); + } + + public void startPageSequence(String id) throws IFException { + throw new UnsupportedOperationException(); + } + + public void endPageSequence() throws IFException { + throw new UnsupportedOperationException(); + } + + public void startPage(int index, String name, String pageMasterName, Dimension size) + throws IFException { + throw new UnsupportedOperationException(); + } + + public void endPage() throws IFException { + throw new UnsupportedOperationException(); + } + + public void startPageHeader() throws IFException { + throw new UnsupportedOperationException(); + } + + public void endPageHeader() throws IFException { + throw new UnsupportedOperationException(); + } + + public IFPainter startPageContent() throws IFException { + throw new UnsupportedOperationException(); + } + + public void endPageContent() throws IFException { + throw new UnsupportedOperationException(); + } + + public void startPageTrailer() throws IFException { + throw new UnsupportedOperationException(); + } + + public void endPageTrailer() throws IFException { + throw new UnsupportedOperationException(); + } + + public void handleExtensionObject(Object extension) throws IFException { + throw new UnsupportedOperationException(); + } +} diff --git a/src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java b/src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java index b0c003b91..70fe0b449 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java +++ b/src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java @@ -130,7 +130,7 @@ public class Java2DGraphicsState { */ public boolean updateFont(String name, int size) { - FontMetricsMapper mapper = (FontMetricsMapper)fontInfo.getMetricsFor(name); + FontMetricsMapper mapper = (FontMetricsMapper) fontInfo.getMetricsFor(name); boolean updateName = (!mapper.getFontName().equals( getGraph().getFont().getFontName())); boolean updateSize = (size != (getGraph().getFont().getSize() * 1000)); diff --git a/src/java/org/apache/fop/render/java2d/Java2DPainter.java b/src/java/org/apache/fop/render/java2d/Java2DPainter.java index 7e4d72c14..7b8a96b99 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DPainter.java +++ b/src/java/org/apache/fop/render/java2d/Java2DPainter.java @@ -47,10 +47,10 @@ import org.apache.fop.traits.RuleStyle; import org.apache.fop.util.CharUtilities; /** - * {@link org.apache.fop.render.intermediate.IFPainter} implementation - * that paints on a Graphics2D instance. + * {@link org.apache.fop.render.intermediate.IFPainter} implementation that paints on a Graphics2D + * instance. */ -public class Java2DPainter extends AbstractIFPainter { +public class Java2DPainter extends AbstractIFPainter<Java2DDocumentHandler> { /** the IF context */ protected IFContext ifContext; @@ -62,7 +62,7 @@ public class Java2DPainter extends AbstractIFPainter { /** The current state, holds a Graphics2D and its context */ protected Java2DGraphicsState g2dState; - private Stack g2dStateStack = new Stack(); + private Stack<Java2DGraphicsState> g2dStateStack = new Stack<Java2DGraphicsState>(); /** * Main constructor. @@ -83,7 +83,7 @@ public class Java2DPainter extends AbstractIFPainter { * @param state the IF state object */ public Java2DPainter(Graphics2D g2d, IFContext context, FontInfo fontInfo, IFState state) { - super(); + super(new Java2DDocumentHandler()); this.ifContext = context; if (state != null) { this.state = state.push(); @@ -258,7 +258,7 @@ public class Java2DPainter extends AbstractIFPainter { /** Restores the last graphics state from the stack. */ protected void restoreGraphicsState() { g2dState.dispose(); - g2dState = (Java2DGraphicsState)g2dStateStack.pop(); + g2dState = g2dStateStack.pop(); } private void concatenateTransformationMatrix(AffineTransform transform) throws IOException { diff --git a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java index 8b60df746..91d38675d 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.Java2DRendererOption.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.getResourceResolver(), 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..1ed0aec96 --- /dev/null +++ b/src/java/org/apache/fop/render/java2d/Java2DRendererConfig.java @@ -0,0 +1,83 @@ +/* + * 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.Java2DRendererOption.JAVA2D_TRANSPARENT_PAGE_BACKGROUND; + +/** + * The Java2D renderer configuration data object. + */ +public final class Java2DRendererConfig implements RendererConfig { + + private final EnumMap<Java2DRendererOption, Object> params + = new EnumMap<Java2DRendererOption, Object>(Java2DRendererOption.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)); + } + + /** + * The Java2D renderer configuration data parser. + */ + public static class Java2DRendererConfigParser implements RendererConfigParser { + + private final String mimeType; + + public Java2DRendererConfigParser(String mimeType) { + this.mimeType = mimeType; + } + + /** {@inheritDoc} */ + 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; + } + + /** {@inheritDoc} */ + 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..9ff2ccdbd 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.DefaultRendererConfigurator; import org.apache.fop.render.Renderer; +import org.apache.fop.render.RendererConfig.RendererConfigParser; /** * Configurerer for Java 2D renderer */ -public class Java2DRendererConfigurator extends PrintRendererConfigurator { +public class Java2DRendererConfigurator extends DefaultRendererConfigurator { /** * 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/ps/PSConfigurationConstants.java b/src/java/org/apache/fop/render/java2d/Java2DRendererOption.java index 6b3550f57..b25f05889 100644 --- a/src/java/org/apache/fop/render/ps/PSConfigurationConstants.java +++ b/src/java/org/apache/fop/render/java2d/Java2DRendererOption.java @@ -17,17 +17,21 @@ /* $Id$ */ -package org.apache.fop.render.ps; +package org.apache.fop.render.java2d; -/** - * Constants used for configuring PostScript output. - */ -public interface PSConfigurationConstants { +import org.apache.fop.render.RendererConfigOption; + +public enum Java2DRendererOption implements RendererConfigOption { + /** Rendering Options key for the controlling the transparent page background option. */ + JAVA2D_TRANSPARENT_PAGE_BACKGROUND("transparent-page-background"); + + private final String name; + + private Java2DRendererOption(String name) { + this.name = name; + } - /** 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"; + 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/Java2DRendererOption.java b/src/java/org/apache/fop/render/pcl/Java2DRendererOption.java new file mode 100644 index 000000000..cb23f7191 --- /dev/null +++ b/src/java/org/apache/fop/render/pcl/Java2DRendererOption.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. + */ + +package org.apache.fop.render.pcl; + +import org.apache.fop.render.RendererConfigOption; + +/** + * An enumeration of the renderer configuration options available to the Java2D renderer via the + * FOP conf. + */ +public enum Java2DRendererOption implements RendererConfigOption { + + 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 Java2DRendererOption(String name, Class<?> type) { + this.name = name; + this.type = type; + } + + /** {@inheritDoc} */ + public String getName() { + return name; + } + + Class<?> getType() { + return type; + } +} diff --git a/src/java/org/apache/fop/render/pcl/PCLDocumentHandler.java b/src/java/org/apache/fop/render/pcl/PCLDocumentHandler.java index 332b4a77d..a44205d06 100644 --- a/src/java/org/apache/fop/render/pcl/PCLDocumentHandler.java +++ b/src/java/org/apache/fop/render/pcl/PCLDocumentHandler.java @@ -32,7 +32,7 @@ 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; @@ -42,6 +42,7 @@ 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; /** @@ -74,7 +75,9 @@ public class PCLDocumentHandler extends AbstractBinaryWritingIFDocumentHandler /** * Default constructor. */ - public PCLDocumentHandler() { + public PCLDocumentHandler(IFContext context) { + super(context); + this.pclUtil = new PCLRenderingUtil(context.getUserAgent()); } /** {@inheritDoc} */ @@ -88,15 +91,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} */ @@ -227,7 +223,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())); @@ -276,7 +272,6 @@ public class PCLDocumentHandler extends AbstractBinaryWritingIFDocumentHandler public void endPageContent() throws IFException { if (this.currentImage != null) { try { - //ImageWriterUtil.saveAsPNG(this.currentImage, new java.io.File("D:/page.png")); Rectangle printArea = this.currentPageDefinition.getLogicalPageRect(); gen.setCursorPos(0, 0); gen.paintBitmap(this.currentImage, printArea.getSize(), true); 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/PCLGenerator.java b/src/java/org/apache/fop/render/pcl/PCLGenerator.java index 29fe77323..0db295a5a 100644 --- a/src/java/org/apache/fop/render/pcl/PCLGenerator.java +++ b/src/java/org/apache/fop/render/pcl/PCLGenerator.java @@ -677,13 +677,6 @@ public class PCLGenerator { } finally { g2d.dispose(); } - /* - try { - BatchDiffer.saveAsPNG(alpha, new java.io.File("D:/out-alpha.png")); - BatchDiffer.saveAsPNG(mask, new java.io.File("D:/out-mask.png")); - } catch (IOException e) { - e.printStackTrace(); - }*/ return mask; } else { return null; @@ -715,7 +708,6 @@ public class PCLGenerator { (int)Math.ceil(UnitConv.mpt2px(targetDim.height, effResolution))); } boolean scaled = !orgDim.equals(effDim); - //ImageWriterUtil.saveAsPNG(img, new java.io.File("D:/text-0-org.png")); boolean monochrome = isMonochromeImage(img); if (!monochrome) { 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 a057252d6..179a4f527 100644 --- a/src/java/org/apache/fop/render/pcl/PCLPainter.java +++ b/src/java/org/apache/fop/render/pcl/PCLPainter.java @@ -47,7 +47,6 @@ import org.apache.fop.fonts.FontTriplet; import org.apache.fop.render.ImageHandlerUtil; import org.apache.fop.render.RenderingContext; import org.apache.fop.render.intermediate.AbstractIFPainter; -import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFState; import org.apache.fop.render.intermediate.IFUtil; @@ -58,15 +57,12 @@ import org.apache.fop.traits.RuleStyle; import org.apache.fop.util.CharUtilities; /** - * {@link org.apache.fop.render.intermediate.IFPainter} implementation - * that produces PCL 5. + * {@link org.apache.fop.render.intermediate.IFPainter} implementation that produces PCL 5. */ -public class PCLPainter extends AbstractIFPainter implements PCLConstants { +public class PCLPainter extends AbstractIFPainter<PCLDocumentHandler> implements PCLConstants { private static final boolean DEBUG = false; - private PCLDocumentHandler parent; - /** The PCL generator */ private PCLGenerator gen; @@ -74,7 +70,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { private int currentPrintDirection = 0; //private GeneralPath currentPath = null; - private Stack graphicContextStack = new Stack(); + private Stack<GraphicContext> graphicContextStack = new Stack<GraphicContext>(); private GraphicContext graphicContext = new GraphicContext(); /** @@ -83,19 +79,14 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { * @param pageDefinition the page definition describing the page to be rendered */ public PCLPainter(PCLDocumentHandler parent, PCLPageDefinition pageDefinition) { - this.parent = parent; + super(parent); this.gen = parent.getPCLGenerator(); this.state = IFState.create(); this.currentPageDefinition = pageDefinition; } - /** {@inheritDoc} */ - public IFContext getContext() { - return this.parent.getContext(); - } - PCLRenderingUtil getPCLUtil() { - return this.parent.getPCLUtil(); + return getDocumentHandler().getPCLUtil(); } /** @return the target resolution */ @@ -231,7 +222,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { g2d.translate(-rect.x, -rect.y); Java2DPainter painter = new Java2DPainter(g2d, - getContext(), parent.getFontInfo(), state); + getContext(), getFontInfo(), state); try { painter.drawBorderRect(rect, top, bottom, left, right); } catch (IFException e) { @@ -266,7 +257,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { g2d.translate(-boundingBox.x, -boundingBox.y); Java2DPainter painter = new Java2DPainter(g2d, - getContext(), parent.getFontInfo(), state); + getContext(), getFontInfo(), state); try { painter.drawLine(start, end, width, color, style); } catch (IFException e) { @@ -323,9 +314,8 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { state.getFontFamily(), state.getFontStyle(), state.getFontWeight()); //TODO Ignored: state.getFontVariant() //TODO Opportunity for font caching if font state is more heavily used - String fontKey = parent.getFontInfo().getInternalFontKey(triplet); - boolean pclFont = getPCLUtil().isAllTextAsBitmaps() - ? false + String fontKey = getFontKey(triplet); + boolean pclFont = getPCLUtil().isAllTextAsBitmaps() ? false : HardcodedFonts.setFont(gen, fontKey, state.getFontSize(), text); if (pclFont) { drawTextNative(x, y, letterSpacing, wordSpacing, dp, text, triplet); @@ -354,7 +344,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { setCursorPos(x, y); float fontSize = state.getFontSize() / 1000f; - Font font = parent.getFontInfo().getFontInstance(triplet, state.getFontSize()); + Font font = getFontInfo().getFontInstance(triplet, state.getFontSize()); int l = text.length(); int[] dx = IFUtil.convertDPToDX ( dp ); int dxl = (dx != null ? dx.length : 0); @@ -446,11 +436,15 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { final int letterSpacing, final int wordSpacing, final int[][] dp, final String text, FontTriplet triplet) throws IFException { //Use Java2D to paint different fonts via bitmap - final Font font = parent.getFontInfo().getFontInstance(triplet, state.getFontSize()); + final Font font = getFontInfo().getFontInstance(triplet, state.getFontSize()); //for cursive fonts, so the text isn't clipped - final FontMetricsMapper mapper = (FontMetricsMapper)parent.getFontInfo().getMetricsFor( - font.getFontName()); + FontMetricsMapper mapper; + try { + mapper = (FontMetricsMapper) 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; @@ -478,8 +472,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { rect = new Rectangle(x, y, 1000, -descent); g2d.draw(rect); } - Java2DPainter painter = new Java2DPainter(g2d, - getContext(), parent.getFontInfo(), state); + Java2DPainter painter = new Java2DPainter(g2d, getContext(), getFontInfo(), state); try { painter.drawText(x, y, letterSpacing, wordSpacing, dp, text); } catch (IFException e) { @@ -504,7 +497,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { /** Restores the last graphics state from the stack. */ private void restoreGraphicsState() { - graphicContext = (GraphicContext)graphicContextStack.pop(); + graphicContext = graphicContextStack.pop(); } private void concatenateTransformationMatrix(AffineTransform transform) throws IOException { 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..29fccc2c8 --- /dev/null +++ b/src/java/org/apache/fop/render/pcl/PCLRendererConfig.java @@ -0,0 +1,123 @@ +/* + * 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.Java2DRendererOption.DISABLE_PJL; +import static org.apache.fop.render.pcl.Java2DRendererOption.RENDERING_MODE; +import static org.apache.fop.render.pcl.Java2DRendererOption.TEXT_RENDERING; + +/** + * The PCL renderer configuration data object. + */ +public final class PCLRendererConfig implements RendererConfig { + + private final Map<Java2DRendererOption, Object> params + = new EnumMap<Java2DRendererOption, Object>(Java2DRendererOption.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(Java2DRendererOption option, Class<T> type) { + assert option.getType().equals(type); + return type.cast(params.get(option)); + } + + private <T> void setParam(Java2DRendererOption option, T value) { + assert option.getType().isInstance(value); + params.put(option, value); + } + + /** + * The PCL renderer configuration data parser. + */ + public static final class PCLRendererConfigParser implements RendererConfigParser { + + /** {@inheritDoc} */ + 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)); + } + } + + /** {@inheritDoc} */ + 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..d103b4796 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.InternalResourceResolver; +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(InternalResourceResolver resourceResolver, + List<EmbedFontInfo> fontList) { + return new ConfiguredFontCollection(resourceResolver, 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..afea5a7fe 100644 --- a/src/java/org/apache/fop/render/pcl/PCLRenderingMode.java +++ b/src/java/org/apache/fop/render/pcl/PCLRenderingMode.java @@ -20,25 +20,22 @@ package org.apache.fop.render.pcl; import java.io.ObjectStreamException; -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 { /** "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 +67,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..dd9320571 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java @@ -40,7 +40,6 @@ import org.apache.fop.fo.extensions.xmp.XMPMetadata; import org.apache.fop.pdf.PDFAnnotList; import org.apache.fop.pdf.PDFDocument; import org.apache.fop.pdf.PDFPage; -import org.apache.fop.pdf.PDFResourceContext; import org.apache.fop.pdf.PDFResources; import org.apache.fop.render.extensions.prepress.PageBoundaries; import org.apache.fop.render.extensions.prepress.PageScale; @@ -50,6 +49,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; /** @@ -67,31 +67,28 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { private PDFStructureTreeBuilder structureTreeBuilder; /** the PDF Document being created */ - protected PDFDocument pdfDoc; + private PDFDocument pdfDoc; /** * Utility class which enables all sorts of features that are not directly connected to the * normal rendering process. */ - protected PDFRenderingUtil pdfUtil; + private final PDFRenderingUtil pdfUtil; /** the /Resources object of the PDF document being created */ - protected PDFResources pdfResources; + private PDFResources pdfResources; /** The current content generator */ - protected PDFContentGenerator generator; - - /** the current annotation list to add annotations to */ - protected PDFResourceContext currentContext; + private PDFContentGenerator generator; /** the current page to add annotations to */ - protected PDFPage currentPage; + private PDFPage currentPage; /** the current page's PDF reference */ - protected PageReference currentPageRef; + private PageReference currentPageRef; /** Used for bookmarks/outlines. */ - protected Map<Integer, PageReference> pageReferences = new HashMap<Integer, PageReference>(); + private Map<Integer, PageReference> pageReferences = new HashMap<Integer, PageReference>(); private final PDFDocumentNavigationHandler documentNavigationHandler = new PDFDocumentNavigationHandler(this); @@ -99,7 +96,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 +112,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} */ @@ -128,14 +121,30 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { return this.documentNavigationHandler; } - PDFRenderingUtil getPDFUtil() { - return this.pdfUtil; + void mergeRendererOptionsConfig(PDFRendererOptionsConfig config) { + pdfUtil.mergeRendererOptionsConfig(config); } PDFLogicalStructureHandler getLogicalStructureHandler() { return logicalStructureHandler; } + PDFDocument getPDFDocument() { + return pdfDoc; + } + + PDFPage getCurrentPage() { + return currentPage; + } + + PageReference getCurrentPageRef() { + return currentPageRef; + } + + PDFContentGenerator getGenerator() { + return generator; + } + /** {@inheritDoc} */ public void startDocument() throws IFException { super.startDocument(); @@ -174,7 +183,6 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { pdfResources = null; this.generator = null; - currentContext = null; currentPage = null; } catch (IOException ioe) { throw new IFException("I/O error in endDocument()", ioe); 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/PDFDocumentNavigationHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java index af49fea4c..1ef637726 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java @@ -63,7 +63,7 @@ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler } PDFDocument getPDFDoc() { - return this.documentHandler.pdfDoc; + return this.documentHandler.getPDFDocument(); } /** {@inheritDoc} */ @@ -100,7 +100,7 @@ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler /** {@inheritDoc} */ public void renderLink(Link link) throws IFException { Rectangle targetRect = link.getTargetRect(); - int pageHeight = documentHandler.currentPageRef.getPageDimension().height; + int pageHeight = documentHandler.getCurrentPageRef().getPageDimension().height; Rectangle2D targetRect2D = new Rectangle2D.Double( targetRect.getMinX() / 1000.0, (pageHeight - targetRect.getMinY() - targetRect.getHeight()) / 1000.0, @@ -116,7 +116,7 @@ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler if (documentHandler.getUserAgent().isAccessibilityEnabled() && structure != null) { documentHandler.getLogicalStructureHandler().addLinkContentItem(pdfLink, structure); } - documentHandler.currentPage.addAnnotation(pdfLink); + documentHandler.getCurrentPage().addAnnotation(pdfLink); } } diff --git a/src/java/org/apache/fop/render/pdf/PDFEncryptionOption.java b/src/java/org/apache/fop/render/pdf/PDFEncryptionOption.java new file mode 100644 index 000000000..f3e51e34a --- /dev/null +++ b/src/java/org/apache/fop/render/pdf/PDFEncryptionOption.java @@ -0,0 +1,98 @@ +/* + * 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.render.RendererConfigOption; + +public enum PDFEncryptionOption implements RendererConfigOption { + + /** + * 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", ""); + + public static final String ENCRYPTION_PARAMS = "encryption-params"; + + private final String name; + + private final Object defaultValue; + + private PDFEncryptionOption(String name, Object defaultValue) { + this.name = name; + this.defaultValue = defaultValue; + } + + private PDFEncryptionOption(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/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/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java index d7a335dcc..77ec1d3bf 100644 --- a/src/java/org/apache/fop/render/pdf/PDFPainter.java +++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java @@ -30,19 +30,16 @@ import java.io.IOException; import org.w3c.dom.Document; import org.apache.fop.fonts.Font; -import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontTriplet; import org.apache.fop.fonts.LazyFont; import org.apache.fop.fonts.SingleByteFont; import org.apache.fop.fonts.Typeface; -import org.apache.fop.pdf.PDFDocument; import org.apache.fop.pdf.PDFNumber; import org.apache.fop.pdf.PDFStructElem; import org.apache.fop.pdf.PDFTextUtil; import org.apache.fop.pdf.PDFXObject; import org.apache.fop.render.RenderingContext; import org.apache.fop.render.intermediate.AbstractIFPainter; -import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFState; import org.apache.fop.render.intermediate.IFUtil; @@ -55,9 +52,7 @@ import org.apache.fop.util.CharUtilities; /** * IFPainter implementation that produces PDF. */ -public class PDFPainter extends AbstractIFPainter { - - private final PDFDocumentHandler documentHandler; +public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> { /** The current content generator */ protected PDFContentGenerator generator; @@ -77,34 +72,15 @@ public class PDFPainter extends AbstractIFPainter { */ public PDFPainter(PDFDocumentHandler documentHandler, PDFLogicalStructureHandler logicalStructureHandler) { - super(); - this.documentHandler = documentHandler; + super(documentHandler); this.logicalStructureHandler = logicalStructureHandler; - this.generator = documentHandler.generator; + this.generator = documentHandler.getGenerator(); this.borderPainter = new PDFBorderPainter(this.generator); this.state = IFState.create(); accessEnabled = this.getUserAgent().isAccessibilityEnabled(); } /** {@inheritDoc} */ - @Override - protected IFContext getContext() { - return this.documentHandler.getContext(); - } - - PDFRenderingUtil getPDFUtil() { - return this.documentHandler.pdfUtil; - } - - PDFDocument getPDFDoc() { - return this.documentHandler.pdfDoc; - } - - FontInfo getFontInfo() { - return this.documentHandler.getFontInfo(); - } - - /** {@inheritDoc} */ public void startViewport(AffineTransform transform, Dimension size, Rectangle clipRect) throws IFException { generator.saveGraphicsState(); @@ -133,7 +109,7 @@ public class PDFPainter extends AbstractIFPainter { /** {@inheritDoc} */ public void drawImage(String uri, Rectangle rect) throws IFException { - PDFXObject xobject = getPDFDoc().getXObject(uri); + PDFXObject xobject = getDocumentHandler().getPDFDocument().getXObject(uri); if (xobject != null) { if (accessEnabled) { PDFStructElem structElem = (PDFStructElem) getContext().getStructureTreeElement(); @@ -160,7 +136,7 @@ public class PDFPainter extends AbstractIFPainter { @Override protected RenderingContext createRenderingContext() { PDFRenderingContext pdfContext = new PDFRenderingContext( - getUserAgent(), generator, this.documentHandler.currentPage, getFontInfo()); + getUserAgent(), generator, getDocumentHandler().getCurrentPage(), getFontInfo()); pdfContext.setMarkedContentInfo(imageMCI); return pdfContext; } @@ -334,12 +310,11 @@ public class PDFPainter extends AbstractIFPainter { } } - private void drawTextWithDX ( int x, int y, String text, FontTriplet triplet, - int letterSpacing, int wordSpacing, int[] dx ) { - + private void drawTextWithDX(int x, int y, String text, FontTriplet triplet, + int letterSpacing, int wordSpacing, int[] dx) throws IFException { //TODO Ignored: state.getFontVariant() //TODO Opportunity for font caching if font state is more heavily used - String fontKey = getFontInfo().getInternalFontKey(triplet); + String fontKey = getFontKey(triplet); int sizeMillipoints = state.getFontSize(); float fontSize = sizeMillipoints / 1000f; 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..049345609 --- /dev/null +++ b/src/java/org/apache/fop/render/pdf/PDFRendererConfig.java @@ -0,0 +1,227 @@ +/* + * 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.PDFEncryptionParams; +import org.apache.fop.pdf.PDFFilterList; +import org.apache.fop.render.RendererConfig; +import org.apache.fop.render.RendererConfigOption; +import org.apache.fop.util.LogUtil; + +import static org.apache.fop.render.pdf.PDFEncryptionOption.ENCRYPTION_LENGTH; +import static org.apache.fop.render.pdf.PDFEncryptionOption.ENCRYPTION_PARAMS; +import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_ACCESSCONTENT; +import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_ANNOTATIONS; +import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_ASSEMBLEDOC; +import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_COPY_CONTENT; +import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_EDIT_CONTENT; +import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_FILLINFORMS; +import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_PRINT; +import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_PRINTHQ; +import static org.apache.fop.render.pdf.PDFEncryptionOption.OWNER_PASSWORD; +import static org.apache.fop.render.pdf.PDFEncryptionOption.USER_PASSWORD; +import static org.apache.fop.render.pdf.PDFRendererOption.DISABLE_SRGB_COLORSPACE; +import static org.apache.fop.render.pdf.PDFRendererOption.FILTER_LIST; +import static org.apache.fop.render.pdf.PDFRendererOption.OUTPUT_PROFILE; +import static org.apache.fop.render.pdf.PDFRendererOption.PDF_A_MODE; +import static org.apache.fop.render.pdf.PDFRendererOption.PDF_X_MODE; +import static org.apache.fop.render.pdf.PDFRendererOption.VERSION; + +/** + * The PDF renderer configuration data object. + */ +public final class PDFRendererConfig implements RendererConfig { + + private static final Log LOG = LogFactory.getLog(PDFRendererConfig.class); + + private final PDFRendererOptionsConfig configOption; + + private final DefaultFontConfig fontConfig; + + private PDFRendererConfig(DefaultFontConfig fontConfig, PDFRendererOptionsConfig config) { + this.fontConfig = fontConfig; + this.configOption = config; + } + + public PDFRendererOptionsConfig getConfigOptions() { + return configOption; + } + + public DefaultFontConfig getFontInfoConfig() { + return fontConfig; + } + + /** + * The PDF renderer configuration data parser. + */ + 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 final Map<PDFRendererOption, Object> configOptions + = new EnumMap<PDFRendererOption, Object>(PDFRendererOption.class); + + private PDFEncryptionParams encryptionConfig; + + private PDFRendererConfig pdfConfig; + + private ParserHelper(Configuration cfg, FOUserAgent userAgent, boolean strict) throws FOPException { + if (cfg != null) { + configure(cfg, userAgent, strict); + } + pdfConfig = new PDFRendererConfig(new DefaultFontConfigParser().parse(cfg, strict), + new PDFRendererOptionsConfig(configOptions, encryptionConfig)); + } + + private void parseAndPut(PDFRendererOption option, Configuration cfg) { + put(option, option.parse(parseConfig(cfg, option))); + } + + private void put(PDFRendererOption option, Object value) { + if (value != null && !value.equals(option.getDefaultValue())) { + configOptions.put(option, value); + } + } + + private void configure(Configuration cfg, FOUserAgent userAgent, boolean strict) throws FOPException { + try { + buildFilterMapFromConfiguration(cfg); + parseAndPut(PDF_A_MODE, cfg); + parseAndPut(PDF_X_MODE, cfg); + configureEncryptionParams(cfg, userAgent, strict); + parseAndPut(OUTPUT_PROFILE, cfg); + parseAndPut(DISABLE_SRGB_COLORSPACE, cfg); + + parseAndPut(VERSION, cfg); + } catch (ConfigurationException e) { + LogUtil.handleException(LOG, e, strict); + } + } + + private void configureEncryptionParams(Configuration cfg, FOUserAgent userAgent, boolean strict) { + Configuration encryptCfg = cfg.getChild(ENCRYPTION_PARAMS, false); + if (encryptCfg != null) { + 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); + } + } + } + + 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, RendererConfigOption option) { + Configuration child = cfg.getChild(option.getName()); + return child.getValue(null); + } + + private boolean doesValueExist(Configuration cfg, RendererConfigOption option) { + return cfg.getChild(option.getName(), false) != 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/PDFRendererConfigurator.java b/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java index df5224c04..96a19db6a 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java +++ b/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java @@ -19,239 +19,30 @@ 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.DefaultRendererConfigurator; +import org.apache.fop.render.RendererConfig.RendererConfigParser; 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 DefaultRendererConfigurator { /** * 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); - } - - 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); - } - Configuration noPrintHqConfig = encryptionParamsConfig.getChild( - PDFConfigurationConstants.NO_PRINTHQ, false); - if (noPrintHqConfig != null) { - encryptionParams.setAllowPrintHq(false); - } - Configuration encryptionLengthConfig = encryptionParamsConfig.getChild( - PDFConfigurationConstants.ENCRYPTION_LENGTH, false); - if (encryptionLengthConfig != null) { - int encryptionLength = checkEncryptionLength( - Integer.parseInt(encryptionLengthConfig.getValue(null))); - encryptionParams.setEncryptionLengthInBits(encryptionLength); - } - } - - 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."); - } - } - } - - /** - * Builds a filter map from an Avalon Configuration object. - * - * @param cfg the Configuration object - * @return Map the newly built filter map - * @throws ConfigurationException if a filter list is defined twice - */ - public static Map buildFilterMapFromConfiguration(Configuration cfg) - throws ConfigurationException { - Map filterMap = new java.util.HashMap(); - Configuration[] filterLists = cfg.getChildren("filterList"); - for (int i = 0; i < filterLists.length; i++) { - Configuration filters = filterLists[i]; - String type = filters.getAttribute("type", null); - Configuration[] filt = filters.getChildren("value"); - List filterList = new java.util.ArrayList(); - for (int j = 0; j < filt.length; j++) { - String name = filt[j].getValue(); - filterList.add(name); - } - - if (type == null) { - type = PDFFilterList.DEFAULT_FILTER; - } - - if (!filterList.isEmpty() && log.isDebugEnabled()) { - StringBuffer debug = new StringBuffer("Adding PDF filter"); - if (filterList.size() != 1) { - debug.append("s"); - } - debug.append(" for type ").append(type).append(": "); - for (int j = 0; j < filterList.size(); j++) { - if (j != 0) { - debug.append(", "); - } - debug.append(filterList.get(j)); - } - log.debug(debug.toString()); - } - - if (filterMap.get(type) != null) { - throw new ConfigurationException("A filterList of type '" - + type + "' has already been defined"); - } - filterMap.put(type, filterList); - } - return filterMap; - } - - // ---=== 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); - } + ((PDFDocumentHandler) documentHandler).mergeRendererOptionsConfig( + ((PDFRendererConfig) getRendererConfig(documentHandler)).getConfigOptions()); } } diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererOption.java b/src/java/org/apache/fop/render/pdf/PDFRendererOption.java new file mode 100644 index 000000000..2ebd691fe --- /dev/null +++ b/src/java/org/apache/fop/render/pdf/PDFRendererOption.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 java.net.URI; +import java.net.URISyntaxException; + +import org.apache.fop.apps.io.InternalResourceResolver; +import org.apache.fop.pdf.PDFAMode; +import org.apache.fop.pdf.PDFXMode; +import org.apache.fop.pdf.Version; +import org.apache.fop.render.RendererConfigOption; + +public enum PDFRendererOption implements RendererConfigOption { + FILTER_LIST("filterList", null) { + @Override + Object deserialize(String value) { + throw new UnsupportedOperationException(); + } + }, + /** Rendering Options key for the PDF/A mode, default: {@link PDFAMode#DISABLED} */ + PDF_A_MODE("pdf-a-mode", PDFAMode.DISABLED) { + @Override + PDFAMode deserialize(String value) { + return PDFAMode.getValueOf(value); + } + }, + /** Rendering Options key for the PDF/X mode, default: {@link PDFXMode#DISABLED} */ + PDF_X_MODE("pdf-x-mode", PDFXMode.DISABLED) { + @Override + PDFXMode deserialize(String value) { + return PDFXMode.getValueOf(value); + } + }, + /** PDF version entry: specify the version of the PDF document created, datatype: String */ + VERSION("version") { + @Override + Version deserialize(String value) { + return Version.getValueOf(value); + } + }, + /** + * 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) { + @Override + Boolean deserialize(String value) { + return Boolean.valueOf(value); + } + }, + /** Rendering Options key for the ICC profile for the output intent. */ + OUTPUT_PROFILE("output-profile") { + @Override + URI deserialize(String value) { + try { + return InternalResourceResolver.cleanURI(value); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + }; + + private final String name; + + private final Object defaultValue; + + private PDFRendererOption(String name, Object defaultValue) { + this.name = name; + this.defaultValue = defaultValue; + } + + private PDFRendererOption(String name) { + this(name, null); + } + + public String getName() { + return name; + } + + public Object getDefaultValue() { + return defaultValue; + } + + public Object parse(Object object) { + if (object instanceof String) { + return deserialize((String) object); + } else { + return object; + } + } + + abstract Object deserialize(String value); + +} diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererOptionsConfig.java b/src/java/org/apache/fop/render/pdf/PDFRendererOptionsConfig.java new file mode 100644 index 000000000..71102ecf0 --- /dev/null +++ b/src/java/org/apache/fop/render/pdf/PDFRendererOptionsConfig.java @@ -0,0 +1,123 @@ +/* + * 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.net.URI; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + +import org.apache.fop.pdf.PDFAMode; +import org.apache.fop.pdf.PDFEncryptionParams; +import org.apache.fop.pdf.PDFXMode; +import org.apache.fop.pdf.Version; + +import static org.apache.fop.render.pdf.PDFRendererOption.DISABLE_SRGB_COLORSPACE; +import static org.apache.fop.render.pdf.PDFRendererOption.FILTER_LIST; +import static org.apache.fop.render.pdf.PDFRendererOption.OUTPUT_PROFILE; +import static org.apache.fop.render.pdf.PDFRendererOption.PDF_A_MODE; +import static org.apache.fop.render.pdf.PDFRendererOption.PDF_X_MODE; +import static org.apache.fop.render.pdf.PDFRendererOption.VERSION; + +/** + * The renderer options configuration data. + */ +public final class PDFRendererOptionsConfig { + + static final PDFRendererOptionsConfig DEFAULT; + + static { + final EnumMap<PDFRendererOption, Object> props + = new EnumMap<PDFRendererOption, Object>(PDFRendererOption.class); + for (PDFRendererOption option : PDFRendererOption.values()) { + props.put(option, option.getDefaultValue()); + } + DEFAULT = new PDFRendererOptionsConfig(props, null); + } + + private final Map<PDFRendererOption, Object> properties + = new EnumMap<PDFRendererOption, Object>(PDFRendererOption.class); + + private final PDFEncryptionParams encryptionConfig; + + PDFRendererOptionsConfig(Map<PDFRendererOption, Object> props, + PDFEncryptionParams encryptionParams) { + properties.putAll(props); + this.encryptionConfig = copyPDFEncryptionParams(encryptionParams); + } + + private static PDFEncryptionParams copyPDFEncryptionParams(PDFEncryptionParams source) { + return source == null ? null : new PDFEncryptionParams(source); + } + + PDFRendererOptionsConfig merge(PDFRendererOptionsConfig config) { + if (config == null) { + return this; + } else { + return new PDFRendererOptionsConfig(merge(this.properties, config.properties), + config.getEncryptionParameters() == null + ? copyPDFEncryptionParams(this.encryptionConfig) + : copyPDFEncryptionParams(config.getEncryptionParameters())); + } + } + + private static Map<PDFRendererOption, Object> merge( + Map<PDFRendererOption, Object> first, Map<PDFRendererOption, Object> second) { + final EnumMap<PDFRendererOption, Object> merged + = new EnumMap<PDFRendererOption, Object>(PDFRendererOption.class); + for (PDFRendererOption option : PDFRendererOption.values()) { + Object value = second.get(option); + if (value != null) { + merged.put(option, value); + } else { + merged.put(option, first.get(option)); + } + } + return merged; + } + + public Map<String, List<String>> getFilterMap() { + return (Map<String, List<String>>) properties.get(FILTER_LIST); + } + + public PDFAMode getPDFAMode() { + return (PDFAMode) properties.get(PDF_A_MODE); + } + + public PDFXMode getPDFXMode() { + return (PDFXMode) properties.get(PDF_X_MODE); + } + + public PDFEncryptionParams getEncryptionParameters() { + return encryptionConfig; + } + + public URI getOutputProfileURI() { + return (URI) properties.get(OUTPUT_PROFILE); + } + + public Boolean getDisableSRGBColorSpace() { + return (Boolean) properties.get(DISABLE_SRGB_COLORSPACE); + } + + public Version getPDFVersion() { + return (Version) properties.get(VERSION); + } +} diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java index 53d259677..fba9d922f 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java @@ -24,17 +24,15 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.URL; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.EnumMap; 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.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.xmlgraphics.image.loader.util.ImageUtil; import org.apache.xmlgraphics.java2d.color.profile.ColorProfileUtil; import org.apache.xmlgraphics.xmp.Metadata; import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter; @@ -42,6 +40,7 @@ import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema; import org.apache.fop.accessibility.Accessibility; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.io.InternalResourceResolver; import org.apache.fop.fo.extensions.xmp.XMPMetadata; import org.apache.fop.pdf.PDFAMode; import org.apache.fop.pdf.PDFArray; @@ -68,11 +67,24 @@ 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.PDFEncryptionOption.ENCRYPTION_PARAMS; +import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_ACCESSCONTENT; +import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_ANNOTATIONS; +import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_ASSEMBLEDOC; +import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_COPY_CONTENT; +import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_EDIT_CONTENT; +import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_FILLINFORMS; +import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_PRINT; +import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_PRINTHQ; +import static org.apache.fop.render.pdf.PDFEncryptionOption.OWNER_PASSWORD; +import static org.apache.fop.render.pdf.PDFEncryptionOption.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,171 +92,42 @@ class PDFRenderingUtil implements PDFConfigurationConstants { private FOUserAgent userAgent; /** the PDF Document being created */ - protected PDFDocument pdfDoc; - - /** the PDF/A mode (Default: disabled) */ - protected PDFAMode pdfAMode = PDFAMode.DISABLED; - - /** the PDF/X mode (Default: disabled) */ - protected PDFXMode pdfXMode = PDFXMode.DISABLED; - - /** the (optional) encryption parameters */ - protected PDFEncryptionParams encryptionParams; + private PDFDocument pdfDoc; - /** Registry of PDF filters */ - protected Map filterMap; + private PDFRendererOptionsConfig rendererConfig; /** the ICC stream used as output profile by this document for PDF/A and PDF/X functionality. */ - protected PDFICCStream outputProfile; - /** the default sRGB color space. */ - protected PDFICCBasedColorSpace sRGBColorSpace; - /** controls whether the sRGB color space should be installed */ - protected boolean disableSRGBColorSpace = false; - - /** Optional URI to an output profile to be used. */ - protected String outputProfileURI; - - protected Version maxPDFVersion; + private PDFICCStream outputProfile; + /** the default sRGB color space. */ + private PDFICCBasedColorSpace sRGBColorSpace; PDFRenderingUtil(FOUserAgent userAgent) { this.userAgent = userAgent; initialize(); } - private static boolean booleanValueOf(Object obj) { - if (obj instanceof Boolean) { - return ((Boolean)obj).booleanValue(); - } else if (obj instanceof String) { - return Boolean.valueOf((String)obj).booleanValue(); - } else { - throw new IllegalArgumentException("Boolean or \"true\" or \"false\" expected."); - } - } - private void initialize() { - PDFEncryptionParams params - = (PDFEncryptionParams)userAgent.getRendererOptions().get(ENCRYPTION_PARAMS); - if (params != null) { - this.encryptionParams = params; //overwrite if available - } - String userPassword = (String)userAgent.getRendererOptions().get(USER_PASSWORD); - if (userPassword != null) { - getEncryptionParams().setUserPassword(userPassword); - } - String ownerPassword = (String)userAgent.getRendererOptions().get(OWNER_PASSWORD); - if (ownerPassword != null) { - getEncryptionParams().setOwnerPassword(ownerPassword); - } - Object noPrint = userAgent.getRendererOptions().get(NO_PRINT); - if (noPrint != null) { - getEncryptionParams().setAllowPrint(!booleanValueOf(noPrint)); - } - Object noCopyContent = userAgent.getRendererOptions().get(NO_COPY_CONTENT); - if (noCopyContent != null) { - getEncryptionParams().setAllowCopyContent(!booleanValueOf(noCopyContent)); - } - Object noEditContent = userAgent.getRendererOptions().get(NO_EDIT_CONTENT); - if (noEditContent != null) { - getEncryptionParams().setAllowEditContent(!booleanValueOf(noEditContent)); - } - Object noAnnotations = userAgent.getRendererOptions().get(NO_ANNOTATIONS); - if (noAnnotations != null) { - getEncryptionParams().setAllowEditAnnotations(!booleanValueOf(noAnnotations)); - } - Object noFillInForms = userAgent.getRendererOptions().get(NO_FILLINFORMS); - if (noFillInForms != null) { - getEncryptionParams().setAllowFillInForms(!booleanValueOf(noFillInForms)); - } - Object noAccessContent = userAgent.getRendererOptions().get(NO_ACCESSCONTENT); - if (noAccessContent != null) { - getEncryptionParams().setAllowAccessContent(!booleanValueOf(noAccessContent)); - } - Object noAssembleDoc = userAgent.getRendererOptions().get(NO_ASSEMBLEDOC); - if (noAssembleDoc != null) { - getEncryptionParams().setAllowAssembleDocument(!booleanValueOf(noAssembleDoc)); - } - Object noPrintHQ = userAgent.getRendererOptions().get(NO_PRINTHQ); - if (noPrintHQ != null) { - getEncryptionParams().setAllowPrintHq(!booleanValueOf(noPrintHQ)); - } - String s = (String)userAgent.getRendererOptions().get(PDF_A_MODE); - if (s != null) { - this.pdfAMode = PDFAMode.valueOf(s); - } - if (this.pdfAMode.isPDFA1LevelA()) { + rendererConfig = PDFRendererOptionsConfig.DEFAULT.merge(createFromUserAgent(userAgent)); + if (rendererConfig.getPDFAMode().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); - if (s != null) { - this.pdfXMode = PDFXMode.valueOf(s); - } - s = (String)userAgent.getRendererOptions().get(KEY_OUTPUT_PROFILE); - if (s != null) { - this.outputProfileURI = s; - } - Object disableSRGBColorSpace = userAgent.getRendererOptions().get( - KEY_DISABLE_SRGB_COLORSPACE); - if (disableSRGBColorSpace != null) { - this.disableSRGBColorSpace = booleanValueOf(disableSRGBColorSpace); - } - } - - public FOUserAgent getUserAgent() { - return this.userAgent; - } - - /** - * Sets the PDF/A mode for the PDF renderer. - * @param mode the PDF/A mode - */ - public void setAMode(PDFAMode mode) { - this.pdfAMode = mode; - } - - /** - * Sets the PDF/X mode for the PDF renderer. - * @param mode the PDF/X mode - */ - public void setXMode(PDFXMode mode) { - this.pdfXMode = mode; - } - - /** - * Sets the output color profile for the PDF renderer. - * @param outputProfileURI the URI to the output color profile - */ - public void setOutputProfileURI(String outputProfileURI) { - this.outputProfileURI = outputProfileURI; } - /** - * Enables or disables the default sRGB color space needed for the PDF document to preserve - * the sRGB colors used in XSL-FO. - * @param disable true to disable, false to enable - */ - public void setDisableSRGBColorSpace(boolean disable) { - this.disableSRGBColorSpace = disable; + private static PDFRendererOptionsConfig createFromUserAgent(FOUserAgent userAgent) { + Map<PDFRendererOption, Object> properties + = new EnumMap<PDFRendererOption, Object>(PDFRendererOption.class); + for (PDFRendererOption option : PDFRendererOption.values()) { + Object value = userAgent.getRendererOption(option); + properties.put(option, option.parse(value)); + } + PDFEncryptionParams encryptionConfig = new EncryptionParamsBuilder().createParams(userAgent); + return new PDFRendererOptionsConfig(properties, encryptionConfig); } - /** - * Sets the filter map to be used by the PDF renderer. - * @param filterMap the filter map - */ - public void setFilterMap(Map filterMap) { - this.filterMap = filterMap; - } - - /** - * Gets the encryption parameters used by the PDF renderer. - * @return encryptionParams the encryption parameters - */ - PDFEncryptionParams getEncryptionParams() { - if (this.encryptionParams == null) { - this.encryptionParams = new PDFEncryptionParams(); - } - return this.encryptionParams; + void mergeRendererOptionsConfig(PDFRendererOptionsConfig config) { + rendererConfig = rendererConfig.merge(config); } private void updateInfo() { @@ -258,15 +141,15 @@ class PDFRenderingUtil implements PDFConfigurationConstants { } private void updatePDFProfiles() { - pdfDoc.getProfile().setPDFAMode(this.pdfAMode); - pdfDoc.getProfile().setPDFXMode(this.pdfXMode); + pdfDoc.getProfile().setPDFAMode(rendererConfig.getPDFAMode()); + pdfDoc.getProfile().setPDFXMode(rendererConfig.getPDFXMode()); } private void addsRGBColorSpace() throws IOException { - if (disableSRGBColorSpace) { - if (this.pdfAMode != PDFAMode.DISABLED - || this.pdfXMode != PDFXMode.DISABLED - || this.outputProfileURI != null) { + if (rendererConfig.getDisableSRGBColorSpace()) { + if (rendererConfig.getPDFAMode() != PDFAMode.DISABLED + || rendererConfig.getPDFXMode() != PDFXMode.DISABLED + || rendererConfig.getOutputProfileURI() != null) { throw new IllegalStateException("It is not possible to disable the sRGB color" + " space if PDF/A or PDF/X functionality is enabled or an" + " output profile is set!"); @@ -286,17 +169,10 @@ class PDFRenderingUtil implements PDFConfigurationConstants { } ICC_Profile profile; InputStream in = null; - if (this.outputProfileURI != null) { + URI outputProfileUri = rendererConfig.getOutputProfileURI(); + if (outputProfileUri != null) { this.outputProfile = pdfDoc.getFactory().makePDFICCStream(); - Source src = getUserAgent().resolveURI(this.outputProfileURI); - if (src == null) { - throw new IOException("Output profile not found: " + this.outputProfileURI); - } - if (src instanceof StreamSource) { - in = ((StreamSource)src).getInputStream(); - } else { - in = new URL(src.getSystemId()).openStream(); - } + in = userAgent.getResourceResolver().getResource(rendererConfig.getOutputProfileURI()); try { profile = ColorProfileUtil.getICC_Profile(in); } finally { @@ -381,7 +257,7 @@ class PDFRenderingUtil implements PDFConfigurationConstants { } String producer = userAgent.getProducer() != null ? userAgent.getProducer() : ""; - + final Version maxPDFVersion = rendererConfig.getPDFVersion(); if (maxPDFVersion == null) { this.pdfDoc = new PDFDocument(producer); } else { @@ -391,22 +267,24 @@ class PDFRenderingUtil implements PDFConfigurationConstants { } updateInfo(); updatePDFProfiles(); - pdfDoc.setFilterMap(filterMap); + pdfDoc.setFilterMap(rendererConfig.getFilterMap()); pdfDoc.outputHeader(out); //Setup encryption if necessary - PDFEncryptionManager.setupPDFEncryption(encryptionParams, pdfDoc); + PDFEncryptionManager.setupPDFEncryption(rendererConfig.getEncryptionParameters(), pdfDoc); addsRGBColorSpace(); - if (this.outputProfileURI != null) { + if (rendererConfig.getOutputProfileURI() != null) { addDefaultOutputProfile(); } + PDFXMode pdfXMode = rendererConfig.getPDFXMode(); if (pdfXMode != PDFXMode.DISABLED) { log.debug(pdfXMode + " is active."); log.warn("Note: " + pdfXMode + " support is work-in-progress and not fully implemented, yet!"); addPDFXOutputIntent(); } + PDFAMode pdfAMode = rendererConfig.getPDFAMode(); if (pdfAMode.isPDFA1LevelB()) { log.debug("PDF/A is active. Conformance Level: " + pdfAMode); addPDFA1OutputIntent(); @@ -456,8 +334,13 @@ class PDFRenderingUtil implements PDFConfigurationConstants { //Create embedded file PDFEmbeddedFile file = new PDFEmbeddedFile(); this.pdfDoc.registerObject(file); - Source src = getUserAgent().resolveURI(embeddedFile.getSrc()); - InputStream in = ImageUtil.getInputStream(src); + URI srcURI; + try { + srcURI = InternalResourceResolver.cleanURI(embeddedFile.getSrc()); + } catch (URISyntaxException use) { + throw new RuntimeException(use); + } + InputStream in = userAgent.getResourceResolver().getResource(srcURI); if (in == null) { throw new FileNotFoundException(embeddedFile.getSrc()); } @@ -497,14 +380,72 @@ class PDFRenderingUtil implements PDFConfigurationConstants { nameArray.add(new PDFReference(fileSpec)); } - /** - * Sets the PDF version of the output document. See {@link Version} for the format of - * <code>version</code>. - * @param version the PDF version - * @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); + private static final class EncryptionParamsBuilder { + private PDFEncryptionParams params; + + private EncryptionParamsBuilder() { + } + + private PDFEncryptionParams createParams(FOUserAgent userAgent) { + params = (PDFEncryptionParams) userAgent.getRendererOptions().get(ENCRYPTION_PARAMS); + String userPassword = (String) userAgent.getRendererOption(USER_PASSWORD); + if (userPassword != null) { + getEncryptionParams().setUserPassword(userPassword); + } + String ownerPassword = (String) userAgent.getRendererOption(OWNER_PASSWORD); + if (ownerPassword != null) { + getEncryptionParams().setOwnerPassword(ownerPassword); + } + Object noPrint = userAgent.getRendererOption(NO_PRINT); + if (noPrint != null) { + getEncryptionParams().setAllowPrint(!booleanValueOf(noPrint)); + } + Object noCopyContent = userAgent.getRendererOption(NO_COPY_CONTENT); + if (noCopyContent != null) { + getEncryptionParams().setAllowCopyContent(!booleanValueOf(noCopyContent)); + } + Object noEditContent = userAgent.getRendererOption(NO_EDIT_CONTENT); + if (noEditContent != null) { + getEncryptionParams().setAllowEditContent(!booleanValueOf(noEditContent)); + } + Object noAnnotations = userAgent.getRendererOption(NO_ANNOTATIONS); + if (noAnnotations != null) { + getEncryptionParams().setAllowEditAnnotations(!booleanValueOf(noAnnotations)); + } + Object noFillInForms = userAgent.getRendererOption(NO_FILLINFORMS); + if (noFillInForms != null) { + getEncryptionParams().setAllowFillInForms(!booleanValueOf(noFillInForms)); + } + Object noAccessContent = userAgent.getRendererOption(NO_ACCESSCONTENT); + if (noAccessContent != null) { + getEncryptionParams().setAllowAccessContent(!booleanValueOf(noAccessContent)); + } + Object noAssembleDoc = userAgent.getRendererOption(NO_ASSEMBLEDOC); + if (noAssembleDoc != null) { + getEncryptionParams().setAllowAssembleDocument(!booleanValueOf(noAssembleDoc)); + } + Object noPrintHQ = userAgent.getRendererOption(NO_PRINTHQ); + if (noPrintHQ != null) { + getEncryptionParams().setAllowPrintHq(!booleanValueOf(noPrintHQ)); + } + return params; + } + + private PDFEncryptionParams getEncryptionParams() { + if (params == null) { + params = new PDFEncryptionParams(); + } + return params; + } + + private static boolean booleanValueOf(Object obj) { + if (obj instanceof Boolean) { + return ((Boolean)obj).booleanValue(); + } else if (obj instanceof String) { + return Boolean.valueOf((String)obj).booleanValue(); + } else { + throw new IllegalArgumentException("Boolean or \"true\" or \"false\" expected."); + } + } } } diff --git a/src/java/org/apache/fop/render/print/PrintRendererMaker.java b/src/java/org/apache/fop/render/print/PrintRendererMaker.java index 63444a628..e5673c1f4 100644 --- a/src/java/org/apache/fop/render/print/PrintRendererMaker.java +++ b/src/java/org/apache/fop/render/print/PrintRendererMaker.java @@ -19,12 +19,12 @@ package org.apache.fop.render.print; +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.PrintRendererConfigurator; import org.apache.fop.render.Renderer; -import org.apache.fop.render.RendererConfigurator; /** * RendererMaker for the Print Renderer. @@ -33,24 +33,23 @@ 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 { + PrintRendererConfigurator.createDefaultInstance(userAgent).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 0fe564827..0ec5fdda6 100644 --- a/src/java/org/apache/fop/render/ps/PSDocumentHandler.java +++ b/src/java/org/apache/fop/render/ps/PSDocumentHandler.java @@ -22,10 +22,12 @@ package org.apache.fop.render.ps; import java.awt.Dimension; import java.awt.geom.Dimension2D; import java.awt.geom.Rectangle2D; -import java.io.File; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -50,13 +52,14 @@ import org.apache.xmlgraphics.ps.dsc.ResourceTracker; import org.apache.xmlgraphics.ps.dsc.events.DSCCommentBoundingBox; import org.apache.xmlgraphics.ps.dsc.events.DSCCommentHiResBoundingBox; -import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; +import org.apache.fop.apps.io.TempResourceURIGenerator; import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler; 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; @@ -76,13 +79,15 @@ public class PSDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { * Utility class which enables all sorts of features that are not directly connected to the * normal rendering process. */ - protected PSRenderingUtil psUtil; + private PSRenderingUtil psUtil; /** The PostScript generator used to output the PostScript */ - protected PSGenerator gen; + PSGenerator gen; /** the temporary file in case of two-pass processing */ - private File tempFile; + private URI tempURI; + private static final TempResourceURIGenerator TEMP_URI_GENERATOR + = new TempResourceURIGenerator("ps-optimize"); private int currentPageNumber = 0; private PageDefinition currentPageDefinition; @@ -113,7 +118,9 @@ public class PSDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { /** * Default constructor. */ - public PSDocumentHandler() { + public PSDocumentHandler(IFContext context) { + super(context); + this.psUtil = new PSRenderingUtil(context.getUserAgent()); } /** {@inheritDoc} */ @@ -126,17 +133,13 @@ public class PSDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { return MimeConstants.MIME_POSTSCRIPT; } - /** {@inheritDoc} */ - public void setContext(IFContext context) { - super.setContext(context); - FOUserAgent userAgent = context.getUserAgent(); - this.psUtil = new PSRenderingUtil(userAgent); - eventProducer = PSEventProducer.Provider.get(userAgent.getEventBroadcaster()); + PSGenerator getGenerator() { + return gen; } /** {@inheritDoc} */ public IFDocumentHandlerConfigurator getConfigurator() { - return new PSRendererConfigurator(getUserAgent()); + return new PSRendererConfigurator(getUserAgent(), new PSRendererConfigParser()); } PSRenderingUtil getPSUtil() { @@ -148,11 +151,10 @@ public class PSDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { super.startDocument(); this.fontResources = new FontResourceCache(getFontInfo()); try { - OutputStream out; + final OutputStream out; if (psUtil.isOptimizeResources()) { - this.tempFile = File.createTempFile("fop", ".ps"); - out = new java.io.FileOutputStream(this.tempFile); - out = new java.io.BufferedOutputStream(out); + tempURI = TEMP_URI_GENERATOR.generate(); + out = new BufferedOutputStream(getUserAgent().getResourceResolver().getOutputStream(tempURI)); } else { out = this.outputStream; } @@ -259,8 +261,7 @@ public class PSDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { log.debug("Processing PostScript resources..."); long startTime = System.currentTimeMillis(); ResourceTracker resTracker = gen.getResourceTracker(); - InputStream in = new java.io.FileInputStream(this.tempFile); - in = new java.io.BufferedInputStream(in); + InputStream in = new BufferedInputStream(getUserAgent().getResourceResolver().getResource(tempURI)); try { try { ResourceHandler handler = new ResourceHandler(getUserAgent(), eventProducer, @@ -273,10 +274,6 @@ public class PSDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { } } finally { IOUtils.closeQuietly(in); - if (!this.tempFile.delete()) { - this.tempFile.deleteOnExit(); - log.warn("Could not delete temporary file: " + this.tempFile); - } } if (log.isDebugEnabled()) { long duration = System.currentTimeMillis() - startTime; 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 d0d75744f..c99bb21e1 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -19,19 +19,14 @@ 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.HashMap; import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Set; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -526,27 +521,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/PSPainter.java b/src/java/org/apache/fop/render/ps/PSPainter.java index 9d16cb428..b8947ff60 100644 --- a/src/java/org/apache/fop/render/ps/PSPainter.java +++ b/src/java/org/apache/fop/render/ps/PSPainter.java @@ -41,7 +41,6 @@ import org.apache.xmlgraphics.ps.PSGenerator; import org.apache.xmlgraphics.ps.PSResource; import org.apache.fop.fonts.Font; -import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontTriplet; import org.apache.fop.fonts.LazyFont; import org.apache.fop.fonts.MultiByteFont; @@ -49,7 +48,6 @@ import org.apache.fop.fonts.SingleByteFont; import org.apache.fop.fonts.Typeface; import org.apache.fop.render.RenderingContext; import org.apache.fop.render.intermediate.AbstractIFPainter; -import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFState; import org.apache.fop.render.intermediate.IFUtil; @@ -61,12 +59,11 @@ import org.apache.fop.util.HexEncoder; /** * IFPainter implementation that produces PostScript. */ -public class PSPainter extends AbstractIFPainter { +public class PSPainter extends AbstractIFPainter<PSDocumentHandler> { /** logging instance */ private static Log log = LogFactory.getLog(PSPainter.class); - private PSDocumentHandler documentHandler; private PSBorderPainter borderPainter; private boolean inTextMode = false; @@ -80,27 +77,13 @@ public class PSPainter extends AbstractIFPainter { } protected PSPainter(PSDocumentHandler documentHandler, IFState state) { - super(); - this.documentHandler = documentHandler; - this.borderPainter = new PSBorderPainter(documentHandler.gen); + super(documentHandler); + this.borderPainter = new PSBorderPainter(getGenerator()); this.state = state; } - /** {@inheritDoc} */ - protected IFContext getContext() { - return this.documentHandler.getContext(); - } - - PSRenderingUtil getPSUtil() { - return this.documentHandler.psUtil; - } - - FontInfo getFontInfo() { - return this.documentHandler.getFontInfo(); - } - private PSGenerator getGenerator() { - return this.documentHandler.gen; + return getDocumentHandler().getGenerator(); } /** {@inheritDoc} */ @@ -168,7 +151,7 @@ public class PSPainter extends AbstractIFPainter { /** {@inheritDoc} */ protected void drawImageUsingImageHandler(ImageInfo info, Rectangle rect) throws ImageException, IOException { - if (!getPSUtil().isOptimizeResources() + if (!getDocumentHandler().getPSUtil().isOptimizeResources() || PSImageUtils.isImageInlined(info, (PSRenderingContext)createRenderingContext())) { super.drawImageUsingImageHandler(info, rect); @@ -177,7 +160,7 @@ public class PSPainter extends AbstractIFPainter { log.debug("Image " + info + " is embedded as a form later"); } //Don't load image at this time, just put a form placeholder in the stream - PSResource form = documentHandler.getFormForImage(info.getOriginalURI()); + PSResource form = getDocumentHandler().getFormForImage(info.getOriginalURI()); PSImageUtils.drawForm(form, info, rect, getGenerator()); } } @@ -260,7 +243,7 @@ public class PSPainter extends AbstractIFPainter { if (top != null || bottom != null || left != null || right != null) { try { endTextObject(); - if (getPSUtil().getRenderingMode() == PSRenderingMode.SIZE + if (getDocumentHandler().getPSUtil().getRenderingMode() == PSRenderingMode.SIZE && hasOnlySolidBorders(top, bottom, left, right)) { super.drawBorderRect(rect, top, bottom, left, right, innerBackgroundColor); } else { @@ -287,7 +270,7 @@ public class PSPainter extends AbstractIFPainter { if (fontName == null) { throw new NullPointerException("fontName must not be null"); } - Typeface tf = (Typeface)getFontInfo().getFonts().get(fontName); + Typeface tf = getFontInfo().getFonts().get(fontName); if (tf instanceof LazyFont) { tf = ((LazyFont)tf).getRealFont(); } @@ -377,10 +360,7 @@ public class PSPainter extends AbstractIFPainter { state.getFontFamily(), state.getFontStyle(), state.getFontWeight()); //TODO Ignored: state.getFontVariant() //TODO Opportunity for font caching if font state is more heavily used - String fontKey = getFontInfo().getInternalFontKey(triplet); - if (fontKey == null) { - throw new IFException("Font not available: " + triplet, null); - } + String fontKey = getFontKey(triplet); int sizeMillipoints = state.getFontSize(); // This assumes that *all* CIDFonts use a /ToUnicode mapping @@ -543,10 +523,9 @@ public class PSPainter extends AbstractIFPainter { } private void useFont(String key, int size) throws IOException { - PSFontResource res = this.documentHandler.getPSResourceForFontKey(key); + PSFontResource res = getDocumentHandler().getPSResourceForFontKey(key); PSGenerator generator = getGenerator(); generator.useFont("/" + res.getName(), size / 1000f); res.notifyResourceUsageOnPage(generator.getResourceTracker()); } - } 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..e26be11d0 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSRendererConfig.java @@ -0,0 +1,147 @@ +/* + * 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.PSRendererOption.AUTO_ROTATE_LANDSCAPE; +import static org.apache.fop.render.ps.PSRendererOption.DSC_COMPLIANT; +import static org.apache.fop.render.ps.PSRendererOption.LANGUAGE_LEVEL; +import static org.apache.fop.render.ps.PSRendererOption.OPTIMIZE_RESOURCES; +import static org.apache.fop.render.ps.PSRendererOption.RENDERING_MODE; +import static org.apache.fop.render.ps.PSRendererOption.SAFE_SET_PAGE_DEVICE; + +/** + * The PostScript renderer configuration data object. + */ +public final class PSRendererConfig implements RendererConfig { + + private final EnumMap<PSRendererOption, Object> params + = new EnumMap<PSRendererOption, Object>(PSRendererOption.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); + } + + /** + * The PostScript renderer configuration data parser. + */ + 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(PSRendererOption option, + Object value) { + config.params.put(option, value != null ? value : option.getDefaultValue()); + } + + private void setBoolConfigParam(Configuration cfg, PSRendererOption option) { + setConfigParameter(option, cfg.getChild( + option.getName()).getValueAsBoolean((Boolean) option.getDefaultValue())); + } + + } + +} diff --git a/src/java/org/apache/fop/render/ps/PSRendererConfigurator.java b/src/java/org/apache/fop/render/ps/PSRendererConfigurator.java index 00f3fc154..b453de413 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.DefaultRendererConfigurator; +import org.apache.fop.render.RendererConfig.RendererConfigParser; 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 DefaultRendererConfigurator + 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/PSRendererOption.java b/src/java/org/apache/fop/render/ps/PSRendererOption.java new file mode 100644 index 000000000..4c3396921 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSRendererOption.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.RendererConfigOption; + +/** + * An enumeration of the PostScript renderer configuration options along with their default values. + */ +public enum PSRendererOption implements RendererConfigOption { + /** 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 PSRendererOption(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/PSRenderingUtil.java b/src/java/org/apache/fop/render/ps/PSRenderingUtil.java index b22391718..4033c304f 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.PSRendererOption.AUTO_ROTATE_LANDSCAPE; +import static org.apache.fop.render.ps.PSRendererOption.LANGUAGE_LEVEL; +import static org.apache.fop.render.ps.PSRendererOption.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/PSTextPainter.java b/src/java/org/apache/fop/render/ps/PSTextPainter.java index 2b3afaec7..1f89dc8f0 100644 --- a/src/java/org/apache/fop/render/ps/PSTextPainter.java +++ b/src/java/org/apache/fop/render/ps/PSTextPainter.java @@ -52,7 +52,7 @@ import org.apache.fop.util.CharUtilities; import org.apache.fop.util.HexEncoder; /** - * Renders the attributed character iterator of a text node. + * Renders the attributed character iterator of a {@link org.apache.batik.gvt.TextNode TextNode}. * This class draws the text directly using PostScript text operators so * the text is not drawn using shapes which makes the PS files larger. * <p> diff --git a/src/java/org/apache/fop/render/ps/ResourceHandler.java b/src/java/org/apache/fop/render/ps/ResourceHandler.java index 5594897ba..95b544ec2 100644 --- a/src/java/org/apache/fop/render/ps/ResourceHandler.java +++ b/src/java/org/apache/fop/render/ps/ResourceHandler.java @@ -287,7 +287,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(); @@ -299,7 +299,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..6c2d7c03d 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.getResourceResolver(), 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..a600047ae 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.DefaultRendererConfigurator; import org.apache.fop.render.Renderer; +import org.apache.fop.render.RendererConfig.RendererConfigParser; /** * TXT Renderer configurator */ -public class TXTRendererConfigurator extends PrintRendererConfigurator { +public class TXTRendererConfigurator extends DefaultRendererConfigurator { /** * 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..f597ee518 --- /dev/null +++ b/src/java/org/apache/fop/render/txt/TxtRendererConfig.java @@ -0,0 +1,99 @@ +/* + * 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.RendererConfigOption; + +/** + * The Text renderer configuration data object. + */ +public final class TxtRendererConfig implements RendererConfig { + + public enum TxtRendererOption implements RendererConfigOption { + ENCODING("encoding", "UTF-8"); + + private final String name; + private final Object defaultValue; + + private TxtRendererOption(String name, Object defaultValue) { + this.name = name; + this.defaultValue = defaultValue; + } + + public String getName() { + return name; + } + + public Object getDefaultValue() { + return defaultValue; + } + } + + private final EnumMap<TxtRendererOption, Object> params + = new EnumMap<TxtRendererOption, Object>(TxtRendererOption.class); + + private final DefaultFontConfig fontConfig; + + private TxtRendererConfig(DefaultFontConfig fontConfig) { + this.fontConfig = fontConfig; + } + + public DefaultFontConfig getFontInfoConfig() { + return fontConfig; + } + + public String getEncoding() { + return (String) params.get(TxtRendererOption.ENCODING); + } + + /** + * The Text renderer configuration data parser. + */ + public static final class TxtRendererConfigParser implements RendererConfigParser { + + /** {@inheritDoc} */ + public TxtRendererConfig build(FOUserAgent userAgent, Configuration cfg) throws FOPException { + TxtRendererConfig config = new TxtRendererConfig(new DefaultFontConfigParser().parse(cfg, + userAgent.validateStrictly())); + if (cfg != null) { + TxtRendererOption option = TxtRendererOption.ENCODING; + String value = cfg.getChild(option.getName(), true).getValue(null); + config.params.put(option, value != null ? value : option.getDefaultValue()); + } + return config; + } + + /** {@inheritDoc} */ + 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..3110ed0ef 100644 --- a/src/java/org/apache/fop/render/xml/XMLRendererMaker.java +++ b/src/java/org/apache/fop/render/xml/XMLRendererMaker.java @@ -19,12 +19,12 @@ package org.apache.fop.render.xml; +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.PrintRendererConfigurator; import org.apache.fop.render.Renderer; -import org.apache.fop.render.RendererConfigurator; /** * RendererMaker for the Area Tree XML Renderer. @@ -33,22 +33,22 @@ 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 { + PrintRendererConfigurator.createDefaultInstance(userAgent).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..9dcf10a2b 100644 --- a/src/java/org/apache/fop/servlet/FopServlet.java +++ b/src/java/org/apache/fop/servlet/FopServlet.java @@ -21,7 +21,10 @@ package org.apache.fop.servlet; import java.io.File; import java.io.IOException; +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 +45,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 +97,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..d413e3274 100644 --- a/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java +++ b/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java @@ -19,23 +19,28 @@ package org.apache.fop.svg; +import java.io.File; +import java.net.URI; import java.util.List; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.fop.apps.FOPException; -import org.apache.fop.fonts.CustomFontCollection; -import org.apache.fop.fonts.FontCollection; +import org.apache.fop.apps.io.InternalResourceResolver; +import org.apache.fop.apps.io.ResourceResolverFactory; +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 +58,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.getConfigOptions().getFilterMap()); + } catch (FOPException e) { + throw new RuntimeException(e); + } //Fonts try { @@ -78,30 +86,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); - } + URI thisUri = new File(".").getAbsoluteFile().toURI(); + InternalResourceResolver resourceResolver = ResourceResolverFactory.createDefaultInternalResourceResolver(thisUri); + //TODO The following could be optimized by retaining the FontManager somewhere + FontManager fontManager = new FontManager(resourceResolver, 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, resourceResolver, 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..a249fe47b 100644 --- a/src/java/org/apache/fop/util/ColorSpaceCache.java +++ b/src/java/org/apache/fop/util/ColorSpaceCache.java @@ -21,19 +21,18 @@ package org.apache.fop.util; import java.awt.color.ColorSpace; import java.awt.color.ICC_Profile; +import java.io.InputStream; import java.util.Collections; +import java.util.HashMap; import java.util.Map; -import javax.xml.transform.Source; -import javax.xml.transform.URIResolver; -import javax.xml.transform.stream.StreamSource; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; 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.InternalResourceResolver; /** * Map with cached ICC based ColorSpace objects. @@ -42,16 +41,15 @@ public class ColorSpaceCache { /** logger instance */ private static Log log = LogFactory.getLog(ColorSpaceCache.class); - private URIResolver resolver; - private Map<String, ColorSpace> colorSpaceMap - = Collections.synchronizedMap(new java.util.HashMap<String, ColorSpace>()); + private InternalResourceResolver resourceResolver; + private Map<String, ColorSpace> colorSpaceMap = Collections.synchronizedMap(new HashMap<String, ColorSpace>()); /** * Default constructor - * @param resolver uri resolver + * @param resourceResolver uri resolver */ - public ColorSpaceCache(URIResolver resolver) { - this.resolver = resolver; + public ColorSpaceCache(InternalResourceResolver resourceResolver) { + this.resourceResolver = resourceResolver; } /** @@ -69,21 +67,21 @@ public class ColorSpaceCache { * @param renderingIntent overriding rendering intent * @return ICC ColorSpace object or null if ColorSpace could not be created */ - public ColorSpace get(String profileName, String base, String iccProfileSrc, + public ColorSpace get(String profileName, String iccProfileSrc, RenderingIntent renderingIntent) { - String key = profileName + ":" + base + iccProfileSrc; + String key = profileName + ":" + iccProfileSrc; + // TODO: This stuff needs some TLC, fix it!! ColorSpace colorSpace = null; if (!colorSpaceMap.containsKey(key)) { try { ICC_Profile iccProfile = null; // First attempt to use the FOP URI resolver to locate the ICC // profile - Source src = resolver.resolve(iccProfileSrc, base); - if (src != null && src instanceof StreamSource) { + InputStream stream = resourceResolver.getResource(iccProfileSrc); + if (stream != null) { // FOP URI resolver found ICC profile - create ICC profile // from the Source - iccProfile = ColorProfileUtil.getICC_Profile(((StreamSource) src) - .getInputStream()); + iccProfile = ICC_Profile.getInstance(stream); } else { // TODO - Would it make sense to fall back on VM ICC // resolution @@ -100,6 +98,7 @@ public class ColorSpaceCache { } catch (Exception e) { // Ignore exception - will be logged a bit further down // (colorSpace == null case) + log.warn("Exception thrown resolving the color space: " + e.getMessage()); } if (colorSpace != null) { diff --git a/src/java/org/apache/fop/util/ColorUtil.java b/src/java/org/apache/fop/util/ColorUtil.java index 09e9dd50b..b18192657 100644 --- a/src/java/org/apache/fop/util/ColorUtil.java +++ b/src/java/org/apache/fop/util/ColorUtil.java @@ -404,10 +404,8 @@ 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( - iccProfileName, - foUserAgent.getBaseURL(), iccProfileSrc, - renderingIntent); + colorSpace = foUserAgent.getColorSpaceCache().get( + iccProfileName, iccProfileSrc, renderingIntent); } if (colorSpace != null) { // ColorSpace is available @@ -488,10 +486,8 @@ 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( - iccProfileName, - foUserAgent.getBaseURL(), iccProfileSrc, - renderingIntent); + colorSpace = (ICC_ColorSpace)foUserAgent.getColorSpaceCache().get( + iccProfileName, iccProfileSrc, renderingIntent); } if (colorSpace != null) { ICC_Profile profile = colorSpace.getProfile(); |