diff options
author | Jeremias Maerki <jeremias@apache.org> | 2008-09-28 13:17:57 +0000 |
---|---|---|
committer | Jeremias Maerki <jeremias@apache.org> | 2008-09-28 13:17:57 +0000 |
commit | d6d3411ca856d605080c25624da32cd9ad1df9bb (patch) | |
tree | 66974a04550755b6e933d9a2daa3510557c688b6 /src | |
parent | c785bd37ca4848a0a0022eb9a480560c1a0b7af1 (diff) | |
download | xmlgraphics-fop-d6d3411ca856d605080c25624da32cd9ad1df9bb.tar.gz xmlgraphics-fop-d6d3411ca856d605080c25624da32cd9ad1df9bb.zip |
Split IFPainter into IFDocumentHandler and IFPainter. This makes the implementation classes smaller, better allows to isolate the painting parts and helps with formats that generate one object per page (SVG, PNG etc.).
Added ImageHandlerFactory to FopFactory.
Started TIFF output in order to develop the Java2DPainter that will be needed for certain tasks when generating PCL.
Tweaked the way XML is generated for IF and SVG output.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign@699813 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
60 files changed, 4083 insertions, 1852 deletions
diff --git a/src/java/META-INF/services/org.apache.fop.render.ImageHandler b/src/java/META-INF/services/org.apache.fop.render.ImageHandler index 81accc88a..d9f2ccbba 100644 --- a/src/java/META-INF/services/org.apache.fop.render.ImageHandler +++ b/src/java/META-INF/services/org.apache.fop.render.ImageHandler @@ -3,3 +3,5 @@ org.apache.fop.render.pdf.PDFImageHandlerRenderedImage org.apache.fop.render.pdf.PDFImageHandlerRawJPEG
org.apache.fop.render.pdf.PDFImageHandlerRawCCITTFax
org.apache.fop.render.pdf.PDFImageHandlerSVG
+org.apache.fop.render.java2d.Java2DImageHandlerRenderedImage
+org.apache.fop.render.java2d.Java2DImageHandlerGraphics2D
diff --git a/src/java/META-INF/services/org.apache.fop.render.intermediate.IFDocumentHandler b/src/java/META-INF/services/org.apache.fop.render.intermediate.IFDocumentHandler new file mode 100644 index 000000000..4e8309fea --- /dev/null +++ b/src/java/META-INF/services/org.apache.fop.render.intermediate.IFDocumentHandler @@ -0,0 +1,3 @@ +org.apache.fop.render.pdf.PDFDocumentHandlerMaker
+org.apache.fop.render.pcl.PCLDocumentHandlerMaker
+org.apache.fop.render.bitmap.TIFFDocumentHandlerMaker
\ No newline at end of file diff --git a/src/java/META-INF/services/org.apache.fop.render.intermediate.IFPainter b/src/java/META-INF/services/org.apache.fop.render.intermediate.IFPainter deleted file mode 100644 index 8b7fd4508..000000000 --- a/src/java/META-INF/services/org.apache.fop.render.intermediate.IFPainter +++ /dev/null @@ -1,2 +0,0 @@ -org.apache.fop.render.pdf.PDFPainterMaker
-org.apache.fop.render.pcl.PCLPainterMaker
\ No newline at end of file diff --git a/src/java/org/apache/fop/apps/FopFactory.java b/src/java/org/apache/fop/apps/FopFactory.java index 883afdcfa..96c22f964 100644 --- a/src/java/org/apache/fop/apps/FopFactory.java +++ b/src/java/org/apache/fop/apps/FopFactory.java @@ -47,6 +47,7 @@ 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.RendererFactory; import org.apache.fop.render.XMLHandlerRegistry; import org.apache.fop.util.ColorSpaceCache; @@ -69,6 +70,9 @@ public class FopFactory implements ImageContext { /** Registry for XML handlers */ private XMLHandlerRegistry xmlHandlers; + /** Registry for image handlers */ + private ImageHandlerRegistry imageHandlers; + /** The registry for ElementMapping instances */ private ElementMappingRegistry elementMappingRegistry; @@ -156,6 +160,7 @@ public class FopFactory implements ImageContext { this.imageManager = new ImageManager(this); this.rendererFactory = new RendererFactory(); this.xmlHandlers = new XMLHandlerRegistry(); + this.imageHandlers = new ImageHandlerRegistry(); this.ignoredNamespaces = new java.util.HashSet(); } @@ -276,6 +281,11 @@ public class FopFactory implements ImageContext { return this.xmlHandlers; } + /** @return the image handler registry */ + public ImageHandlerRegistry getImageHandlerRegistry() { + return this.imageHandlers; + } + /** @return the element mapping registry */ public ElementMappingRegistry getElementMappingRegistry() { return this.elementMappingRegistry; diff --git a/src/java/org/apache/fop/render/AbstractRenderer.java b/src/java/org/apache/fop/render/AbstractRenderer.java index 18c540fed..2be9150b0 100644 --- a/src/java/org/apache/fop/render/AbstractRenderer.java +++ b/src/java/org/apache/fop/render/AbstractRenderer.java @@ -114,7 +114,7 @@ public abstract class AbstractRenderer private Set warnedXMLHandlers; /** {@inheritDoc} */ - public abstract void setupFontInfo(FontInfo fontInfo); + public abstract void setupFontInfo(FontInfo fontInfo) throws FOPException; /** {@inheritDoc} */ public void setUserAgent(FOUserAgent agent) { diff --git a/src/java/org/apache/fop/render/PrintRenderer.java b/src/java/org/apache/fop/render/PrintRenderer.java index 56504ff53..818e31568 100644 --- a/src/java/org/apache/fop/render/PrintRenderer.java +++ b/src/java/org/apache/fop/render/PrintRenderer.java @@ -26,6 +26,7 @@ import java.util.Map; import org.w3c.dom.Document; +import org.apache.fop.apps.FOPException; import org.apache.fop.area.Area; import org.apache.fop.area.Trait; import org.apache.fop.fonts.CustomFontCollection; @@ -75,12 +76,8 @@ public abstract class PrintRenderer extends AbstractRenderer { return this.embedFontInfoList; } - /** - * Set up the font info - * - * @param inFontInfo font info to set up - */ - public void setupFontInfo(FontInfo inFontInfo) { + /** {@inheritDoc} */ + public void setupFontInfo(FontInfo inFontInfo) throws FOPException { this.fontInfo = inFontInfo; FontManager fontManager = userAgent.getFactory().getFontManager(); FontCollection[] fontCollections = new FontCollection[] { diff --git a/src/java/org/apache/fop/render/Renderer.java b/src/java/org/apache/fop/render/Renderer.java index 0ff37db0e..5fa9ca5b2 100644 --- a/src/java/org/apache/fop/render/Renderer.java +++ b/src/java/org/apache/fop/render/Renderer.java @@ -98,8 +98,9 @@ public interface Renderer { * Set up the given FontInfo. * * @param fontInfo The font information + * @throws FOPException if an error occurs while setting up the font info object */ - void setupFontInfo(FontInfo fontInfo); + void setupFontInfo(FontInfo fontInfo) throws FOPException; /** * Reports if out of order rendering is supported. <p> diff --git a/src/java/org/apache/fop/render/RendererFactory.java b/src/java/org/apache/fop/render/RendererFactory.java index 412f3e2cd..5a82151e5 100644 --- a/src/java/org/apache/fop/render/RendererFactory.java +++ b/src/java/org/apache/fop/render/RendererFactory.java @@ -34,9 +34,8 @@ import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.area.AreaTreeHandler; import org.apache.fop.fo.FOEventHandler; -import org.apache.fop.render.intermediate.AbstractIFPainterMaker; -import org.apache.fop.render.intermediate.IFPainter; -import org.apache.fop.render.intermediate.IFPainterConfigurator; +import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker; +import org.apache.fop.render.intermediate.IFDocumentHandler; import org.apache.fop.render.intermediate.IFRenderer; /** @@ -49,7 +48,7 @@ public class RendererFactory { private Map rendererMakerMapping = new java.util.HashMap(); private Map eventHandlerMakerMapping = new java.util.HashMap(); - private Map painterMakerMapping = new java.util.HashMap(); + private Map documentHandlerMakerMapping = new java.util.HashMap(); /** * Main constructor. @@ -57,7 +56,7 @@ public class RendererFactory { public RendererFactory() { discoverRenderers(); discoverFOEventHandlers(); - discoverPainters(); + discoverDocumentHandlers(); } /** @@ -95,19 +94,19 @@ public class RendererFactory { } /** - * Add a new painter maker. If another maker has already been registered for a + * Add a new document handler maker. If another maker has already been registered for a * particular MIME type, this call overwrites the existing one. - * @param maker the painter maker + * @param maker the intermediate format document handler maker */ - public void addPainterMaker(AbstractIFPainterMaker maker) { + public void addDocumentHandlerMaker(AbstractIFDocumentHandlerMaker maker) { String[] mimes = maker.getSupportedMimeTypes(); for (int i = 0; i < mimes.length; i++) { //This overrides any renderer previously set for a MIME type - if (painterMakerMapping.get(mimes[i]) != null) { - log.trace("Overriding painter for " + mimes[i] + if (documentHandlerMakerMapping.get(mimes[i]) != null) { + log.trace("Overriding document handler for " + mimes[i] + " with " + maker.getClass().getName()); } - painterMakerMapping.put(mimes[i], maker); + documentHandlerMakerMapping.put(mimes[i], maker); } } @@ -164,15 +163,15 @@ public class RendererFactory { } /** - * Add a new painter maker. If another maker has already been registered for a + * Add a new document handler maker. If another maker has already been registered for a * particular MIME type, this call overwrites the existing one. - * @param className the fully qualified class name of the painter maker + * @param className the fully qualified class name of the document handler maker */ - public void addPainterMaker(String className) { + public void addDocumentHandlerMaker(String className) { try { - AbstractIFPainterMaker makerInstance - = (AbstractIFPainterMaker)Class.forName(className).newInstance(); - addPainterMaker(makerInstance); + AbstractIFDocumentHandlerMaker makerInstance + = (AbstractIFDocumentHandlerMaker)Class.forName(className).newInstance(); + addDocumentHandlerMaker(makerInstance); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("Could not find " + className); @@ -185,7 +184,7 @@ public class RendererFactory { } catch (ClassCastException e) { throw new IllegalArgumentException(className + " is not an " - + AbstractIFPainterMaker.class.getName()); + + AbstractIFDocumentHandlerMaker.class.getName()); } } @@ -216,9 +215,9 @@ public class RendererFactory { * @param mime the requested output format * @return the requested RendererMaker or null if none is available */ - public AbstractIFPainterMaker getPainterMaker(String mime) { - AbstractIFPainterMaker maker - = (AbstractIFPainterMaker)painterMakerMapping.get(mime); + public AbstractIFDocumentHandlerMaker getDocumentHandlerMaker(String mime) { + AbstractIFDocumentHandlerMaker maker + = (AbstractIFDocumentHandlerMaker)documentHandlerMakerMapping.get(mime); return maker; } @@ -244,12 +243,14 @@ public class RendererFactory { } return rend; } else { - AbstractIFPainterMaker painterMaker = getPainterMaker(outputFormat); - if (painterMaker != null) { + AbstractIFDocumentHandlerMaker documentHandlerMaker + = getDocumentHandlerMaker(outputFormat); + if (documentHandlerMaker != null) { IFRenderer rend = new IFRenderer(); rend.setUserAgent(userAgent); - IFPainter painter = createPainter(userAgent, outputFormat); - rend.setPainter(painter); + IFDocumentHandler documentHandler = createDocumentHandler( + userAgent, outputFormat); + rend.setDocumentHandler(documentHandler); return rend; } else { throw new UnsupportedOperationException( @@ -278,19 +279,20 @@ public class RendererFactory { return maker.makeFOEventHandler(userAgent, out); } else { AbstractRendererMaker rendMaker = getRendererMaker(outputFormat); - AbstractIFPainterMaker painterMaker = null; + AbstractIFDocumentHandlerMaker documentHandlerMaker = null; boolean outputStreamMissing = (userAgent.getRendererOverride() == null); if (rendMaker == null) { - painterMaker = getPainterMaker(outputFormat); - if (painterMaker != null) { - outputStreamMissing &= (out == null) && (painterMaker.needsOutputStream()); + documentHandlerMaker = getDocumentHandlerMaker(outputFormat); + if (documentHandlerMaker != null) { + outputStreamMissing &= (out == null) + && (documentHandlerMaker.needsOutputStream()); } } else { outputStreamMissing &= (out == null) && (rendMaker.needsOutputStream()); } if (userAgent.getRendererOverride() != null || rendMaker != null - || painterMaker != null) { + || documentHandlerMaker != null) { if (outputStreamMissing) { throw new FOPException( "OutputStream has not been set"); @@ -308,32 +310,26 @@ public class RendererFactory { } /** - * Creates a {@code IFPainter} object based on render-type desired + * Creates a {@code IFDocumentHandler} object based on the desired output format. * @param userAgent the user agent for access to configuration * @param outputFormat the MIME type of the output format to use (ex. "application/pdf"). - * @return the new {@code IFPainter} instance - * @throws FOPException if the painter cannot be properly constructed + * @return the new {@code IFDocumentHandler} instance + * @throws FOPException if the document handler cannot be properly constructed */ - public IFPainter createPainter(FOUserAgent userAgent, String outputFormat) + public IFDocumentHandler createDocumentHandler(FOUserAgent userAgent, String outputFormat) throws FOPException { /* - if (userAgent.getIFPainterOverride() != null) { - return userAgent.getIFPainterOverride(); + if (userAgent.getIFDocumentHandlerOverride() != null) { + return userAgent.getIFDocumentHandlerOverride(); } else { */ - AbstractIFPainterMaker maker = getPainterMaker(outputFormat); + AbstractIFDocumentHandlerMaker maker = getDocumentHandlerMaker(outputFormat); if (maker == null) { throw new UnsupportedOperationException( - "No renderer for the requested format available: " + outputFormat); + "No IF document handler for the requested format available: " + outputFormat); } - IFPainter painter = maker.makePainter(userAgent); - painter.setUserAgent(userAgent); - IFPainterConfigurator configurator = maker.getConfigurator(userAgent); - if (configurator != null) { - configurator.configure(painter); - configurator.setupFontInfo(painter); - } - return painter; + IFDocumentHandler documentHandler = maker.makeIFDocumentHandler(userAgent); + return documentHandler; //} } @@ -350,7 +346,7 @@ public class RendererFactory { while (iter.hasNext()) { lst.add(((String)iter.next())); } - iter = this.painterMakerMapping.keySet().iterator(); + iter = this.documentHandlerMakerMapping.keySet().iterator(); while (iter.hasNext()) { lst.add(((String)iter.next())); } @@ -409,24 +405,23 @@ public class RendererFactory { } /** - * Discovers {@code IFPainter} implementations through the classpath and dynamically + * Discovers {@code IFDocumentHandler} implementations through the classpath and dynamically * registers them. */ - private void discoverPainters() { + private void discoverDocumentHandlers() { // add mappings from available services - Iterator providers - = Service.providers(IFPainter.class); + Iterator providers = Service.providers(IFDocumentHandler.class); if (providers != null) { while (providers.hasNext()) { - AbstractIFPainterMaker maker = (AbstractIFPainterMaker)providers.next(); + AbstractIFDocumentHandlerMaker maker = (AbstractIFDocumentHandlerMaker)providers.next(); try { if (log.isDebugEnabled()) { - log.debug("Dynamically adding maker for IFPainter: " + log.debug("Dynamically adding maker for IFDocumentHandler: " + maker.getClass().getName()); } - addPainterMaker(maker); + addDocumentHandlerMaker(maker); } catch (IllegalArgumentException e) { - log.error("Error while adding maker for IFPainter", e); + log.error("Error while adding maker for IFDocumentHandler", e); } } diff --git a/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java b/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java new file mode 100644 index 000000000..937a07465 --- /dev/null +++ b/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java @@ -0,0 +1,109 @@ +/* + * 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.image.BufferedImage; + +import org.apache.xmlgraphics.image.writer.ImageWriterParams; + +import org.apache.fop.render.java2d.Java2DRenderingSettings; + +/** + * This class holds settings used when rendering to bitmaps. + */ +public class BitmapRenderingSettings extends Java2DRenderingSettings implements TIFFConstants { + + /** ImageWriter parameters */ + private ImageWriterParams writerParams; + + /** Image Type as parameter for the BufferedImage constructor (see BufferedImage.TYPE_*) */ + private int bufferedImageType = BufferedImage.TYPE_INT_ARGB; + + /** true if anti-aliasing is set */ + private boolean antialiasing = true; + + /** true if qualityRendering is set */ + private boolean qualityRendering = true; + + /** + * Default constructor. Initializes the settings to their default values. + */ + public BitmapRenderingSettings() { + writerParams = new ImageWriterParams(); + writerParams.setCompressionMethod(COMPRESSION_PACKBITS); + } + + /** + * Returns the image writer parameters used for encoding the bitmap images. + * @return the image writer parameters + */ + public ImageWriterParams getWriterParams() { + return this.writerParams; + } + + /** + * Returns the BufferedImage type. + * @return one of BufferedImage.TYPE_* + */ + public int getBufferedImageType() { + return this.bufferedImageType; + } + + /** + * Sets the type of the BufferedImage to use when preparing a new instance. + * @param bufferedImageType a BufferImage.TYPE_* value + */ + public void setBufferedImageType(int bufferedImageType) { + this.bufferedImageType = bufferedImageType; + } + + /** + * Enables or disables anti-aliasing. + * @param value true to enable anti-aliasing + */ + public void setAntiAliasing(boolean value) { + this.antialiasing = value; + } + + /** + * Indicates whether anti-aliasing is enabled. + * @return true if anti-aliasing is enabled + */ + public boolean isAntiAliasingEnabled() { + return this.antialiasing; + } + + /** + * Controls whether to optimize rendering for speed or for quality. + * @param quality true to optimize for quality, false to optimize for speed + */ + public void setQualityRendering(boolean quality) { + this.qualityRendering = quality; + } + + /** + * Indicates whether quality rendering is enabled. + * @return true indicates optimization for quality, false indicates optimization for speed + */ + public boolean isQualityRenderingEnabled() { + return this.qualityRendering; + } + +} diff --git a/src/java/org/apache/fop/render/bitmap/TIFFConstants.java b/src/java/org/apache/fop/render/bitmap/TIFFConstants.java new file mode 100644 index 000000000..437cf536a --- /dev/null +++ b/src/java/org/apache/fop/render/bitmap/TIFFConstants.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.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; + + /** No compression */ + String COMPRESSION_NONE = "NONE"; + /** JPEG compression */ + String COMPRESSION_JPEG = "JPEG"; + /** Packbits (RLE) compression */ + String COMPRESSION_PACKBITS = "PackBits"; + /** Deflate compression */ + String COMPRESSION_DEFLATE = "Deflate"; + /** LZW compression */ + String COMPRESSION_LZW = "LZW"; + /** ZLib compression */ + String COMPRESSION_ZLIB = "ZLib"; + /** CCITT Group 4 (T.6) compression */ + String COMPRESSION_CCITT_T6 = "CCITT T.6"; //CCITT Group 4 + /** CCITT Group 3 (T.4) compression */ + String COMPRESSION_CCITT_T4 = "CCITT T.4"; //CCITT Group 3 + +} diff --git a/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java b/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java new file mode 100644 index 000000000..0da1c02fe --- /dev/null +++ b/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java @@ -0,0 +1,272 @@ +/* + * 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.Dimension; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +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.FOUserAgent; +import org.apache.fop.apps.FopFactoryConfigurator; +import org.apache.fop.apps.MimeConstants; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler; +import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; +import org.apache.fop.render.intermediate.IFException; +import org.apache.fop.render.intermediate.IFPainter; +import org.apache.fop.render.java2d.Java2DPainter; +import org.apache.fop.render.java2d.Java2DUtil; + +/** + * {@code IFDocumentHandler} implementation that produces PCL 5. + */ +public class TIFFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler + implements TIFFConstants { + + /** logging instance */ + private static Log log = LogFactory.getLog(TIFFDocumentHandler.class); + + private ImageWriter imageWriter; + private MultiImageWriter multiImageWriter; + + private int pageCount; + private Dimension currentPageDimensions; + private BufferedImage currentImage; + + private BitmapRenderingSettings bitmapSettings = new BitmapRenderingSettings(); + + private double scaleFactor = 1.0; + + /** + * Default constructor. + */ + public TIFFDocumentHandler() { + } + + /** {@inheritDoc} */ + public boolean supportsPagesOutOfOrder() { + return false; + } + + /** {@inheritDoc} */ + public String getMimeType() { + return MimeConstants.MIME_TIFF; + } + + /** {@inheritDoc} */ + public void setUserAgent(FOUserAgent ua) { + super.setUserAgent(ua); + + //Set target resolution + int dpi = Math.round(ua.getTargetResolution()); + getSettings().getWriterParams().setResolution(dpi); + } + + /** {@inheritDoc} */ + public IFDocumentHandlerConfigurator getConfigurator() { + return new TIFFRendererConfigurator(getUserAgent()); + } + + /** + * Returns the settings for bitmap rendering. + * @return the settings object + */ + public BitmapRenderingSettings getSettings() { + return this.bitmapSettings; + } + + /** {@inheritDoc} */ + public void setDefaultFontInfo(FontInfo fontInfo) { + FontInfo fi = Java2DUtil.buildDefaultJava2DBasedFontInfo(fontInfo, getUserAgent()); + setFontInfo(fi); + } + + //---------------------------------------------------------------------------------------------- + + /** {@inheritDoc} */ + public void startDocument() throws IFException { + try { + if (getUserAgent() == null) { + throw new IllegalStateException( + "User agent must be set before starting PDF generation"); + } + if (this.outputStream == null) { + throw new IllegalStateException("OutputStream hasn't been set through setResult()"); + } + + // Creates writer + this.imageWriter = ImageWriterRegistry.getInstance().getWriterFor(getMimeType()); + if (this.imageWriter == null) { + BitmapRendererEventProducer eventProducer + = BitmapRendererEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.noImageWriterFound(this, getMimeType()); + } + if (this.imageWriter.supportsMultiImageWriter()) { + this.multiImageWriter = this.imageWriter.createMultiImageWriter(outputStream); + } + this.pageCount = 0; + } catch (IOException e) { + throw new IFException("I/O error in startDocument()", e); + } + } + + /** {@inheritDoc} */ + public void endDocumentHeader() throws IFException { + } + + /** {@inheritDoc} */ + public void endDocument() throws IFException { + try { + if (this.multiImageWriter != null) { + this.multiImageWriter.close(); + } + this.multiImageWriter = null; + this.imageWriter = null; + } catch (IOException ioe) { + throw new IFException("I/O error in endDocument()", ioe); + } + super.endDocument(); + } + + /** {@inheritDoc} */ + public void startPageSequence(String id) throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void endPageSequence() throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void startPage(int index, String name, Dimension size) throws IFException { + this.pageCount++; + this.currentPageDimensions = new Dimension(size); + } + + /** {@inheritDoc} */ + public IFPainter startPageContent() throws IFException { + double scale = scaleFactor + * (25.4f / FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION) + / getUserAgent().getTargetPixelUnitToMillimeter(); + int bitmapWidth = (int) ((this.currentPageDimensions.width * scale / 1000f) + 0.5f); + int bitmapHeight = (int) ((this.currentPageDimensions.height * scale / 1000f) + 0.5f); + this.currentImage = createBufferedImage(bitmapWidth, bitmapHeight); + Graphics2D graphics2D = this.currentImage.createGraphics(); + // draw page background + if (!getSettings().hasTransparentPageBackground()) { + graphics2D.setBackground(getSettings().getPageBackgroundColor()); + graphics2D.setPaint(getSettings().getPageBackgroundColor()); + graphics2D.fillRect(0, 0, bitmapWidth, bitmapHeight); + } + + graphics2D.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_ON); + if (getSettings().isAntiAliasingEnabled() + && this.currentImage.getColorModel().getPixelSize() > 1) { + graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + graphics2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + } else { + graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_OFF); + graphics2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + } + if (getSettings().isQualityRenderingEnabled()) { + graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + } else { + graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_SPEED); + } + graphics2D.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, + RenderingHints.VALUE_STROKE_PURE); + graphics2D.scale(scale / 1000f, scale / 1000f); + + return new Java2DPainter(graphics2D, getUserAgent(), getFontInfo()); + } + + /** + * Creates a new BufferedImage. + * @param bitmapWidth the desired width in pixels + * @param bitmapHeight the desired height in pixels + * @return the new BufferedImage instance + */ + protected BufferedImage createBufferedImage(int bitmapWidth, int bitmapHeight) { + return new BufferedImage(bitmapWidth, bitmapHeight, getSettings().getBufferedImageType()); + } + + /** {@inheritDoc} */ + public void endPageContent() throws IFException { + try { + if (this.multiImageWriter == null) { + switch (this.pageCount) { + case 1: + this.imageWriter.writeImage( + this.currentImage, this.outputStream, + getSettings().getWriterParams()); + break; + case 2: + BitmapRendererEventProducer eventProducer + = BitmapRendererEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.stoppingAfterFirstPageNoFilename(this); + break; + default: + //ignore + } + } else { + this.multiImageWriter.writeImage(this.currentImage, + getSettings().getWriterParams()); + } + this.currentImage = null; + } catch (IOException ioe) { + throw new IFException("I/O error while encoding BufferedImage", ioe); + } + } + + /** {@inheritDoc} */ + public void endPage() throws IFException { + this.currentPageDimensions = null; + } + + /** {@inheritDoc} */ + public void handleExtensionObject(Object extension) throws IFException { + if (false) { + //TODO Handle extensions + } else { + log.debug("Don't know how to handle extension object. Ignoring: " + + extension + " (" + extension.getClass().getName() + ")"); + } + } + +} diff --git a/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandlerMaker.java b/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandlerMaker.java new file mode 100644 index 000000000..dd1cb10be --- /dev/null +++ b/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandlerMaker.java @@ -0,0 +1,58 @@ +/* + * 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 org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.MimeConstants; +import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker; +import org.apache.fop.render.intermediate.IFDocumentHandler; +import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; + +/** + * Document handler factory for TIFF output. + */ +public class TIFFDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { + + //TODO Revert to normal MIME after stabilization! + private static final String[] MIMES = new String[] {MimeConstants.MIME_TIFF + ";mode=painter"}; + + /** {@inheritDoc} */ + public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { + TIFFDocumentHandler handler = new TIFFDocumentHandler(); + handler.setUserAgent(ua); + return handler; + } + + /** {@inheritDoc} */ + public boolean needsOutputStream() { + return true; + } + + /** {@inheritDoc} */ + public String[] getSupportedMimeTypes() { + return MIMES; + } + + /** {@inheritDoc} */ + public IFDocumentHandlerConfigurator getConfigurator(FOUserAgent userAgent) { + return new TIFFRendererConfigurator(userAgent); + } + +} diff --git a/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java b/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java index fea831a9b..c524ccc3a 100644 --- a/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java +++ b/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java @@ -43,7 +43,6 @@ 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; /** @@ -67,19 +66,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 { - - /** The MIME type for tiff-Rendering */ - public static final String MIME_TYPE = MimeConstants.MIME_TIFF; - - //private static final String COMPRESSION_NONE = "NONE"; - //private static final String COMPRESSION_JPEG = "JPEG"; - public static final String COMPRESSION_PACKBITS = "PackBits"; - //private static final String COMPRESSION_DEFLATE = "Deflate"; - //private static final String COMPRESSION_LZW = "LZW"; - //private static final String COMPRESSION_ZLIB = "ZLib"; - public static final String COMPRESSION_CCITT_T6 = "CCITT T.6"; //CCITT Group 4 - public static final String COMPRESSION_CCITT_T4 = "CCITT T.4"; //CCITT Group 3 +public class TIFFRenderer extends Java2DRenderer implements TIFFConstants { /** ImageWriter parameters */ private ImageWriterParams writerParams; diff --git a/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java index ff5e22ceb..a5b8e5531 100644 --- a/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java +++ b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java @@ -19,18 +19,38 @@ package org.apache.fop.render.bitmap; +import java.awt.Color; +import java.awt.Graphics2D; import java.awt.image.BufferedImage; +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.render.PrintRendererConfigurator; +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.Renderer; +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; /** * TIFF Renderer configurator */ -public class TIFFRendererConfigurator extends PrintRendererConfigurator { +public class TIFFRendererConfigurator extends Java2DRendererConfigurator + implements IFDocumentHandlerConfigurator { /** * Default constructor @@ -52,15 +72,9 @@ public class TIFFRendererConfigurator extends PrintRendererConfigurator { if (cfg != null) { TIFFRenderer tiffRenderer = (TIFFRenderer)renderer; //set compression - String name = cfg.getChild("compression").getValue(TIFFRenderer.COMPRESSION_PACKBITS); + String name = cfg.getChild("compression").getValue(TIFFConstants.COMPRESSION_PACKBITS); //Some compression formats need a special image format: - if (name.equalsIgnoreCase(TIFFRenderer.COMPRESSION_CCITT_T6)) { - tiffRenderer.setBufferedImageType(BufferedImage.TYPE_BYTE_BINARY); - } else if (name.equalsIgnoreCase(TIFFRenderer.COMPRESSION_CCITT_T4)) { - tiffRenderer.setBufferedImageType(BufferedImage.TYPE_BYTE_BINARY); - } else { - tiffRenderer.setBufferedImageType(BufferedImage.TYPE_INT_ARGB); - } + tiffRenderer.setBufferedImageType(getBufferedImageTypeFor(name)); if (!"NONE".equalsIgnoreCase(name)) { tiffRenderer.getWriterParams().setCompressionMethod(name); } @@ -70,4 +84,104 @@ public class TIFFRendererConfigurator extends PrintRendererConfigurator { } super.configure(renderer); } + + 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)) { + return BufferedImage.TYPE_BYTE_BINARY; + } else { + return BufferedImage.TYPE_INT_ARGB; + } + } + + // ---=== IFDocumentHandler configuration ===--- + + /** {@inheritDoc} */ + public void configure(IFDocumentHandler documentHandler) throws FOPException { + Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); + if (cfg != 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); + } + + 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)); + } else { + settings.setPageBackgroundColor(Color.WHITE); + } + } + + 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); + } + + 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 { + throw new FOPException("Invalid value for color-mode: " + color); + } + } + } + } + + /** {@inheritDoc} */ + public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo) + throws FOPException { + FontManager fontManager = userAgent.getFactory().getFontManager(); + + Graphics2D graphics2D = Java2DFontMetrics.createFontMetricsGraphics2D(); + + List fontCollections = new java.util.ArrayList(); + fontCollections.add(new Base14FontCollection(graphics2D)); + fontCollections.add(new InstalledFontCollection(graphics2D)); + + 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)); + } + + fontManager.setup(fontInfo, + (FontCollection[])fontCollections.toArray( + new FontCollection[fontCollections.size()])); + documentHandler.setFontInfo(fontInfo); + } + + } diff --git a/src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFPainter.java b/src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFDocumentHandler.java index 7f82f3d93..758b18dbb 100644 --- a/src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFPainter.java +++ b/src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFDocumentHandler.java @@ -37,9 +37,9 @@ import org.apache.fop.fonts.FontManager; import org.apache.fop.fonts.base14.Base14FontCollection; /** - * Abstract base class for binary-writing IFPainter implementations. + * Abstract base class for binary-writing {@code IFDocumentHandler} implementations. */ -public abstract class AbstractBinaryWritingIFPainter extends AbstractIFPainter { +public abstract class AbstractBinaryWritingIFDocumentHandler extends AbstractIFDocumentHandler { /** The output stream to write the document to */ protected OutputStream outputStream; @@ -83,10 +83,7 @@ public abstract class AbstractBinaryWritingIFPainter extends AbstractIFPainter { } } - /** - * Returns the {@code FontInfo} object. - * @return the font info - */ + /** {@inheritDoc} */ public FontInfo getFontInfo() { return this.fontInfo; } @@ -97,13 +94,13 @@ public abstract class AbstractBinaryWritingIFPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void setDefaultFontInfo() { + public void setDefaultFontInfo(FontInfo fontInfo) { FontManager fontManager = getUserAgent().getFactory().getFontManager(); FontCollection[] fontCollections = new FontCollection[] { new Base14FontCollection(fontManager.isBase14KerningEnabled()) }; - FontInfo fi = new FontInfo(); + FontInfo fi = (fontInfo != null ? fontInfo : new FontInfo()); fi.setEventListener(new FontEventAdapter(getUserAgent().getEventBroadcaster())); fontManager.setup(fi, fontCollections); setFontInfo(fi); diff --git a/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java b/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java new file mode 100644 index 000000000..b1f1f20f9 --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.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.intermediate; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.fop.apps.FOUserAgent; + +/** + * Abstract base class for {@code IFDocumentHandler} implementations. + */ +public abstract class AbstractIFDocumentHandler implements IFDocumentHandler { + + /** logging instance */ + private static Log log = LogFactory.getLog(AbstractIFDocumentHandler.class); + + private FOUserAgent userAgent; + + /** + * Default constructor. + */ + public AbstractIFDocumentHandler() { + } + + /** {@inheritDoc} */ + public void setUserAgent(FOUserAgent ua) { + if (this.userAgent != null) { + throw new IllegalStateException("The user agent was already set"); + } + this.userAgent = ua; + } + + /** + * Returns the user agent. + * @return the user agent + */ + public FOUserAgent getUserAgent() { + return this.userAgent; + } + + /** {@inheritDoc} */ + public void startDocumentHeader() throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void endDocumentHeader() throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void startDocumentTrailer() throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void endDocumentTrailer() throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void startPageHeader() throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void endPageHeader() throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void startPageTrailer() throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void endPageTrailer() throws IFException { + //nop + } + +} diff --git a/src/java/org/apache/fop/render/intermediate/AbstractIFPainterMaker.java b/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandlerMaker.java index aa653cd3e..f163c3776 100644 --- a/src/java/org/apache/fop/render/intermediate/AbstractIFPainterMaker.java +++ b/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandlerMaker.java @@ -22,38 +22,38 @@ package org.apache.fop.render.intermediate; import org.apache.fop.apps.FOUserAgent; /** - * Base class for factory classes which instantiate {@code IFPainter}s and provide information - * about them. + * Base class for factory classes which instantiate {@code IFDocumentHandler}s and provide + * information about them. */ -public abstract class AbstractIFPainterMaker { +public abstract class AbstractIFDocumentHandlerMaker { /** - * Instantiates a new {@code IFPainter}. + * Instantiates a new {@code IFDocumentHandler}. * @param userAgent the user agent - * @return the newly instantiated painter + * @return the newly instantiated document handler */ - public abstract IFPainter makePainter(FOUserAgent userAgent); + public abstract IFDocumentHandler makeIFDocumentHandler(FOUserAgent userAgent); /** - * @return Indicates whether this painter requires an OutputStream to work with. + * @return Indicates whether this document handler requires an OutputStream to work with. */ public abstract boolean needsOutputStream(); /** - * @return an array of MIME types the painter supports. + * @return an array of MIME types the document handler supports. */ public abstract String[] getSupportedMimeTypes(); /** * Returns a configurator object that can be used to - * configure the painter. + * configure the document handler. * @param userAgent the user agent - * @return a configurator object that can be used to configure the painter + * @return a configurator object that can be used to configure the document handler */ - public abstract IFPainterConfigurator getConfigurator(FOUserAgent userAgent); + public abstract IFDocumentHandlerConfigurator getConfigurator(FOUserAgent userAgent); /** - * Indicates whether a specific MIME type is supported by this painter. + * Indicates whether a specific MIME type is supported by this document handler. * @param mimeType the MIME type (ex. "application/pdf") * @return true if the MIME type is supported */ diff --git a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java index 90876b18c..a54e62bd0 100644 --- a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java +++ b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java @@ -40,6 +40,7 @@ import org.apache.xmlgraphics.image.loader.ImageSessionContext; import org.apache.xmlgraphics.image.loader.util.ImageUtil; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.FopFactory; import org.apache.fop.events.ResourceEventProducer; import org.apache.fop.render.ImageHandler; import org.apache.fop.render.ImageHandlerRegistry; @@ -56,12 +57,6 @@ public abstract class AbstractIFPainter implements IFPainter { /** non-URI that can be used in feedback messages that an image is an instream-object */ protected static final String INSTREAM_OBJECT_URI = "(instream-object)"; - private FOUserAgent userAgent; - - /** Image handler registry */ - protected ImageHandlerRegistry imageHandlerRegistry = new ImageHandlerRegistry(); - //TODO Move reference to FOPFactory to the user has a chance to add his own implementations - //and so the lookup process isn't redone for each painter instance. /** * Default constructor. @@ -69,60 +64,18 @@ public abstract class AbstractIFPainter implements IFPainter { public AbstractIFPainter() { } - /** {@inheritDoc} */ - public void setUserAgent(FOUserAgent ua) { - if (this.userAgent != null) { - throw new IllegalStateException("The user agent was already set"); - } - this.userAgent = ua; - } - /** * Returns the user agent. * @return the user agent */ - protected FOUserAgent getUserAgent() { - return this.userAgent; - } - - /** {@inheritDoc} */ - public void startDocumentHeader() throws IFException { - //nop - } - - /** {@inheritDoc} */ - public void endDocumentHeader() throws IFException { - //nop - } - - /** {@inheritDoc} */ - public void startDocumentTrailer() throws IFException { - //nop - } + protected abstract FOUserAgent getUserAgent(); - /** {@inheritDoc} */ - public void endDocumentTrailer() throws IFException { - //nop - } - - /** {@inheritDoc} */ - public void startPageHeader() throws IFException { - //nop - } - - /** {@inheritDoc} */ - public void endPageHeader() throws IFException { - //nop - } - - /** {@inheritDoc} */ - public void startPageTrailer() throws IFException { - //nop - } - - /** {@inheritDoc} */ - public void endPageTrailer() throws IFException { - //nop + /** + * Returns the FOP factory. + * @return the FOP factory. + */ + protected FopFactory getFopFactory() { + return getUserAgent().getFactory(); } private AffineTransform combine(AffineTransform[] transforms) { @@ -159,8 +112,9 @@ public abstract class AbstractIFPainter implements IFPainter { */ protected void drawImageUsingImageHandler(ImageInfo info, Rectangle rect) throws ImageException, IOException { - ImageManager manager = getUserAgent().getFactory().getImageManager(); + ImageManager manager = getFopFactory().getImageManager(); ImageSessionContext sessionContext = getUserAgent().getImageSessionContext(); + ImageHandlerRegistry imageHandlerRegistry = getFopFactory().getImageHandlerRegistry(); //Load and convert the image to a supported format RenderingContext context = createRenderingContext(); @@ -197,7 +151,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 = getUserAgent().getFactory().getImageManager(); + ImageManager manager = getFopFactory().getImageManager(); ImageInfo info = null; try { ImageSessionContext sessionContext = getUserAgent().getImageSessionContext(); @@ -225,7 +179,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 = getUserAgent().getFactory().getImageManager(); + ImageManager manager = getFopFactory().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 new file mode 100644 index 000000000..98706c09b --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFDocumentHandler.java @@ -0,0 +1,86 @@ +/* + * 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 javax.xml.transform.OutputKeys; +import javax.xml.transform.Result; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.sax.SAXTransformerFactory; +import javax.xml.transform.sax.TransformerHandler; + +import org.xml.sax.ContentHandler; + +import org.apache.fop.util.GenerationHelperContentHandler; + +/** + * Abstract base class for XML-writing {@code IFDocumentHandler} implementations. + */ +public abstract class AbstractXMLWritingIFDocumentHandler extends AbstractIFDocumentHandler { + + /** + * Default SAXTransformerFactory that can be used by subclasses. + */ + protected SAXTransformerFactory tFactory + = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); + + /** Main SAX ContentHandler to receive the generated SAX events. */ + protected GenerationHelperContentHandler handler; + + /** {@inheritDoc} */ + public void setResult(Result result) throws IFException { + if (result instanceof SAXResult) { + SAXResult saxResult = (SAXResult)result; + this.handler = new GenerationHelperContentHandler( + saxResult.getHandler(), getMainNamespace()); + } else { + this.handler = new GenerationHelperContentHandler( + createContentHandler(result), getMainNamespace()); + } + } + + /** + * Returns the main namespace used for generated XML content. + * @return the main namespace + */ + protected abstract String getMainNamespace(); + + /** + * Creates a ContentHandler for the given JAXP Result instance. + * @param result the JAXP Result instance + * @return the requested SAX ContentHandler + * @throws IFException if an error occurs setting up the output + */ + protected ContentHandler createContentHandler(Result result) throws IFException { + try { + TransformerHandler tHandler = tFactory.newTransformerHandler(); + Transformer transformer = tHandler.getTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); + tHandler.setResult(result); + return tHandler; + } catch (TransformerConfigurationException tce) { + throw new IFException( + "Error while setting up the serializer for XML output", tce); + } + } + +} diff --git a/src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFPainter.java b/src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFPainter.java deleted file mode 100644 index 1c90c47f4..000000000 --- a/src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFPainter.java +++ /dev/null @@ -1,277 +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.intermediate; - -import java.awt.Rectangle; -import java.awt.geom.AffineTransform; - -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Result; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.sax.SAXResult; -import javax.xml.transform.sax.SAXTransformerFactory; -import javax.xml.transform.sax.TransformerHandler; - -import org.xml.sax.Attributes; -import org.xml.sax.ContentHandler; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.AttributesImpl; - -import org.apache.xmlgraphics.util.QName; - -import org.apache.fop.fonts.FontInfo; -import org.apache.fop.util.DecimalFormatCache; -import org.apache.fop.util.XMLUtil; - -/** - * Abstract base class for XML-writing IFPainter implementations. - */ -public abstract class AbstractXMLWritingIFPainter extends AbstractIFPainter { - - private static final Attributes EMPTY_ATTS = new AttributesImpl(); - - /** - * Default SAXTransformerFactory that can be used by subclasses. - */ - protected SAXTransformerFactory tFactory - = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); - - /** Main SAX ContentHandler to receive the generated SAX events. */ - protected ContentHandler handler; - - /** {@inheritDoc} */ - public void setResult(Result result) throws IFException { - if (result instanceof SAXResult) { - SAXResult saxResult = (SAXResult)result; - this.handler = saxResult.getHandler(); - } else { - this.handler = createContentHandler(result); - } - } - - /** {@inheritDoc} */ - public void setFontInfo(FontInfo fontInfo) { - //nop, not used - } - - /** {@inheritDoc} */ - public void setDefaultFontInfo() { - //nop, not used - } - - /** - * Returns the main namespace used for generated XML content. - * @return the main namespace - */ - protected abstract String getMainNamespace(); - - /** - * Creates a ContentHandler for the given JAXP Result instance. - * @param result the JAXP Result instance - * @return the requested SAX ContentHandler - * @throws IFException if an error occurs setting up the output - */ - protected ContentHandler createContentHandler(Result result) throws IFException { - try { - TransformerHandler tHandler = tFactory.newTransformerHandler(); - Transformer transformer = tHandler.getTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty(OutputKeys.METHOD, "xml"); - tHandler.setResult(result); - return tHandler; - } catch (TransformerConfigurationException tce) { - throw new IFException( - "Error while setting up the serializer for SVG output", tce); - } - } - - /* ---=== helper methods ===--- */ - - private static String format(double value) { - if (value == -0.0) { - //Don't allow negative zero because of testing - //See http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2.3 - value = 0.0; - } - return DecimalFormatCache.getDecimalFormat(6).format(value); - } - - /** - * Converts an {@code AffineTransform} instance to an SVG style transform method. - * @param transform the transformation matrix - * @param sb the StringBuffer to write the transform method to - * @return the StringBuffer passed to this method - */ - public static StringBuffer toString(AffineTransform transform, StringBuffer sb) { - if (transform.isIdentity()) { - return sb; - } - double[] matrix = new double[6]; - transform.getMatrix(matrix); - if (matrix[0] == 1 && matrix[3] == 1 && matrix[1] == 0 && matrix[2] == 0) { - sb.append("translate("); - sb.append(format(matrix[4])); - if (matrix[5] != 0) { - sb.append(',').append(format(matrix[5])); - } - } else { - sb.append("matrix("); - for (int i = 0; i < 6; i++) { - if (i > 0) { - sb.append(','); - } - sb.append(format(matrix[i])); - } - } - sb.append(')'); - return sb; - } - - /** - * Converts an {@code AffineTransform} array to an SVG style transform method sequence. - * @param transforms the transformation matrix array - * @param sb the StringBuffer to write the transform method sequence to - * @return the StringBuffer passed to this method - */ - public static StringBuffer toString(AffineTransform[] transforms, StringBuffer sb) { - for (int i = 0, c = transforms.length; i < c; i++) { - if (i > 0) { - sb.append(' '); - } - toString(transforms[i], sb); - } - return sb; - } - - /** - * Converts an {@code AffineTransform} array to an SVG style transform method sequence. - * @param transforms the transformation matrix array - * @return the formatted array - */ - public static String toString(AffineTransform[] transforms) { - return toString(transforms, new StringBuffer()).toString(); - } - - /** - * Converts an {@code AffineTransform} instance to an SVG style transform method. - * @param transform the transformation matrix - * @return the formatted array - */ - public static String toString(AffineTransform transform) { - return toString(transform, new StringBuffer()).toString(); - } - - /** - * Convenience method to generate a startElement SAX event. - * @param localName the local name of the element - * @param atts the attributes - * @throws SAXException if a SAX exception occurs - */ - protected void startElement(String localName, Attributes atts) throws SAXException { - handler.startElement(getMainNamespace(), localName, localName, atts); - } - - /** - * Convenience method to generate a startElement SAX event. - * @param localName the local name of the element - * @throws SAXException if a SAX exception occurs - */ - protected void startElement(String localName) throws SAXException { - handler.startElement(getMainNamespace(), localName, localName, EMPTY_ATTS); - } - - /** - * Convenience method to generate a endElement SAX event. - * @param localName the local name of the element - * @throws SAXException if a SAX exception occurs - */ - protected void endElement(String localName) throws SAXException { - handler.endElement(getMainNamespace(), localName, localName); - } - - /** - * Convenience method to generate an empty element. - * @param localName the local name of the element - * @param atts the attributes - * @throws SAXException if a SAX exception occurs - */ - protected void element(String localName, Attributes atts) throws SAXException { - handler.startElement(getMainNamespace(), localName, localName, atts); - handler.endElement(getMainNamespace(), localName, localName); - } - - /** - * Adds an attribute to a given {@code AttributesImpl} instance. - * @param atts the attributes collection - * @param attribute the attribute to add - * @param value the attribute's CDATA value - */ - protected void addAttribute(AttributesImpl atts, QName attribute, String value) { - atts.addAttribute(attribute.getNamespaceURI(), - attribute.getLocalName(), attribute.getQName(), XMLUtil.CDATA, value); - } - - /** - * Adds an attribute to a given {@code AttributesImpl} instance. The attribute will be - * added in the default namespace. - * @param atts the attributes collection - * @param localName the local name of the attribute - * @param value the attribute's CDATA value - */ - protected void addAttribute(AttributesImpl atts, String localName, String value) { - atts.addAttribute("", localName, localName, XMLUtil.CDATA, value); - } - - /** - * Converts an array of integer coordinates into a space-separated string. - * @param coordinates the coordinates - * @return the space-separated array of coordinates - */ - protected String toString(int[] coordinates) { - if (coordinates == null) { - return ""; - } - StringBuffer sb = new StringBuffer(); - for (int i = 0, c = coordinates.length; i < c; i++) { - if (i > 0) { - sb.append(' '); - } - sb.append(Integer.toString(coordinates[i])); - } - return sb.toString(); - } - - /** - * Converts a rectangle into a space-separated string. - * @param rect the rectangle - * @return the space-separated array of coordinates - */ - protected String toString(Rectangle rect) { - if (rect == null) { - return ""; - } - StringBuffer sb = new StringBuffer(); - sb.append(rect.x).append(' ').append(rect.y).append(' '); - sb.append(rect.width).append(' ').append(rect.height); - return sb.toString(); - } - -} diff --git a/src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java b/src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java new file mode 100644 index 000000000..61093769b --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java @@ -0,0 +1,254 @@ +/* + * 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 java.awt.Dimension; + +import javax.xml.transform.Result; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.fonts.FontInfo; + +/** + * Interface used to paint whole documents layouted by Apache FOP. + * <p> + * Call sequence: + * <p> + * <pre> + * startDocument() + * startDocumentHeader() + * [handleExtension()]* + * endDocumentHeader() + * [ + * startPageSequence() + * [ + * startPage() + * startPageHeader() + * [handleExtension()]* + * endPageHeader() + * startPageContent() + * (#box)+ + * endPageContent() + * startPageTrailer() + * (addTarget())* + * endPageTrailer() + * endPage() + * ]* + * endPageSequence() + * ]* + * startDocumentTrailer() + * [handleExtension()]* + * endDocumentTrailer() + * endDocument() + * + * #box: + * startBox() (#pageContent)+ endBox() | + * startViewport() (#pageContext)+ endViewport() + * + * #pageContent: + * ( + * setFont() | + * drawText() | + * drawRect() | + * drawImage() | + * TODO etc. etc. | + * handleExtensionObject() + * ) + * </pre> + */ +public interface IFDocumentHandler { + + /** + * Set the user agent. + * @param userAgent The user agent + */ + void setUserAgent(FOUserAgent userAgent); + + /** + * Sets the JAXP Result object to receive the generated content. + * @param result the JAXP Result object to receive the generated content + * @throws IFException if an error occurs setting up the output + */ + void setResult(Result result) throws IFException; + + /** + * Sets the font set to work with. + * @param fontInfo the font info object + */ + void setFontInfo(FontInfo fontInfo); + + /** + * Returns the font set to work with. + * @return the font info object + */ + FontInfo getFontInfo(); + + /** + * Sets the default font set (with no custom configuration). + * @param fontInfo the font info object to populate + */ + void setDefaultFontInfo(FontInfo fontInfo); + + /** + * Returns the configurator for this document handler, if any. + * @return the configurator or null if there's no configurator + */ + IFDocumentHandlerConfigurator getConfigurator(); + + /** + * Indicates whether the painter supports to handle the pages in mixed order rather than + * ascending order. + * @return true if out-of-order handling is supported + */ + boolean supportsPagesOutOfOrder(); + + /** + * Returns the MIME type of the output format that is generated by this implementation. + * @return the MIME type + */ + String getMimeType(); + + /** + * Indicates the start of a document. This method may only be called once before any other + * event method. + * @throws IFException if an error occurs while handling this event + */ + void startDocument() throws IFException; + + /** + * Indicates the end of a document. This method may only be called once after the whole + * document has been handled. Implementations can release resources (close streams). It is + * an error to call any event method after this method. + * @throws IFException if an error occurs while handling this event + */ + void endDocument() throws IFException; + + /** + * Indicates the start of the document header. This method is called right after the + * {@code #startDocument()} method. Extensions sent to this painter between + * {@code #startDocumentHeader()} and {@code #endDocumentHeader()} apply to the document as + * a whole (like document metadata). + * @throws IFException if an error occurs while handling this event + */ + void startDocumentHeader() throws IFException; + + /** + * Indicates the end of the document header. This method is called before the first + * page sequence. + * @throws IFException if an error occurs while handling this event + */ + void endDocumentHeader() throws IFException; + + /** + * Indicates the start of the document trailer. This method is called after the last + * page sequence. Extensions sent to the painter between + * {@code #startDocumentTrailer()} and {@code #endDocumentTrailer()} apply to the document as + * a whole and is used for document-level content that is only known after all pages have + * been rendered (like named destinations or the bookmark tree). + * @throws IFException if an error occurs while handling this event + */ + void startDocumentTrailer() throws IFException; + + /** + * Indicates the end of the document trailer. This method is called right before the + * {@code #endDocument()} method. + * @throws IFException if an error occurs while handling this event + */ + void endDocumentTrailer() throws IFException; + + /** + * Indicates the start of a new page sequence. + * @param id the page sequence's identifier (or null if none is available) + * @throws IFException if an error occurs while handling this event + */ + void startPageSequence(String id) throws IFException; + /** + * Indicates the end of a page sequence. + * @throws IFException if an error occurs while handling this event + */ + void endPageSequence() throws IFException; + + /** + * Indicates the start of a new page. + * @param index the index of the page (0-based) + * @param name the page name (usually the formatted page number) + * @param size the size of the page (equivalent to the MediaBox in PDF) + * @throws IFException if an error occurs while handling this event + */ + void startPage(int index, String name, Dimension size) throws IFException; + + /** + * Indicates the end of a page + * @throws IFException if an error occurs while handling this event + */ + void endPage() throws IFException; + + /** + * Indicates the start of the page header. + * @throws IFException if an error occurs while handling this event + */ + void startPageHeader() throws IFException; + + /** + * Indicates the end of the page header. + * @throws IFException if an error occurs while handling this event + */ + void endPageHeader() throws IFException; + + /** + * Indicates the start of the page content. The method returns an {@code IFPainter} interface + * which is used to paint the page contents. + * @throws IFException if an error occurs while handling this event + * @return the IFPainter for the page content + */ + IFPainter startPageContent() throws IFException; + + /** + * Indicates the end of the page content. Calls to the {@code IFPainter} returned by the + * respective {@code #startPageContent()} method are illegal. + * @throws IFException if an error occurs while handling this event + */ + void endPageContent() throws IFException; + + /** + * Indicates the start of the page trailer. The page trailer is used for writing down page + * elements which are only know after handling the page itself (like PDF targets). + * @throws IFException if an error occurs while handling this event + */ + void startPageTrailer() throws IFException; + + /** + * Indicates the end of the page trailer. + * @throws IFException if an error occurs while handling this event + */ + void endPageTrailer() throws IFException; + + /** + * Handles an extension object. This can be a DOM document or any arbitrary + * object. If an implementation doesn't know how to handle a particular extension it is simply + * ignored. + * @param extension the extension object + * @throws IFException if an error occurs while handling this event + */ + void handleExtensionObject(Object extension) throws IFException; + + //TODO Prototype the following: + //ContentHandler handleExtension() throws Exception +} diff --git a/src/java/org/apache/fop/render/intermediate/IFPainterConfigurator.java b/src/java/org/apache/fop/render/intermediate/IFDocumentHandlerConfigurator.java index 71a3a484a..633e564a7 100644 --- a/src/java/org/apache/fop/render/intermediate/IFPainterConfigurator.java +++ b/src/java/org/apache/fop/render/intermediate/IFDocumentHandlerConfigurator.java @@ -20,23 +20,26 @@ package org.apache.fop.render.intermediate; import org.apache.fop.apps.FOPException; +import org.apache.fop.fonts.FontInfo; /** - * This interface is implemented by classes that configure an {@code IFPainter} instance. + * This interface is implemented by classes that configure an {@code IFDocumentHandler} instance. */ -public interface IFPainterConfigurator { +public interface IFDocumentHandlerConfigurator { /** - * Configures a painter. - * @param painter the painter instance + * Configures a intermediate format document handler. + * @param documentHandler the document handler instance * @throws FOPException if an error occurs while configuring the object */ - void configure(IFPainter painter) throws FOPException; + void configure(IFDocumentHandler documentHandler) throws FOPException; /** - * Sets up the {@code FontInfo} object for the IFPainter. - * @param painter the painter instance + * Sets up the {@code FontInfo} object for the IFDocumentHandler. + * @param documentHandler the document handler instance + * @param fontInfo the font info object to set up * @throws FOPException if an error occurs while configuring the object */ - void setupFontInfo(IFPainter painter) throws FOPException; + void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo) throws FOPException; + } diff --git a/src/java/org/apache/fop/render/intermediate/IFGraphicContext.java b/src/java/org/apache/fop/render/intermediate/IFGraphicContext.java index 7250dcc39..34ac0bcb2 100644 --- a/src/java/org/apache/fop/render/intermediate/IFGraphicContext.java +++ b/src/java/org/apache/fop/render/intermediate/IFGraphicContext.java @@ -109,7 +109,7 @@ public class IFGraphicContext extends GraphicContext { /** {@inheritDoc} */ public String toString() { StringBuffer sb = new StringBuffer("group: "); - AbstractXMLWritingIFPainter.toString(getTransforms(), sb); + IFUtil.toString(getTransforms(), sb); return sb.toString(); } @@ -149,7 +149,7 @@ public class IFGraphicContext extends GraphicContext { /** {@inheritDoc} */ public String toString() { StringBuffer sb = new StringBuffer("viewport: "); - AbstractXMLWritingIFPainter.toString(getTransforms(), sb); + IFUtil.toString(getTransforms(), sb); sb.append(", ").append(getSize()); if (getClipRect() != null) { sb.append(", ").append(getClipRect()); diff --git a/src/java/org/apache/fop/render/intermediate/IFPainter.java b/src/java/org/apache/fop/render/intermediate/IFPainter.java index b354510f8..2c704db8b 100644 --- a/src/java/org/apache/fop/render/intermediate/IFPainter.java +++ b/src/java/org/apache/fop/render/intermediate/IFPainter.java @@ -27,12 +27,8 @@ import java.awt.Rectangle; import java.awt.geom.AffineTransform; import java.util.Map; -import javax.xml.transform.Result; - import org.w3c.dom.Document; -import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.fonts.FontInfo; import org.apache.fop.traits.BorderProps; import org.apache.fop.traits.RuleStyle; @@ -86,155 +82,6 @@ import org.apache.fop.traits.RuleStyle; */ public interface IFPainter { - /** - * Set the user agent. - * @param userAgent The user agent - */ - void setUserAgent(FOUserAgent userAgent); - - /** - * Sets the JAXP Result object to receive the generated content. - * @param result the JAXP Result object to receive the generated content - * @throws IFException if an error occurs setting up the output - */ - void setResult(Result result) throws IFException; - - /** - * Sets the font set to work with. - * @param fontInfo the font info object - */ - void setFontInfo(FontInfo fontInfo); - - /** - * Sets the default font set (with no custom configuration). - */ - void setDefaultFontInfo(); - - /** - * Indicates whether the painter supports to handle the pages in mixed order rather than - * ascending order. - * @return true if out-of-order handling is supported - */ - boolean supportsPagesOutOfOrder(); - - /** - * Returns the MIME type of the output format that is generated by this implementation. - * @return the MIME type - */ - String getMimeType(); - - /** - * Indicates the start of a document. This method may only be called once before any other - * event method. - * @throws IFException if an error occurs while handling this event - */ - void startDocument() throws IFException; - - /** - * Indicates the end of a document. This method may only be called once after the whole - * document has been handled. Implementations can release resources (close streams). It is - * an error to call any event method after this method. - * @throws IFException if an error occurs while handling this event - */ - void endDocument() throws IFException; - - /** - * Indicates the start of the document header. This method is called right after the - * {@code #startDocument()} method. Extensions sent to this painter between - * {@code #startDocumentHeader()} and {@code #endDocumentHeader()} apply to the document as - * a whole (like document metadata). - * @throws IFException if an error occurs while handling this event - */ - void startDocumentHeader() throws IFException; - - /** - * Indicates the end of the document header. This method is called before the first - * page sequence. - * @throws IFException if an error occurs while handling this event - */ - void endDocumentHeader() throws IFException; - - /** - * Indicates the start of the document trailer. This method is called after the last - * page sequence. Extensions sent to the painter between - * {@code #startDocumentTrailer()} and {@code #endDocumentTrailer()} apply to the document as - * a whole and is used for document-level content that is only known after all pages have - * been rendered (like named destinations or the bookmark tree). - * @throws IFException if an error occurs while handling this event - */ - void startDocumentTrailer() throws IFException; - - /** - * Indicates the end of the document trailer. This method is called right before the - * {@code #endDocument()} method. - * @throws IFException if an error occurs while handling this event - */ - void endDocumentTrailer() throws IFException; - - /** - * Indicates the start of a new page sequence. - * @param id the page sequence's identifier (or null if none is available) - * @throws IFException if an error occurs while handling this event - */ - void startPageSequence(String id) throws IFException; - /** - * Indicates the end of a page sequence. - * @throws IFException if an error occurs while handling this event - */ - void endPageSequence() throws IFException; - - /** - * Indicates the start of a new page. - * @param index the index of the page (0-based) - * @param name the page name (usually the formatted page number) - * @param size the size of the page (equivalent to the MediaBox in PDF) - * @throws IFException if an error occurs while handling this event - */ - void startPage(int index, String name, Dimension size) throws IFException; - - /** - * Indicates the end of a page - * @throws IFException if an error occurs while handling this event - */ - void endPage() throws IFException; - - /** - * Indicates the start of the page header. - * @throws IFException if an error occurs while handling this event - */ - void startPageHeader() throws IFException; - - /** - * Indicates the end of the page header. - * @throws IFException if an error occurs while handling this event - */ - void endPageHeader() throws IFException; - - /** - * Indicates the start of the page content. - * @throws IFException if an error occurs while handling this event - */ - void startPageContent() throws IFException; - - /** - * Indicates the end of the page content. - * @throws IFException if an error occurs while handling this event - */ - void endPageContent() throws IFException; - - /** - * Indicates the start of the page trailer. The page trailer is used for writing down page - * elements which are only know after handling the page itself (like PDF targets). - * @throws IFException if an error occurs while handling this event - */ - void startPageTrailer() throws IFException; - - /** - * Indicates the end of the page trailer. - * @throws IFException if an error occurs while handling this event - */ - void endPageTrailer() throws IFException; - void startViewport(AffineTransform transform, Dimension size, Rectangle clipRect) throws IFException; void startViewport(AffineTransform[] transforms, Dimension size, Rectangle clipRect) throws IFException; //For transform, Batik's org.apache.batik.parser.TransformListHandler/Parser can be used @@ -340,15 +187,4 @@ public interface IFPainter { //etc. etc. - /** - * Handles an extension object. This can be a DOM document or any arbitrary - * object. If an implementation doesn't know how to handle a particular extension it is simply - * ignored. - * @param extension the extension object - * @throws IFException if an error occurs while handling this event - */ - void handleExtensionObject(Object extension) throws IFException; - - //TODO Prototype the following: - //ContentHandler handleExtension() throws Exception } diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java index cc125a6f7..5eaef13ae 100644 --- a/src/java/org/apache/fop/render/intermediate/IFParser.java +++ b/src/java/org/apache/fop/render/intermediate/IFParser.java @@ -74,16 +74,16 @@ public class IFParser implements IFConstants { /** * Parses an intermediate file and paints it. * @param src the Source instance pointing to the intermediate file - * @param painter the intermediate format painter used to process the IF events + * @param documentHandler the intermediate format document handler used to process the IF events * @param userAgent the user agent * @throws TransformerException if an error occurs while parsing the area tree XML */ - public void parse(Source src, IFPainter painter, FOUserAgent userAgent) + public void parse(Source src, IFDocumentHandler documentHandler, FOUserAgent userAgent) throws TransformerException { Transformer transformer = tFactory.newTransformer(); transformer.setErrorListener(new DefaultErrorListener(log)); - SAXResult res = new SAXResult(getContentHandler(painter, userAgent)); + SAXResult res = new SAXResult(getContentHandler(documentHandler, userAgent)); transformer.transform(src, res); } @@ -91,20 +91,22 @@ public class IFParser implements IFConstants { /** * Creates a new ContentHandler instance that you can send the area tree XML to. The parsed * pages are added to the AreaTreeModel instance you pass in as a parameter. - * @param painter the intermediate format painter used to process the IF events + * @param documentHandler the intermediate format document handler used to process the IF events * @param userAgent the user agent * @return the ContentHandler instance to receive the SAX stream from the area tree XML */ - public ContentHandler getContentHandler(IFPainter painter, FOUserAgent userAgent) { + public ContentHandler getContentHandler(IFDocumentHandler documentHandler, + FOUserAgent userAgent) { ElementMappingRegistry elementMappingRegistry = userAgent.getFactory().getElementMappingRegistry(); - return new Handler(painter, userAgent, elementMappingRegistry); + return new Handler(documentHandler, userAgent, elementMappingRegistry); } private static class Handler extends DefaultHandler { private Map elementHandlers = new java.util.HashMap(); + private IFDocumentHandler documentHandler; private IFPainter painter; private FOUserAgent userAgent; private ElementMappingRegistry elementMappingRegistry; @@ -120,9 +122,9 @@ public class IFParser implements IFConstants { private boolean inForeignObject; private Document foreignObject; - public Handler(IFPainter painter, FOUserAgent userAgent, + public Handler(IFDocumentHandler documentHandler, FOUserAgent userAgent, ElementMappingRegistry elementMappingRegistry) { - this.painter = painter; + this.documentHandler = documentHandler; this.userAgent = userAgent; this.elementMappingRegistry = elementMappingRegistry; elementHandlers.put(EL_DOCUMENT, new DocumentHandler()); @@ -279,11 +281,11 @@ public class IFParser implements IFConstants { private class DocumentHandler extends AbstractElementHandler { public void startElement(Attributes attributes) throws IFException { - painter.startDocument(); + documentHandler.startDocument(); } public void endElement() throws IFException { - painter.endDocument(); + documentHandler.endDocument(); } } @@ -291,11 +293,11 @@ public class IFParser implements IFConstants { private class DocumentHeaderHandler extends AbstractElementHandler { public void startElement(Attributes attributes) throws IFException { - painter.startDocumentHeader(); + documentHandler.startDocumentHeader(); } public void endElement() throws IFException { - painter.endDocumentHeader(); + documentHandler.endDocumentHeader(); } } @@ -303,11 +305,11 @@ public class IFParser implements IFConstants { private class DocumentTrailerHandler extends AbstractElementHandler { public void startElement(Attributes attributes) throws IFException { - painter.startDocumentTrailer(); + documentHandler.startDocumentTrailer(); } public void endElement() throws IFException { - painter.endDocumentTrailer(); + documentHandler.endDocumentTrailer(); } } @@ -316,11 +318,11 @@ public class IFParser implements IFConstants { public void startElement(Attributes attributes) throws IFException { String id = attributes.getValue("id"); - painter.startPageSequence(id); + documentHandler.startPageSequence(id); } public void endElement() throws IFException { - painter.endPageSequence(); + documentHandler.endPageSequence(); } } @@ -332,11 +334,11 @@ public class IFParser implements IFConstants { String name = attributes.getValue("name"); int width = Integer.parseInt(attributes.getValue("width")); int height = Integer.parseInt(attributes.getValue("height")); - painter.startPage(index, name, new Dimension(width, height)); + documentHandler.startPage(index, name, new Dimension(width, height)); } public void endElement() throws IFException { - painter.endPage(); + documentHandler.endPage(); } } @@ -344,11 +346,11 @@ public class IFParser implements IFConstants { private class PageHeaderHandler extends AbstractElementHandler { public void startElement(Attributes attributes) throws IFException { - painter.startPageHeader(); + documentHandler.startPageHeader(); } public void endElement() throws IFException { - painter.endPageHeader(); + documentHandler.endPageHeader(); } } @@ -356,11 +358,12 @@ public class IFParser implements IFConstants { private class PageContentHandler extends AbstractElementHandler { public void startElement(Attributes attributes) throws IFException { - painter.startPageContent(); + painter = documentHandler.startPageContent(); } public void endElement() throws IFException { - painter.endPageContent(); + painter = null; + documentHandler.endPageContent(); } } @@ -368,11 +371,11 @@ public class IFParser implements IFConstants { private class PageTrailerHandler extends AbstractElementHandler { public void startElement(Attributes attributes) throws IFException { - painter.startPageTrailer(); + documentHandler.startPageTrailer(); } public void endElement() throws IFException { - painter.endPageTrailer(); + documentHandler.endPageTrailer(); } } @@ -553,14 +556,6 @@ public class IFParser implements IFConstants { // ==================================================================== - - private void assertObjectOfClass(Object obj, Class clazz) { - if (!clazz.isInstance(obj)) { - throw new IllegalStateException("Object is not an instance of " - + clazz.getName() + " but of " + obj.getClass().getName()); - } - } - /** * Handles objects created by "sub-parsers" that implement the ObjectSource interface. * An example of object handled here are ExtensionAttachments. @@ -569,7 +564,7 @@ public class IFParser implements IFConstants { */ protected void handleExternallyGeneratedObject(Object obj) throws SAXException { try { - painter.handleExtensionObject(obj); + documentHandler.handleExtensionObject(obj); } catch (IFException ife) { handleIFException(ife); } diff --git a/src/java/org/apache/fop/render/intermediate/IFRenderer.java b/src/java/org/apache/fop/render/intermediate/IFRenderer.java index 8831656e1..eddd5f1bd 100644 --- a/src/java/org/apache/fop/render/intermediate/IFRenderer.java +++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java @@ -107,6 +107,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { /** XML MIME type */ public static final String IF_MIME_TYPE = MimeConstants.MIME_FOP_IF; + private IFDocumentHandler documentHandler; private IFPainter painter; /** If not null, the XMLRenderer will mimic another renderer by using its font setup. */ @@ -157,30 +158,25 @@ public class IFRenderer extends AbstractPathOrientedRenderer { } /** - * Sets the {@code IFPainter} to be used by the {@code IFRenderer}. - * @param painter the {@code IFPainter} + * Sets the {@code IFDocumentHandler} to be used by the {@code IFRenderer}. + * @param documentHandler the {@code IFDocumentHandler} */ - public void setPainter(IFPainter painter) { - this.painter = painter; - } - - /** - * Call this method to make the XMLRenderer mimic a different renderer by using its font - * setup. This is useful when working with the intermediate format parser. - * @param renderer the renderer to mimic - */ - public void mimicRenderer(Renderer renderer) { - this.mimic = renderer; + public void setDocumentHandler(IFDocumentHandler documentHandler) { + this.documentHandler = documentHandler; } /** {@inheritDoc} */ - public void setupFontInfo(FontInfo inFontInfo) { - if (mimic != null) { - mimic.setupFontInfo(inFontInfo); - this.fontInfo = inFontInfo; + public void setupFontInfo(FontInfo inFontInfo) throws FOPException { + if (this.documentHandler == null) { + this.documentHandler = createDefaultDocumentHandler(); + } + IFDocumentHandlerConfigurator configurator = this.documentHandler.getConfigurator(); + if (configurator != null) { + configurator.setupFontInfo(documentHandler, inFontInfo); } else { - super.setupFontInfo(inFontInfo); + this.documentHandler.setDefaultFontInfo(inFontInfo); } + this.fontInfo = inFontInfo; } private void handleIFException(IFException ife) { @@ -200,11 +196,13 @@ public class IFRenderer extends AbstractPathOrientedRenderer { } /** - * Creates a default {@code IFPainter} when none has been set. - * @return the default IFPainter + * Creates a default {@code IFDocumentHandler} when none has been set. + * @return the default IFDocumentHandler */ - protected IFPainter createDefaultPainter() { - return new IFSerializer(); + protected IFDocumentHandler createDefaultDocumentHandler() { + IFSerializer serializer = new IFSerializer(); + serializer.setUserAgent(getUserAgent()); + return serializer; } /** {@inheritDoc} */ @@ -217,20 +215,18 @@ public class IFRenderer extends AbstractPathOrientedRenderer { result.setSystemId( getUserAgent().getOutputFile().toURI().toURL().toExternalForm()); } - if (this.painter == null) { - this.painter = new IFSerializer(); - this.painter.setUserAgent(getUserAgent()); + if (this.documentHandler == null) { + this.documentHandler = createDefaultDocumentHandler(); } - this.painter.setFontInfo(fontInfo); - this.painter.setResult(result); + this.documentHandler.setResult(result); } super.startRenderer(null); if (log.isDebugEnabled()) { - log.debug("Rendering areas via painter (" - + this.painter.getClass().getName() + ")..."); + log.debug("Rendering areas via IF document handler (" + + this.documentHandler.getClass().getName() + ")..."); } - painter.startDocument(); - painter.startDocumentHeader(); + documentHandler.startDocument(); + documentHandler.startDocumentHeader(); } catch (IFException e) { handleIFExceptionWithIOException(e); } @@ -240,16 +236,16 @@ public class IFRenderer extends AbstractPathOrientedRenderer { public void stopRenderer() throws IOException { try { if (this.inPageSequence) { - painter.endPageSequence(); + documentHandler.endPageSequence(); this.inPageSequence = false; } - painter.startDocumentTrailer(); + documentHandler.startDocumentTrailer(); finishOpenGoTos(); if (this.bookmarkTree != null) { - painter.handleExtensionObject(this.bookmarkTree); + documentHandler.handleExtensionObject(this.bookmarkTree); } - painter.endDocumentTrailer(); - painter.endDocument(); + documentHandler.endDocumentTrailer(); + documentHandler.endDocument(); } catch (IFException e) { handleIFExceptionWithIOException(e); } @@ -285,7 +281,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { GoToXYAction action = getGoToActionForID(targetID, pv.getPageIndex()); NamedDestination namedDestination = new NamedDestination(targetID, action); try { - painter.handleExtensionObject(namedDestination); + documentHandler.handleExtensionObject(namedDestination); } catch (IFException ife) { handleIFException(ife); } @@ -444,16 +440,16 @@ public class IFRenderer extends AbstractPathOrientedRenderer { public void startPageSequence(PageSequence pageSequence) { try { if (this.inPageSequence) { - painter.endPageSequence(); + documentHandler.endPageSequence(); } else { if (this.documentMetadata == null) { this.documentMetadata = createDefaultDocumentMetadata(); } - painter.handleExtensionObject(this.documentMetadata); - painter.endDocumentHeader(); + documentHandler.handleExtensionObject(this.documentMetadata); + documentHandler.endDocumentHeader(); this.inPageSequence = true; } - painter.startPageSequence(null); + documentHandler.startPageSequence(null); } catch (IFException e) { handleIFException(e); } @@ -496,17 +492,18 @@ public class IFRenderer extends AbstractPathOrientedRenderer { Dimension dim = new Dimension( (int)Math.ceil(viewArea.getWidth()), (int)Math.ceil(viewArea.getHeight())); - painter.startPage(page.getPageIndex(), page.getPageNumberString(), dim); - painter.startPageHeader(); + documentHandler.startPage(page.getPageIndex(), page.getPageNumberString(), dim); + documentHandler.startPageHeader(); //TODO Handle page header - painter.endPageHeader(); - painter.startPageContent(); + documentHandler.endPageHeader(); + this.painter = documentHandler.startPageContent(); super.renderPage(page); - painter.endPageContent(); - painter.startPageTrailer(); + this.painter = null; + documentHandler.endPageContent(); + documentHandler.startPageTrailer(); //TODO Handle page trailer - painter.endPageTrailer(); - painter.endPage(); + documentHandler.endPageTrailer(); + documentHandler.endPage(); } catch (IFException e) { handleIFException(e); } diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java index 20db35c6a..95d1f20fe 100644 --- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java +++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java @@ -36,6 +36,7 @@ import org.xml.sax.helpers.AttributesImpl; import org.apache.xmlgraphics.util.QName; import org.apache.xmlgraphics.util.XMLizable; +import org.apache.fop.fonts.FontInfo; import org.apache.fop.render.RenderingContext; import org.apache.fop.traits.BorderProps; import org.apache.fop.traits.RuleStyle; @@ -46,7 +47,9 @@ import org.apache.fop.util.XMLUtil; /** * IFPainter implementation that serializes the intermediate format to XML. */ -public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConstants { +public class IFSerializer extends AbstractXMLWritingIFDocumentHandler implements IFConstants, IFPainter { + + private IFDocumentHandler mimicHandler; /** * Default constructor. @@ -72,12 +75,48 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst } /** {@inheritDoc} */ + public IFDocumentHandlerConfigurator getConfigurator() { + if (this.mimicHandler != null) { + return getMimickedDocumentHandler().getConfigurator(); + } else { + return new IFSerializerConfiguration(getUserAgent()); + } + } + + public void mimicDocumentHandler(IFDocumentHandler targetHandler) { + this.mimicHandler = targetHandler; + } + + public IFDocumentHandler getMimickedDocumentHandler() { + return this.mimicHandler; + } + + /** {@inheritDoc} */ + public FontInfo getFontInfo() { + if (this.mimicHandler != null) { + return this.mimicHandler.getFontInfo(); + } else { + return null; + } + } + + /** {@inheritDoc} */ + public void setFontInfo(FontInfo fontInfo) { + //nop, not used + } + + /** {@inheritDoc} */ + public void setDefaultFontInfo(FontInfo fontInfo) { + //nop, not used + } + + /** {@inheritDoc} */ public void startDocument() throws IFException { try { handler.startDocument(); handler.startPrefixMapping("", NAMESPACE); handler.startPrefixMapping(XLINK_PREFIX, XLINK_NAMESPACE); - startElement(EL_DOCUMENT); + handler.startElement(EL_DOCUMENT); } catch (SAXException e) { throw new IFException("SAX error in startDocument()", e); } @@ -86,7 +125,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst /** {@inheritDoc} */ public void startDocumentHeader() throws IFException { try { - startElement(EL_HEADER); + handler.startElement(EL_HEADER); } catch (SAXException e) { throw new IFException("SAX error in startDocumentHeader()", e); } @@ -95,7 +134,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst /** {@inheritDoc} */ public void endDocumentHeader() throws IFException { try { - endElement(EL_HEADER); + handler.endElement(EL_HEADER); } catch (SAXException e) { throw new IFException("SAX error in startDocumentHeader()", e); } @@ -104,7 +143,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst /** {@inheritDoc} */ public void startDocumentTrailer() throws IFException { try { - startElement(EL_TRAILER); + handler.startElement(EL_TRAILER); } catch (SAXException e) { throw new IFException("SAX error in startDocumentTrailer()", e); } @@ -113,16 +152,16 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst /** {@inheritDoc} */ public void endDocumentTrailer() throws IFException { try { - endElement(EL_TRAILER); + handler.endElement(EL_TRAILER); } catch (SAXException e) { - throw new IFException("SAX error in startDocumentTrailer()", e); + throw new IFException("SAX error in endDocumentTrailer()", e); } } /** {@inheritDoc} */ public void endDocument() throws IFException { try { - endElement(EL_DOCUMENT); + handler.endElement(EL_DOCUMENT); handler.endDocument(); } catch (SAXException e) { throw new IFException("SAX error in endDocument()", e); @@ -136,7 +175,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst if (id != null) { atts.addAttribute(XML_NAMESPACE, "id", "xml:id", XMLUtil.CDATA, id); } - startElement(EL_PAGE_SEQUENCE, atts); + handler.startElement(EL_PAGE_SEQUENCE, atts); } catch (SAXException e) { throw new IFException("SAX error in startPageSequence()", e); } @@ -145,7 +184,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst /** {@inheritDoc} */ public void endPageSequence() throws IFException { try { - endElement(EL_PAGE_SEQUENCE); + handler.endElement(EL_PAGE_SEQUENCE); } catch (SAXException e) { throw new IFException("SAX error in endPageSequence()", e); } @@ -159,7 +198,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst addAttribute(atts, "name", name); addAttribute(atts, "width", Integer.toString(size.width)); addAttribute(atts, "height", Integer.toString(size.height)); - startElement(EL_PAGE, atts); + handler.startElement(EL_PAGE, atts); } catch (SAXException e) { throw new IFException("SAX error in startPage()", e); } @@ -168,7 +207,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst /** {@inheritDoc} */ public void startPageHeader() throws IFException { try { - startElement(EL_PAGE_HEADER); + handler.startElement(EL_PAGE_HEADER); } catch (SAXException e) { throw new IFException("SAX error in startPageHeader()", e); } @@ -177,16 +216,17 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst /** {@inheritDoc} */ public void endPageHeader() throws IFException { try { - endElement(EL_PAGE_HEADER); + handler.endElement(EL_PAGE_HEADER); } catch (SAXException e) { throw new IFException("SAX error in endPageHeader()", e); } } /** {@inheritDoc} */ - public void startPageContent() throws IFException { + public IFPainter startPageContent() throws IFException { try { - startElement(EL_PAGE_CONTENT); + handler.startElement(EL_PAGE_CONTENT); + return this; } catch (SAXException e) { throw new IFException("SAX error in startPageContent()", e); } @@ -195,7 +235,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst /** {@inheritDoc} */ public void endPageContent() throws IFException { try { - endElement(EL_PAGE_CONTENT); + handler.endElement(EL_PAGE_CONTENT); } catch (SAXException e) { throw new IFException("SAX error in endPageContent()", e); } @@ -204,7 +244,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst /** {@inheritDoc} */ public void startPageTrailer() throws IFException { try { - startElement(EL_PAGE_TRAILER); + handler.startElement(EL_PAGE_TRAILER); } catch (SAXException e) { throw new IFException("SAX error in startPageTrailer()", e); } @@ -213,7 +253,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst /** {@inheritDoc} */ public void endPageTrailer() throws IFException { try { - endElement(EL_PAGE_TRAILER); + handler.endElement(EL_PAGE_TRAILER); } catch (SAXException e) { throw new IFException("SAX error in endPageTrailer()", e); } @@ -222,22 +262,24 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst /** {@inheritDoc} */ public void endPage() throws IFException { try { - endElement(EL_PAGE); + handler.endElement(EL_PAGE); } catch (SAXException e) { throw new IFException("SAX error in endPage()", e); } } + //---=== IFPainter ===--- + /** {@inheritDoc} */ public void startViewport(AffineTransform transform, Dimension size, Rectangle clipRect) throws IFException { - startViewport(toString(transform), size, clipRect); + startViewport(IFUtil.toString(transform), size, clipRect); } /** {@inheritDoc} */ public void startViewport(AffineTransform[] transforms, Dimension size, Rectangle clipRect) throws IFException { - startViewport(toString(transforms), size, clipRect); + startViewport(IFUtil.toString(transforms), size, clipRect); } private void startViewport(String transform, Dimension size, Rectangle clipRect) @@ -250,9 +292,9 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst addAttribute(atts, "width", Integer.toString(size.width)); addAttribute(atts, "height", Integer.toString(size.height)); if (clipRect != null) { - addAttribute(atts, "clip-rect", toString(clipRect)); + addAttribute(atts, "clip-rect", IFUtil.toString(clipRect)); } - startElement(EL_VIEWPORT, atts); + handler.startElement(EL_VIEWPORT, atts); } catch (SAXException e) { throw new IFException("SAX error in startViewport()", e); } @@ -261,7 +303,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst /** {@inheritDoc} */ public void endViewport() throws IFException { try { - endElement(EL_VIEWPORT); + handler.endElement(EL_VIEWPORT); } catch (SAXException e) { throw new IFException("SAX error in endViewport()", e); } @@ -269,12 +311,12 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst /** {@inheritDoc} */ public void startGroup(AffineTransform[] transforms) throws IFException { - startGroup(toString(transforms)); + startGroup(IFUtil.toString(transforms)); } /** {@inheritDoc} */ public void startGroup(AffineTransform transform) throws IFException { - startGroup(toString(transform)); + startGroup(IFUtil.toString(transform)); } private void startGroup(String transform) throws IFException { @@ -283,7 +325,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst if (transform != null && transform.length() > 0) { addAttribute(atts, "transform", transform); } - startElement(EL_GROUP, atts); + handler.startElement(EL_GROUP, atts); } catch (SAXException e) { throw new IFException("SAX error in startGroup()", e); } @@ -292,7 +334,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst /** {@inheritDoc} */ public void endGroup() throws IFException { try { - endElement(EL_GROUP); + handler.endElement(EL_GROUP); } catch (SAXException e) { throw new IFException("SAX error in endGroup()", e); } @@ -314,7 +356,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst addAttribute(atts, (QName)entry.getKey(), entry.getValue().toString()); } } - element(EL_IMAGE, atts); + handler.element(EL_IMAGE, atts); } catch (SAXException e) { throw new IFException("SAX error in startGroup()", e); } @@ -335,9 +377,9 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst addAttribute(atts, (QName)entry.getKey(), entry.getValue().toString()); } } - startElement(EL_IMAGE, atts); + handler.startElement(EL_IMAGE, atts); new DOM2SAX(handler).writeDocument(doc, true); - endElement(EL_IMAGE); + handler.endElement(EL_IMAGE); } catch (SAXException e) { throw new IFException("SAX error in startGroup()", e); } @@ -359,7 +401,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst addAttribute(atts, "y", Integer.toString(rect.y)); addAttribute(atts, "width", Integer.toString(rect.width)); addAttribute(atts, "height", Integer.toString(rect.height)); - element(EL_CLIP_RECT, atts); + handler.element(EL_CLIP_RECT, atts); } catch (SAXException e) { throw new IFException("SAX error in clipRect()", e); } @@ -377,7 +419,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst addAttribute(atts, "width", Integer.toString(rect.width)); addAttribute(atts, "height", Integer.toString(rect.height)); addAttribute(atts, "fill", toString(fill)); - element(EL_RECT, atts); + handler.element(EL_RECT, atts); } catch (SAXException e) { throw new IFException("SAX error in fillRect()", e); } @@ -407,7 +449,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst if (end != null) { addAttribute(atts, "end", end.toString()); } - element(EL_BORDER_RECT, atts); + handler.element(EL_BORDER_RECT, atts); } catch (SAXException e) { throw new IFException("SAX error in drawBorderRect()", e); } @@ -425,7 +467,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst addAttribute(atts, "stroke-width", Integer.toString(width)); addAttribute(atts, "color", Integer.toString(width)); addAttribute(atts, "style", style.getName()); - element(EL_LINE, atts); + handler.element(EL_LINE, atts); } catch (SAXException e) { throw new IFException("SAX error in drawLine()", e); } @@ -438,15 +480,15 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst addAttribute(atts, "x", Integer.toString(x)); addAttribute(atts, "y", Integer.toString(y)); if (dx != null) { - addAttribute(atts, "dx", toString(dx)); + addAttribute(atts, "dx", IFUtil.toString(dx)); } if (dy != null) { - addAttribute(atts, "dy", toString(dy)); + addAttribute(atts, "dy", IFUtil.toString(dy)); } - startElement(EL_TEXT, atts); + handler.startElement(EL_TEXT, atts); char[] chars = text.toCharArray(); handler.characters(chars, 0, chars.length); - endElement(EL_TEXT); + handler.endElement(EL_TEXT); } catch (SAXException e) { throw new IFException("SAX error in setFont()", e); } @@ -475,7 +517,7 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst if (color != null) { addAttribute(atts, "color", toString(color)); } - element(EL_FONT, atts); + handler.element(EL_FONT, atts); } catch (SAXException e) { throw new IFException("SAX error in setFont()", e); } @@ -501,4 +543,13 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst throw new IllegalStateException("Should never be called!"); } + private void addAttribute(AttributesImpl atts, + org.apache.xmlgraphics.util.QName attribute, String value) { + XMLUtil.addAttribute(atts, attribute, value); + } + + private void addAttribute(AttributesImpl atts, String localName, String value) { + XMLUtil.addAttribute(atts, localName, value); + } + } diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializerConfiguration.java b/src/java/org/apache/fop/render/intermediate/IFSerializerConfiguration.java new file mode 100644 index 000000000..8f47c5511 --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/IFSerializerConfiguration.java @@ -0,0 +1,80 @@ +/* + * 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 java.util.List; + +import org.apache.avalon.framework.configuration.Configuration; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.fonts.CustomFontCollection; +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.fonts.base14.Base14FontCollection; +import org.apache.fop.render.DefaultFontResolver; +import org.apache.fop.render.PrintRendererConfigurator; + +/** + * Configurator for the IFSerializer. + */ +public class IFSerializerConfiguration extends PrintRendererConfigurator + implements IFDocumentHandlerConfigurator { + + /** + * Default constructor + * @param userAgent user agent + */ + public IFSerializerConfiguration(FOUserAgent userAgent) { + super(userAgent); + } + + /** {@inheritDoc} */ + public void configure(IFDocumentHandler documentHandler) throws FOPException { + //nothing to do here + } + + /** {@inheritDoc} */ + public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo) + throws FOPException { + FontManager fontManager = userAgent.getFactory().getFontManager(); + List fontCollections = new java.util.ArrayList(); + 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 fontList = buildFontList(cfg, fontResolver, listener); + fontCollections.add(new CustomFontCollection(fontResolver, fontList)); + } + + fontManager.setup(fontInfo, + (FontCollection[])fontCollections.toArray( + new FontCollection[fontCollections.size()])); + documentHandler.setFontInfo(fontInfo); + } + +} diff --git a/src/java/org/apache/fop/render/intermediate/IFUtil.java b/src/java/org/apache/fop/render/intermediate/IFUtil.java new file mode 100644 index 000000000..513e1c786 --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/IFUtil.java @@ -0,0 +1,140 @@ +/* + * 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 java.awt.Rectangle; +import java.awt.geom.AffineTransform; + +import org.apache.fop.util.DecimalFormatCache; + +/** + * Utility functions for the intermediate format. + */ +public class IFUtil { + + private static String format(double value) { + if (value == -0.0) { + //Don't allow negative zero because of testing + //See http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2.3 + value = 0.0; + } + return DecimalFormatCache.getDecimalFormat(6).format(value); + } + + /** + * Converts an {@code AffineTransform} instance to an SVG style transform method. + * @param transform the transformation matrix + * @param sb the StringBuffer to write the transform method to + * @return the StringBuffer passed to this method + */ + public static StringBuffer toString(AffineTransform transform, StringBuffer sb) { + if (transform.isIdentity()) { + return sb; + } + double[] matrix = new double[6]; + transform.getMatrix(matrix); + if (matrix[0] == 1 && matrix[3] == 1 && matrix[1] == 0 && matrix[2] == 0) { + sb.append("translate("); + sb.append(format(matrix[4])); + if (matrix[5] != 0) { + sb.append(',').append(format(matrix[5])); + } + } else { + sb.append("matrix("); + for (int i = 0; i < 6; i++) { + if (i > 0) { + sb.append(','); + } + sb.append(format(matrix[i])); + } + } + sb.append(')'); + return sb; + } + + /** + * Converts an {@code AffineTransform} array to an SVG style transform method sequence. + * @param transforms the transformation matrix array + * @param sb the StringBuffer to write the transform method sequence to + * @return the StringBuffer passed to this method + */ + public static StringBuffer toString(AffineTransform[] transforms, StringBuffer sb) { + for (int i = 0, c = transforms.length; i < c; i++) { + if (i > 0) { + sb.append(' '); + } + toString(transforms[i], sb); + } + return sb; + } + + /** + * Converts an {@code AffineTransform} array to an SVG style transform method sequence. + * @param transforms the transformation matrix array + * @return the formatted array + */ + public static String toString(AffineTransform[] transforms) { + return toString(transforms, new StringBuffer()).toString(); + } + + /** + * Converts an {@code AffineTransform} instance to an SVG style transform method. + * @param transform the transformation matrix + * @return the formatted array + */ + public static String toString(AffineTransform transform) { + return toString(transform, new StringBuffer()).toString(); + } + + /** + * Converts an array of integer coordinates into a space-separated string. + * @param coordinates the coordinates + * @return the space-separated array of coordinates + */ + public static String toString(int[] coordinates) { + if (coordinates == null) { + return ""; + } + StringBuffer sb = new StringBuffer(); + for (int i = 0, c = coordinates.length; i < c; i++) { + if (i > 0) { + sb.append(' '); + } + sb.append(Integer.toString(coordinates[i])); + } + return sb.toString(); + } + + /** + * Converts a rectangle into a space-separated string. + * @param rect the rectangle + * @return the space-separated array of coordinates + */ + public static String toString(Rectangle rect) { + if (rect == null) { + return ""; + } + StringBuffer sb = new StringBuffer(); + sb.append(rect.x).append(' ').append(rect.y).append(' '); + sb.append(rect.width).append(' ').append(rect.height); + return sb.toString(); + } + +} diff --git a/src/java/org/apache/fop/render/java2d/Java2DBorderPainter.java b/src/java/org/apache/fop/render/java2d/Java2DBorderPainter.java new file mode 100644 index 000000000..cd0cec0f8 --- /dev/null +++ b/src/java/org/apache/fop/render/java2d/Java2DBorderPainter.java @@ -0,0 +1,313 @@ +/* + * 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.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.geom.GeneralPath; +import java.awt.geom.Line2D; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.fop.fo.Constants; +import org.apache.fop.render.intermediate.BorderPainter; +import org.apache.fop.traits.RuleStyle; +import org.apache.fop.util.ColorUtil; + +/** + * Java2D-specific implementation of the {@code BorderPainter}. + */ +public class Java2DBorderPainter extends BorderPainter { + + /** logging instance */ + private static Log log = LogFactory.getLog(Java2DBorderPainter.class); + + private Java2DPainter painter; + + private GeneralPath currentPath = null; + + public Java2DBorderPainter(Java2DPainter painter) { + this.painter = painter; + } + + private Java2DGraphicsState getG2DState() { + return this.painter.g2dState; + } + + private Graphics2D getG2D() { + return getG2DState().getGraph(); + } + + /** {@inheritDoc} */ + protected void drawBorderLine(int x1, int y1, int x2, int y2, boolean horz, + boolean startOrBefore, int style, Color color) { + float w = x2 - x1; + float h = y2 - y1; + if ((w < 0) || (h < 0)) { + log.error("Negative extent received. Border won't be painted."); + return; + } + switch (style) { + case Constants.EN_DASHED: + getG2D().setColor(color); + if (horz) { + float unit = Math.abs(2 * h); + int rep = (int)(w / unit); + if (rep % 2 == 0) { + rep++; + } + unit = w / rep; + float ym = y1 + (h / 2); + BasicStroke s = new BasicStroke(h, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER, 10.0f, new float[] {unit}, 0); + getG2D().setStroke(s); + getG2D().draw(new Line2D.Float(x1, ym, x2, ym)); + } else { + float unit = Math.abs(2 * w); + int rep = (int)(h / unit); + if (rep % 2 == 0) { + rep++; + } + unit = h / rep; + float xm = x1 + (w / 2); + BasicStroke s = new BasicStroke(w, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER, 10.0f, new float[] {unit}, 0); + getG2D().setStroke(s); + getG2D().draw(new Line2D.Float(xm, y1, xm, y2)); + } + break; + case Constants.EN_DOTTED: + getG2D().setColor(color); + if (horz) { + float unit = Math.abs(2 * h); + int rep = (int)(w / unit); + if (rep % 2 == 0) { + rep++; + } + unit = w / rep; + float ym = y1 + (h / 2); + BasicStroke s = new BasicStroke(h, BasicStroke.CAP_ROUND, + BasicStroke.JOIN_MITER, 10.0f, new float[] {0, unit}, 0); + getG2D().setStroke(s); + getG2D().draw(new Line2D.Float(x1, ym, x2, ym)); + } else { + float unit = Math.abs(2 * w); + int rep = (int)(h / unit); + if (rep % 2 == 0) { + rep++; + } + unit = h / rep; + float xm = x1 + (w / 2); + BasicStroke s = new BasicStroke(w, BasicStroke.CAP_ROUND, + BasicStroke.JOIN_MITER, 10.0f, new float[] {0, unit}, 0); + getG2D().setStroke(s); + getG2D().draw(new Line2D.Float(xm, y1, xm, y2)); + } + break; + case Constants.EN_DOUBLE: + getG2D().setColor(color); + if (horz) { + float h3 = h / 3; + float ym1 = y1 + (h3 / 2); + float ym2 = ym1 + h3 + h3; + BasicStroke s = new BasicStroke(h3); + getG2D().setStroke(s); + getG2D().draw(new Line2D.Float(x1, ym1, x2, ym1)); + getG2D().draw(new Line2D.Float(x1, ym2, x2, ym2)); + } else { + float w3 = w / 3; + float xm1 = x1 + (w3 / 2); + float xm2 = xm1 + w3 + w3; + BasicStroke s = new BasicStroke(w3); + getG2D().setStroke(s); + getG2D().draw(new Line2D.Float(xm1, y1, xm1, y2)); + getG2D().draw(new Line2D.Float(xm2, y1, xm2, y2)); + } + break; + case Constants.EN_GROOVE: + case Constants.EN_RIDGE: + float colFactor = (style == Constants.EN_GROOVE ? 0.4f : -0.4f); + if (horz) { + Color uppercol = ColorUtil.lightenColor(color, -colFactor); + Color lowercol = ColorUtil.lightenColor(color, colFactor); + float h3 = h / 3; + float ym1 = y1 + (h3 / 2); + getG2D().setStroke(new BasicStroke(h3)); + getG2D().setColor(uppercol); + getG2D().draw(new Line2D.Float(x1, ym1, x2, ym1)); + getG2D().setColor(color); + getG2D().draw(new Line2D.Float(x1, ym1 + h3, x2, ym1 + h3)); + getG2D().setColor(lowercol); + getG2D().draw(new Line2D.Float(x1, ym1 + h3 + h3, x2, ym1 + h3 + h3)); + } else { + Color leftcol = ColorUtil.lightenColor(color, -colFactor); + Color rightcol = ColorUtil.lightenColor(color, colFactor); + float w3 = w / 3; + float xm1 = x1 + (w3 / 2); + getG2D().setStroke(new BasicStroke(w3)); + getG2D().setColor(leftcol); + getG2D().draw(new Line2D.Float(xm1, y1, xm1, y2)); + getG2D().setColor(color); + getG2D().draw(new Line2D.Float(xm1 + w3, y1, xm1 + w3, y2)); + getG2D().setColor(rightcol); + getG2D().draw(new Line2D.Float(xm1 + w3 + w3, y1, xm1 + w3 + w3, y2)); + } + break; + case Constants.EN_INSET: + case Constants.EN_OUTSET: + colFactor = (style == Constants.EN_OUTSET ? 0.4f : -0.4f); + if (horz) { + color = ColorUtil.lightenColor(color, (startOrBefore ? 1 : -1) * colFactor); + getG2D().setStroke(new BasicStroke(h)); + float ym1 = y1 + (h / 2); + getG2D().setColor(color); + getG2D().draw(new Line2D.Float(x1, ym1, x2, ym1)); + } else { + color = ColorUtil.lightenColor(color, (startOrBefore ? 1 : -1) * colFactor); + float xm1 = x1 + (w / 2); + getG2D().setStroke(new BasicStroke(w)); + getG2D().setColor(color); + getG2D().draw(new Line2D.Float(xm1, y1, xm1, y2)); + } + break; + case Constants.EN_HIDDEN: + break; + default: + getG2D().setColor(color); + if (horz) { + float ym = y1 + (h / 2); + getG2D().setStroke(new BasicStroke(h)); + getG2D().draw(new Line2D.Float(x1, ym, x2, ym)); + } else { + float xm = x1 + (w / 2); + getG2D().setStroke(new BasicStroke(w)); + getG2D().draw(new Line2D.Float(xm, y1, xm, y2)); + } + } + } + + /** {@inheritDoc} */ + public void drawLine(Point start, Point end, int width, Color color, RuleStyle style) { + if (start.y != end.y) { + //TODO Support arbitrary lines if necessary + throw new UnsupportedOperationException( + "Can only deal with horizontal lines right now"); + } + + saveGraphicsState(); + int half = width / 2; + int starty = start.y - half; + Rectangle boundingRect = new Rectangle(start.x, start.y - half, end.x - start.x, width); + getG2DState().updateClip(boundingRect); + + switch (style.getEnumValue()) { + case Constants.EN_SOLID: + case Constants.EN_DASHED: + case Constants.EN_DOUBLE: + drawBorderLine(start.x, start.y - half, end.x, end.y + half, + true, true, style.getEnumValue(), color); + break; + case Constants.EN_DOTTED: + int shift = half; //This shifts the dots to the right by half a dot's width + drawBorderLine(start.x + shift, start.y - half, end.x + shift, end.y + half, + true, true, style.getEnumValue(), color); + break; + case Constants.EN_GROOVE: + case Constants.EN_RIDGE: + getG2DState().updateColor(ColorUtil.lightenColor(color, 0.6f)); + moveTo(start.x, starty); + lineTo(end.x, starty); + lineTo(end.x, starty + 2 * half); + lineTo(start.x, starty + 2 * half); + closePath(); + getG2D().fill(currentPath); + currentPath = null; + getG2DState().updateColor(color); + if (style.getEnumValue() == Constants.EN_GROOVE) { + moveTo(start.x, starty); + lineTo(end.x, starty); + lineTo(end.x, starty + half); + lineTo(start.x + half, starty + half); + lineTo(start.x, starty + 2 * half); + } else { + moveTo(end.x, starty); + lineTo(end.x, starty + 2 * half); + lineTo(start.x, starty + 2 * half); + lineTo(start.x, starty + half); + lineTo(end.x - half, starty + half); + } + closePath(); + getG2D().fill(currentPath); + currentPath = null; + + case Constants.EN_NONE: + // No rule is drawn + break; + default: + } // end switch + restoreGraphicsState(); + } + + /** {@inheritDoc} */ + protected void clip() { + if (currentPath == null) { + throw new IllegalStateException("No current path available!"); + } + getG2DState().updateClip(currentPath); + currentPath = null; + } + + /** {@inheritDoc} */ + protected void closePath() { + currentPath.closePath(); + } + + /** {@inheritDoc} */ + protected void lineTo(int x, int y) { + if (currentPath == null) { + currentPath = new GeneralPath(); + } + currentPath.lineTo(x, y); + } + + /** {@inheritDoc} */ + protected void moveTo(int x, int y) { + if (currentPath == null) { + currentPath = new GeneralPath(); + } + currentPath.moveTo(x, y); + } + + /** {@inheritDoc} */ + protected void saveGraphicsState() { + this.painter.saveGraphicsState(); + } + + /** {@inheritDoc} */ + protected void restoreGraphicsState() { + this.painter.restoreGraphicsState(); + this.currentPath = null; + } + +} diff --git a/src/java/org/apache/fop/render/java2d/Java2DFontMetrics.java b/src/java/org/apache/fop/render/java2d/Java2DFontMetrics.java index 10af3aa86..88ceb1270 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DFontMetrics.java +++ b/src/java/org/apache/fop/render/java2d/Java2DFontMetrics.java @@ -21,12 +21,14 @@ package org.apache.fop.render.java2d; // Java import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.geom.Rectangle2D; import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; import java.awt.font.LineMetrics; import java.awt.font.TextAttribute; import java.awt.font.TextLayout; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; import java.util.Map; /** @@ -110,6 +112,20 @@ public class Java2DFontMetrics { private Graphics2D graphics; /** + * Creates a Graphics2D object for the sole purpose of getting font metrics. + * @return a Graphics2D object + */ + public static Graphics2D createFontMetricsGraphics2D() { + BufferedImage fontImage = new BufferedImage(100, 100, + BufferedImage.TYPE_INT_RGB); + Graphics2D graphics2D = fontImage.createGraphics(); + //The next line is important to get accurate font metrics! + graphics2D.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_ON); + return graphics2D; + } + + /** * Constructs a new Font-metrics. * @param graphics a temp graphics object - this is needed so * that we can get an instance of java.awt.FontMetrics diff --git a/src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java b/src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java index 1c5fa8427..a40ee1d5c 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java +++ b/src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java @@ -222,7 +222,7 @@ public class Java2DGraphicsState { getGraph().setPaint(p); return true; } - } else if (p.equals(getGraph().getPaint())) { + } else if (!p.equals(getGraph().getPaint())) { getGraph().setPaint(p); return true; } @@ -252,10 +252,12 @@ public class Java2DGraphicsState { * according to the rule last-specified-first-applied. * @see java.awt.Graphics2D#transform(AffineTransform) * - * @param tf the transform to concatonate to the current level transform + * @param tf the transform to concatenate to the current level transform */ public void transform(AffineTransform tf) { - getGraph().transform(tf); + if (!tf.isIdentity()) { + getGraph().transform(tf); + } } /** @@ -270,7 +272,7 @@ public class Java2DGraphicsState { /** {@inheritDoc} */ public String toString() { - String s = "AWTGraphicsState " + currentGraphics.toString() + String s = "Java2DGraphicsState " + currentGraphics.toString() + ", Stroke (width: " + currentStrokeWidth + " style: " + currentStrokeStyle + "), " + getTransform(); return s; diff --git a/src/java/org/apache/fop/render/java2d/Java2DImageHandlerGraphics2D.java b/src/java/org/apache/fop/render/java2d/Java2DImageHandlerGraphics2D.java new file mode 100644 index 000000000..3fc1787f4 --- /dev/null +++ b/src/java/org/apache/fop/render/java2d/Java2DImageHandlerGraphics2D.java @@ -0,0 +1,85 @@ +/* + * 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.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; +import java.io.IOException; + +import org.apache.xmlgraphics.image.loader.Image; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; + +import org.apache.fop.render.ImageHandler; +import org.apache.fop.render.RenderingContext; + +/** + * Image handler implementation that paints {@code Graphics2D} image on another {@code Graphics2D} + * target. + */ +public class Java2DImageHandlerGraphics2D implements ImageHandler { + + /** {@inheritDoc} */ + public int getPriority() { + return 200; + } + + /** {@inheritDoc} */ + public Class getSupportedImageClass() { + return ImageGraphics2D.class; + } + + /** {@inheritDoc} */ + public ImageFlavor[] getSupportedImageFlavors() { + return new ImageFlavor[] { + ImageFlavor.GRAPHICS2D + }; + } + + /** {@inheritDoc} */ + public void handleImage(RenderingContext context, Image image, Rectangle pos) + throws IOException { + Java2DRenderingContext java2dContext = (Java2DRenderingContext)context; + ImageInfo info = image.getInfo(); + ImageGraphics2D imageG2D = (ImageGraphics2D)image; + + Dimension dim = info.getSize().getDimensionMpt(); + + Graphics2D g2d = (Graphics2D)java2dContext.getGraphics2D().create(); + g2d.translate(pos.x, pos.y); + double sx = pos.width / dim.getWidth(); + double sy = pos.height / dim.getHeight(); + g2d.scale(sx, sy); + + Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, dim.getWidth(), dim.getHeight()); + imageG2D.getGraphics2DImagePainter().paint(g2d, area); + g2d.dispose(); + } + + /** {@inheritDoc} */ + public boolean isCompatible(RenderingContext targetContext, Image image) { + return (image == null || image instanceof ImageGraphics2D) + && targetContext instanceof Java2DRenderingContext; + } + +} diff --git a/src/java/org/apache/fop/render/java2d/Java2DImageHandlerRenderedImage.java b/src/java/org/apache/fop/render/java2d/Java2DImageHandlerRenderedImage.java new file mode 100644 index 000000000..9c2d24c32 --- /dev/null +++ b/src/java/org/apache/fop/render/java2d/Java2DImageHandlerRenderedImage.java @@ -0,0 +1,122 @@ +/* + * 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.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.RenderedImage; +import java.awt.image.WritableRaster; +import java.io.IOException; + +import org.apache.xmlgraphics.image.loader.Image; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.impl.ImageRawStream; +import org.apache.xmlgraphics.image.loader.impl.ImageRendered; + +import org.apache.fop.render.ImageHandler; +import org.apache.fop.render.RenderingContext; + +/** + * Image handler implementation that paints {@code RenderedImage} instances on a {@code Graphics2D} + * object. + */ +public class Java2DImageHandlerRenderedImage implements ImageHandler { + + /** {@inheritDoc} */ + public int getPriority() { + return 300; + } + + /** {@inheritDoc} */ + public Class getSupportedImageClass() { + return ImageRawStream.class; + } + + /** {@inheritDoc} */ + public ImageFlavor[] getSupportedImageFlavors() { + return new ImageFlavor[] { + ImageFlavor.BUFFERED_IMAGE, + ImageFlavor.RENDERED_IMAGE, + }; + } + + /** {@inheritDoc} */ + public void handleImage(RenderingContext context, Image image, Rectangle pos) + throws IOException { + Java2DRenderingContext java2dContext = (Java2DRenderingContext)context; + ImageInfo info = image.getInfo(); + ImageRendered imageRend = (ImageRendered)image; + Graphics2D g2d = java2dContext.getGraphics2D(); + + AffineTransform at = new AffineTransform(); + at.translate(pos.x, pos.y); + //scaling based on layout instructions + double sx = pos.getWidth() / (double)info.getSize().getWidthMpt(); + double sy = pos.getHeight() / (double)info.getSize().getHeightMpt(); + + //scaling because of image resolution + //float sourceResolution = java2dContext.getUserAgent().getSourceResolution(); + //source resolution seems to be a bad idea, not sure why + float sourceResolution = 72; + sourceResolution *= 1000; //we're working in the millipoint area + sx *= sourceResolution / info.getSize().getDpiHorizontal(); + sy *= sourceResolution / info.getSize().getDpiVertical(); + at.scale(sx, sy); + RenderedImage rend = imageRend.getRenderedImage(); + if (imageRend.getTransparentColor() != null && !rend.getColorModel().hasAlpha()) { + int transCol = imageRend.getTransparentColor().getRGB(); + BufferedImage bufImage = makeTransparentImage(rend); + WritableRaster alphaRaster = bufImage.getAlphaRaster(); + //TODO Masked images: Does anyone know a more efficient method to do this? + final int[] transparent = new int[] {0x00}; + for (int y = 0, maxy = bufImage.getHeight(); y < maxy; y++) { + for (int x = 0, maxx = bufImage.getWidth(); x < maxx; x++) { + int col = bufImage.getRGB(x, y); + if (col == transCol) { + //Mask out all pixels that match the transparent color + alphaRaster.setPixel(x, y, transparent); + } + } + } + g2d.drawRenderedImage(bufImage, at); + } else { + g2d.drawRenderedImage(rend, at); + } + } + + private BufferedImage makeTransparentImage(RenderedImage src) { + BufferedImage bufImage = new BufferedImage(src.getWidth(), src.getHeight(), + BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = bufImage.createGraphics(); + g2d.drawRenderedImage(src, new AffineTransform()); + g2d.dispose(); + return bufImage; + } + + /** {@inheritDoc} */ + public boolean isCompatible(RenderingContext targetContext, Image image) { + return (image == null || image instanceof ImageRendered) + && targetContext instanceof Java2DRenderingContext; + } + +} diff --git a/src/java/org/apache/fop/render/java2d/Java2DPainter.java b/src/java/org/apache/fop/render/java2d/Java2DPainter.java new file mode 100644 index 000000000..9a68f62d0 --- /dev/null +++ b/src/java/org/apache/fop/render/java2d/Java2DPainter.java @@ -0,0 +1,271 @@ +/* + * 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.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.io.IOException; +import java.util.Map; +import java.util.Stack; + +import org.w3c.dom.Document; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.fonts.Font; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontTriplet; +import org.apache.fop.render.RenderingContext; +import org.apache.fop.render.intermediate.AbstractIFPainter; +import org.apache.fop.render.intermediate.IFException; +import org.apache.fop.render.intermediate.IFState; +import org.apache.fop.traits.BorderProps; +import org.apache.fop.traits.RuleStyle; + +/** + * {@code IFPainter} implementation that paints on a Graphics2D instance. + */ +public class Java2DPainter extends AbstractIFPainter { + + /** logging instance */ + private static Log log = LogFactory.getLog(Java2DPainter.class); + + /** the FO user agent */ + protected FOUserAgent userAgent; + + /** The font information */ + protected FontInfo fontInfo; + + /** Holds the intermediate format state */ + protected IFState state; + + private Java2DBorderPainter borderPainter; + + /** The current state, holds a Graphics2D and its context */ + protected Java2DGraphicsState g2dState; + private Stack g2dStateStack = new Stack(); + + /** + * Main constructor. + * @param g2d the target Graphics2D instance + * @param userAgent the user agent + * @param fontInfo the font information + */ + public Java2DPainter(Graphics2D g2d, FOUserAgent userAgent, FontInfo fontInfo) { + super(); + this.userAgent = userAgent; + this.state = IFState.create(); + this.fontInfo = fontInfo; + this.g2dState = new Java2DGraphicsState(g2d, fontInfo, g2d.getTransform()); + this.borderPainter = new Java2DBorderPainter(this); + } + + /** {@inheritDoc} */ + public FOUserAgent getUserAgent() { + return this.userAgent; + } + + /** + * Returns the associated {@code FontInfo} object. + * @return the font info + */ + protected FontInfo getFontInfo() { + return this.fontInfo; + } + + /** + * Returns the Java2D graphics state. + * @return the graphics state + */ + protected Java2DGraphicsState getState() { + return this.g2dState; + } + + //---------------------------------------------------------------------------------------------- + + + /** {@inheritDoc} */ + public void startViewport(AffineTransform transform, Dimension size, Rectangle clipRect) + throws IFException { + saveGraphicsState(); + try { + concatenateTransformationMatrix(transform); + //TODO CLIP! + } catch (IOException ioe) { + throw new IFException("I/O error in startViewport()", ioe); + } + } + + /** {@inheritDoc} */ + public void endViewport() throws IFException { + restoreGraphicsState(); + } + + /** {@inheritDoc} */ + public void startGroup(AffineTransform transform) throws IFException { + saveGraphicsState(); + try { + concatenateTransformationMatrix(transform); + } catch (IOException ioe) { + throw new IFException("I/O error in startGroup()", ioe); + } + } + + /** {@inheritDoc} */ + public void endGroup() throws IFException { + restoreGraphicsState(); + } + + /** {@inheritDoc} */ + public void drawImage(String uri, Rectangle rect, Map foreignAttributes) throws IFException { + drawImageUsingURI(uri, rect); + } + + /** {@inheritDoc} */ + protected RenderingContext createRenderingContext() { + Java2DRenderingContext java2dContext = new Java2DRenderingContext( + getUserAgent(), g2dState.getGraph(), getFontInfo()); + return java2dContext; + } + + /** {@inheritDoc} */ + public void drawImage(Document doc, Rectangle rect, Map foreignAttributes) throws IFException { + drawImageUsingDocument(doc, rect); + } + + /** {@inheritDoc} */ + public void clipRect(Rectangle rect) throws IFException { + } + + /** {@inheritDoc} */ + public void fillRect(Rectangle rect, Paint fill) throws IFException { + if (fill == null) { + return; + } + if (rect.width != 0 && rect.height != 0) { + g2dState.updatePaint(fill); + g2dState.getGraph().fill(rect); + } + } + + /** {@inheritDoc} */ + public void drawBorderRect(Rectangle rect, BorderProps before, BorderProps after, + BorderProps start, BorderProps end) throws IFException { + if (before != null || after != null || start != null || end != null) { + this.borderPainter.drawBorders(rect, before, after, start, end); + } + } + + /** {@inheritDoc} */ + public void drawLine(Point start, Point end, int width, Color color, RuleStyle style) + throws IFException { + this.borderPainter.drawLine(start, end, width, color, style); + } + + /** {@inheritDoc} */ + public void drawText(int x, int y, int[] dx, int[] dy, String text) throws IFException { + //Note: dy is currently ignored + g2dState.updateColor(state.getTextColor()); + FontTriplet triplet = new FontTriplet( + state.getFontFamily(), state.getFontStyle(), state.getFontWeight()); + //TODO Ignored: state.getFontVariant() + //TODO Opportunity for font caching if font state is more heavily used + Font font = getFontInfo().getFontInstance(triplet, state.getFontSize()); + //String fontName = font.getFontName(); + //float fontSize = state.getFontSize() / 1000f; + g2dState.updateFont(font.getFontName(), state.getFontSize() * 1000); + + Graphics2D g2d = this.g2dState.getGraph(); + GlyphVector gv = g2d.getFont().createGlyphVector(g2d.getFontRenderContext(), text); + Point2D cursor = new Point2D.Float(0, 0); + + int l = text.length(); + int dxl = (dx != null ? dx.length : 0); + + if (dx != null && dxl > 0 && dx[0] != 0) { + cursor.setLocation(cursor.getX() - (dx[0] / 10f), cursor.getY()); + gv.setGlyphPosition(0, cursor); + } + for (int i = 0; i < l; i++) { + char orgChar = text.charAt(i); + float glyphAdjust = 0; + int cw = font.getCharWidth(orgChar); + + if (dx != null && i < dxl - 1) { + glyphAdjust += dx[i + 1]; + } + + cursor.setLocation(cursor.getX() + cw - glyphAdjust, cursor.getY()); + gv.setGlyphPosition(i + 1, cursor); + } + g2d.drawGlyphVector(gv, x, y); + } + + /** {@inheritDoc} */ + public void setFont(String family, String style, Integer weight, String variant, Integer size, + Color color) throws IFException { + if (family != null) { + state.setFontFamily(family); + } + if (style != null) { + state.setFontStyle(style); + } + if (weight != null) { + state.setFontWeight(weight.intValue()); + } + if (variant != null) { + state.setFontVariant(variant); + } + if (size != null) { + state.setFontSize(size.intValue()); + } + if (color != null) { + state.setTextColor(color); + } + } + + //---------------------------------------------------------------------------------------------- + + /** Saves the current graphics state on the stack. */ + protected void saveGraphicsState() { + g2dStateStack.push(g2dState); + g2dState = new Java2DGraphicsState(g2dState); + } + + /** Restores the last graphics state from the stack. */ + protected void restoreGraphicsState() { + g2dState.dispose(); + g2dState = (Java2DGraphicsState)g2dStateStack.pop(); + } + + private void concatenateTransformationMatrix(AffineTransform transform) throws IOException { + g2dState.transform(transform); + } + +} diff --git a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java index e3f79dea2..65e6ac0fe 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java +++ b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java @@ -123,7 +123,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem /** The 0-based current page number */ private int currentPageNumber = 0; - /** true if antialiasing is set */ + /** true if anti-aliasing is set */ protected boolean antialiasing = true; /** true if qualityRendering is set */ @@ -171,12 +171,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem //Don't call super.setupFontInfo() here! Java2D needs a special font setup // create a temp Image to test font metrics on this.fontInfo = inFontInfo; - BufferedImage fontImage = new BufferedImage(100, 100, - BufferedImage.TYPE_INT_RGB); - Graphics2D graphics2D = fontImage.createGraphics(); - //The next line is important to get accurate font metrics! - graphics2D.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, - RenderingHints.VALUE_FRACTIONALMETRICS_ON); + Graphics2D graphics2D = Java2DFontMetrics.createFontMetricsGraphics2D(); FontCollection[] fontCollections = new FontCollection[] { new Base14FontCollection(graphics2D), diff --git a/src/java/org/apache/fop/render/java2d/Java2DRenderingContext.java b/src/java/org/apache/fop/render/java2d/Java2DRenderingContext.java new file mode 100644 index 000000000..7bc55502a --- /dev/null +++ b/src/java/org/apache/fop/render/java2d/Java2DRenderingContext.java @@ -0,0 +1,61 @@ +/* + * 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.awt.Graphics2D; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.render.AbstractRenderingContext; + +/** + * Rendering context for PDF production. + */ +public class Java2DRenderingContext extends AbstractRenderingContext { + + private FontInfo fontInfo; + private Graphics2D g2d; + + /** + * Main constructor. + * @param userAgent the user agent + * @param g2d the target Graphics2D instance + * @param fontInfo the font list + */ + public Java2DRenderingContext(FOUserAgent userAgent, Graphics2D g2d, FontInfo fontInfo) { + super(userAgent); + this.g2d = g2d; + this.fontInfo = fontInfo; + } + + /** {@inheritDoc} */ + public String getMimeType() { + return null; //not applicable + } + + /** + * Returns the target Graphics2D object. + * @return the Graphics2D object + */ + public Graphics2D getGraphics2D() { + return this.g2d; + } + +} diff --git a/src/java/org/apache/fop/render/java2d/Java2DRenderingSettings.java b/src/java/org/apache/fop/render/java2d/Java2DRenderingSettings.java new file mode 100644 index 000000000..f7bad64a7 --- /dev/null +++ b/src/java/org/apache/fop/render/java2d/Java2DRenderingSettings.java @@ -0,0 +1,58 @@ +/* + * 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.awt.Color; + +/** + * This class holds settings used when rendering with Java2D. + */ +public class Java2DRenderingSettings { + + /** false: paints a non-transparent white background, true: for a transparent background */ + private Color pageBackgroundColor = Color.WHITE; + + /** + * Returns the page background color. + * @return the page background color or null if the page background is transparent + */ + public Color getPageBackgroundColor() { + return this.pageBackgroundColor; + } + + /** + * Sets the page background color. + * @param color the page background color or null if the page background shall be transparent + */ + public void setPageBackgroundColor(Color color) { + this.pageBackgroundColor = color; + } + + /** + * Indicates whether the pages have a transparent background or if it's painted in a + * particular color. + * @return true if the pages have a transparent background + */ + 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 new file mode 100644 index 000000000..30f84ba22 --- /dev/null +++ b/src/java/org/apache/fop/render/java2d/Java2DUtil.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.java2d; + +import java.awt.Graphics2D; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.fonts.FontCollection; +import org.apache.fop.fonts.FontEventAdapter; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontManager; + +/** + * Rendering-related utilities for Java2D. + */ +public class Java2DUtil { + + /** + * Builds a default {@code FontInfo} object for use with output formats using the Java2D + * font setup. + * @param fontInfo the font info object to populate + * @param userAgent the user agent + * @return the populated font information object + */ + public static FontInfo buildDefaultJava2DBasedFontInfo( + FontInfo fontInfo, FOUserAgent userAgent) { + Graphics2D graphics2D = Java2DFontMetrics.createFontMetricsGraphics2D(); + + FontManager fontManager = userAgent.getFactory().getFontManager(); + FontCollection[] fontCollections = new FontCollection[] { + new org.apache.fop.render.java2d.Base14FontCollection(graphics2D), + new InstalledFontCollection(graphics2D) + }; + + FontInfo fi = (fontInfo != null ? fontInfo : new FontInfo()); + fi.setEventListener(new FontEventAdapter(userAgent.getEventBroadcaster())); + fontManager.setup(fi, fontCollections); + return fi; + } + + +} diff --git a/src/java/org/apache/fop/render/pcl/PCLDocumentHandler.java b/src/java/org/apache/fop/render/pcl/PCLDocumentHandler.java new file mode 100644 index 000000000..ce032ace5 --- /dev/null +++ b/src/java/org/apache/fop/render/pcl/PCLDocumentHandler.java @@ -0,0 +1,252 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.pcl; + +import java.awt.Dimension; +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.MimeConstants; +import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler; +import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; +import org.apache.fop.render.intermediate.IFException; +import org.apache.fop.render.intermediate.IFPainter; + +/** + * {@code IFDocumentHandler} implementation that produces PCL 5. + */ +public class PCLDocumentHandler extends AbstractBinaryWritingIFDocumentHandler + implements PCLConstants { + + /** logging instance */ + private static Log log = LogFactory.getLog(PCLDocumentHandler.class); + + /** Utility class for handling all sorts of peripheral tasks around PCL generation. */ + protected PCLRenderingUtil pclUtil; + + /** The PCL generator */ + private PCLGenerator gen; + + private PCLPageDefinition currentPageDefinition; + + /** contains the pageWith of the last printed page */ + private long pageWidth = 0; + /** contains the pageHeight of the last printed page */ + private long pageHeight = 0; + + /** + * Default constructor. + */ + public PCLDocumentHandler() { + } + + /** {@inheritDoc} */ + public boolean supportsPagesOutOfOrder() { + return false; + } + + /** {@inheritDoc} */ + public String getMimeType() { + return MimeConstants.MIME_PCL; + } + + /** {@inheritDoc} */ + public void setUserAgent(FOUserAgent ua) { + super.setUserAgent(ua); + this.pclUtil = new PCLRenderingUtil(ua); + } + + /** {@inheritDoc} */ + public IFDocumentHandlerConfigurator getConfigurator() { + return null; //No configurator, yet. + } + + PCLRenderingUtil getPCLUtil() { + return this.pclUtil; + } + + PCLGenerator getPCLGenerator() { + return this.gen; + } + + /** @return the target resolution */ + protected int getResolution() { + int resolution = (int)Math.round(getUserAgent().getTargetResolution()); + if (resolution <= 300) { + return 300; + } else { + return 600; + } + } + + //---------------------------------------------------------------------------------------------- + + /** {@inheritDoc} */ + public void startDocument() throws IFException { + try { + if (getUserAgent() == null) { + throw new IllegalStateException( + "User agent must be set before starting PDF generation"); + } + if (this.outputStream == null) { + throw new IllegalStateException("OutputStream hasn't been set through setResult()"); + } + log.debug("Rendering areas to PCL..."); + this.gen = new PCLGenerator(this.outputStream, getResolution()); + + if (!pclUtil.isPJLDisabled()) { + gen.universalEndOfLanguage(); + gen.writeText("@PJL COMMENT Produced by " + getUserAgent().getProducer() + "\n"); + if (getUserAgent().getTitle() != null) { + gen.writeText("@PJL JOB NAME = \"" + getUserAgent().getTitle() + "\"\n"); + } + gen.writeText("@PJL SET RESOLUTION = " + getResolution() + "\n"); + gen.writeText("@PJL ENTER LANGUAGE = PCL\n"); + } + gen.resetPrinter(); + gen.setUnitOfMeasure(getResolution()); + gen.setRasterGraphicsResolution(getResolution()); + } catch (IOException e) { + throw new IFException("I/O error in startDocument()", e); + } + } + + /** {@inheritDoc} */ + public void endDocumentHeader() throws IFException { + } + + /** {@inheritDoc} */ + public void endDocument() throws IFException { + try { + gen.separateJobs(); + gen.resetPrinter(); + if (!pclUtil.isPJLDisabled()) { + gen.universalEndOfLanguage(); + } + } catch (IOException ioe) { + throw new IFException("I/O error in endDocument()", ioe); + } + super.endDocument(); + } + + /** {@inheritDoc} */ + public void startPageSequence(String id) throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void endPageSequence() throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void startPage(int index, String name, Dimension size) throws IFException { + + try { + //TODO Add support for paper-source and duplex-mode + /* + //Paper source + String paperSource = page.getForeignAttributeValue( + new QName(PCLElementMapping.NAMESPACE, null, "paper-source")); + if (paperSource != null) { + gen.selectPaperSource(Integer.parseInt(paperSource)); + } + + // Is Page duplex? + String pageDuplex = page.getForeignAttributeValue( + new QName(PCLElementMapping.NAMESPACE, null, "duplex-mode")); + if (pageDuplex != null) { + gen.selectDuplexMode(Integer.parseInt(pageDuplex)); + }*/ + + //Page size + final long pagewidth = size.width; + final long pageheight = size.height; + selectPageFormat(pagewidth, pageheight); + } catch (IOException ioe) { + throw new IFException("I/O error in startPage()", ioe); + } + } + + /** {@inheritDoc} */ + public IFPainter startPageContent() throws IFException { + return new PCLPainter(this, this.currentPageDefinition); + } + + /** {@inheritDoc} */ + public void endPageContent() throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void endPage() throws IFException { + try { + //Eject page + gen.formFeed(); + } catch (IOException ioe) { + throw new IFException("I/O error in endPage()", ioe); + } + } + + /** {@inheritDoc} */ + public void handleExtensionObject(Object extension) throws IFException { + if (false) { + //TODO Handle extensions + } else { + log.debug("Don't know how to handle extension object. Ignoring: " + + extension + " (" + extension.getClass().getName() + ")"); + } + } + + private void selectPageFormat(long pagewidth, long pageheight) throws IOException { + //Only set the page format if it changes (otherwise duplex printing won't work) + if ((pagewidth != this.pageWidth) || (pageheight != this.pageHeight)) { + this.pageWidth = pagewidth; + this.pageHeight = pageheight; + + this.currentPageDefinition = PCLPageDefinition.getPageDefinition( + pagewidth, pageheight, 1000); + + if (this.currentPageDefinition == null) { + this.currentPageDefinition = PCLPageDefinition.getDefaultPageDefinition(); + log.warn("Paper type could not be determined. Falling back to: " + + this.currentPageDefinition.getName()); + } + if (log.isDebugEnabled()) { + log.debug("page size: " + currentPageDefinition.getPhysicalPageSize()); + log.debug("logical page: " + currentPageDefinition.getLogicalPageRect()); + } + + if (this.currentPageDefinition.isLandscapeFormat()) { + gen.writeCommand("&l1O"); //Landscape Orientation + } else { + gen.writeCommand("&l0O"); //Portrait Orientation + } + gen.selectPageSize(this.currentPageDefinition.getSelector()); + + gen.clearHorizontalMargins(); + gen.setTopMargin(0); + } + } + +} diff --git a/src/java/org/apache/fop/render/pcl/PCLPainterMaker.java b/src/java/org/apache/fop/render/pcl/PCLDocumentHandlerMaker.java index eb5dfda40..5d42d3320 100644 --- a/src/java/org/apache/fop/render/pcl/PCLPainterMaker.java +++ b/src/java/org/apache/fop/render/pcl/PCLDocumentHandlerMaker.java @@ -21,21 +21,23 @@ package org.apache.fop.render.pcl; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; -import org.apache.fop.render.intermediate.AbstractIFPainterMaker; -import org.apache.fop.render.intermediate.IFPainter; -import org.apache.fop.render.intermediate.IFPainterConfigurator; +import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker; +import org.apache.fop.render.intermediate.IFDocumentHandler; +import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; /** - * Painter factory for PCL output. + * Document handler factory for PCL output. */ -public class PCLPainterMaker extends AbstractIFPainterMaker { +public class PCLDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { //TODO Revert to normal MIME after stabilization! private static final String[] MIMES = new String[] {MimeConstants.MIME_PCL + ";mode=painter"}; /** {@inheritDoc} */ - public IFPainter makePainter(FOUserAgent ua) { - return new PCLPainter(); + public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { + PCLDocumentHandler handler = new PCLDocumentHandler(); + handler.setUserAgent(ua); + return handler; } /** {@inheritDoc} */ @@ -48,8 +50,9 @@ public class PCLPainterMaker extends AbstractIFPainterMaker { return MIMES; } - public IFPainterConfigurator getConfigurator(FOUserAgent userAgent) { - return null; //new PDFRendererConfigurator(userAgent); + /** {@inheritDoc} */ + public IFDocumentHandlerConfigurator getConfigurator(FOUserAgent userAgent) { + return null; } } diff --git a/src/java/org/apache/fop/render/pcl/PCLPainter.java b/src/java/org/apache/fop/render/pcl/PCLPainter.java index 9f194df25..d4e04175e 100644 --- a/src/java/org/apache/fop/render/pcl/PCLPainter.java +++ b/src/java/org/apache/fop/render/pcl/PCLPainter.java @@ -38,12 +38,11 @@ import org.apache.commons.logging.LogFactory; import org.apache.xmlgraphics.java2d.GraphicContext; import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.apps.MimeConstants; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontTriplet; import org.apache.fop.pdf.PDFXObject; import org.apache.fop.render.RenderingContext; -import org.apache.fop.render.intermediate.AbstractBinaryWritingIFPainter; +import org.apache.fop.render.intermediate.AbstractIFPainter; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFState; import org.apache.fop.traits.BorderProps; @@ -52,19 +51,18 @@ import org.apache.fop.util.CharUtilities; import org.apache.fop.util.UnitConv; /** - * IFPainter implementation that produces PCL. + * {@code IFPainter} implementation that produces PCL 5. */ -public class PCLPainter extends AbstractBinaryWritingIFPainter implements PCLConstants { +public class PCLPainter extends AbstractIFPainter implements PCLConstants { /** logging instance */ private static Log log = LogFactory.getLog(PCLPainter.class); + private PCLDocumentHandler parent; + /** Holds the intermediate format state */ protected IFState state; - /** Utility class for handling all sorts of peripheral tasks around PCL generation. */ - protected PCLRenderingUtil pclUtil; - /** The PCL generator */ private PCLGenerator gen; @@ -75,35 +73,24 @@ public class PCLPainter extends AbstractBinaryWritingIFPainter implements PCLCon private Stack graphicContextStack = new Stack(); private GraphicContext graphicContext = new GraphicContext(); - /** contains the pageWith of the last printed page */ - private long pageWidth = 0; - /** contains the pageHeight of the last printed page */ - private long pageHeight = 0; - /** - * Default constructor. + * Main constructor. + * @param parent the parent document handler */ - public PCLPainter() { - } - - /** {@inheritDoc} */ - public boolean supportsPagesOutOfOrder() { - return true; - } - - /** {@inheritDoc} */ - public String getMimeType() { - return MimeConstants.MIME_PCL; + public PCLPainter(PCLDocumentHandler parent, PCLPageDefinition pageDefinition) { + this.parent = parent; + this.gen = parent.getPCLGenerator(); + this.state = IFState.create(); + this.currentPageDefinition = pageDefinition; } /** {@inheritDoc} */ - public void setUserAgent(FOUserAgent ua) { - super.setUserAgent(ua); - this.pclUtil = new PCLRenderingUtil(ua); + public FOUserAgent getUserAgent() { + return this.parent.getUserAgent(); } PCLRenderingUtil getPCLUtil() { - return this.pclUtil; + return this.parent.getPCLUtil(); } /** @return the target resolution */ @@ -119,116 +106,6 @@ public class PCLPainter extends AbstractBinaryWritingIFPainter implements PCLCon //---------------------------------------------------------------------------------------------- /** {@inheritDoc} */ - public void startDocument() throws IFException { - try { - if (getUserAgent() == null) { - throw new IllegalStateException( - "User agent must be set before starting PDF generation"); - } - if (this.outputStream == null) { - throw new IllegalStateException("OutputStream hasn't been set through setResult()"); - } - log.debug("Rendering areas to PCL..."); - this.gen = new PCLGenerator(this.outputStream, getResolution()); - - if (!pclUtil.isPJLDisabled()) { - gen.universalEndOfLanguage(); - gen.writeText("@PJL COMMENT Produced by " + getUserAgent().getProducer() + "\n"); - if (getUserAgent().getTitle() != null) { - gen.writeText("@PJL JOB NAME = \"" + getUserAgent().getTitle() + "\"\n"); - } - gen.writeText("@PJL SET RESOLUTION = " + getResolution() + "\n"); - gen.writeText("@PJL ENTER LANGUAGE = PCL\n"); - } - gen.resetPrinter(); - gen.setUnitOfMeasure(getResolution()); - gen.setRasterGraphicsResolution(getResolution()); - } catch (IOException e) { - throw new IFException("I/O error in startDocument()", e); - } - } - - /** {@inheritDoc} */ - public void endDocumentHeader() throws IFException { - } - - /** {@inheritDoc} */ - public void endDocument() throws IFException { - try { - gen.separateJobs(); - gen.resetPrinter(); - if (!pclUtil.isPJLDisabled()) { - gen.universalEndOfLanguage(); - } - } catch (IOException ioe) { - throw new IFException("I/O error in endDocument()", ioe); - } - super.endDocument(); - } - - /** {@inheritDoc} */ - public void startPageSequence(String id) throws IFException { - //nop - } - - /** {@inheritDoc} */ - public void endPageSequence() throws IFException { - //nop - } - - /** {@inheritDoc} */ - public void startPage(int index, String name, Dimension size) throws IFException { - saveGraphicsState(); - - try { - //TODO Add support for paper-source and duplex-mode - /* - //Paper source - String paperSource = page.getForeignAttributeValue( - new QName(PCLElementMapping.NAMESPACE, null, "paper-source")); - if (paperSource != null) { - gen.selectPaperSource(Integer.parseInt(paperSource)); - } - - // Is Page duplex? - String pageDuplex = page.getForeignAttributeValue( - new QName(PCLElementMapping.NAMESPACE, null, "duplex-mode")); - if (pageDuplex != null) { - gen.selectDuplexMode(Integer.parseInt(pageDuplex)); - }*/ - - //Page size - final long pagewidth = size.width; - final long pageheight = size.height; - selectPageFormat(pagewidth, pageheight); - } catch (IOException ioe) { - throw new IFException("I/O error in startPage()", ioe); - } - } - - /** {@inheritDoc} */ - public void startPageContent() throws IFException { - this.state = IFState.create(); - } - - /** {@inheritDoc} */ - public void endPageContent() throws IFException { - assert this.state.pop() == null; - //nop - } - - /** {@inheritDoc} */ - public void endPage() throws IFException { - try { - //Eject page - gen.formFeed(); - restoreGraphicsState(); - } catch (IOException ioe) { - throw new IFException("I/O error in endPage()", ioe); - } - } - - /** {@inheritDoc} */ public void startViewport(AffineTransform transform, Dimension size, Rectangle clipRect) throws IFException { saveGraphicsState(); @@ -377,8 +254,8 @@ public class PCLPainter extends AbstractBinaryWritingIFPainter implements PCLCon state.getFontFamily(), state.getFontStyle(), state.getFontWeight()); //TODO Ignored: state.getFontVariant() //TODO Opportunity for font caching if font state is more heavily used - String fontKey = fontInfo.getInternalFontKey(triplet); - boolean pclFont = pclUtil.isAllTextAsBitmaps() + String fontKey = parent.getFontInfo().getInternalFontKey(triplet); + boolean pclFont = getPCLUtil().isAllTextAsBitmaps() ? false : setFont(fontKey, state.getFontSize(), text); if (true || pclFont) { @@ -403,7 +280,7 @@ public class PCLPainter extends AbstractBinaryWritingIFPainter implements PCLCon setCursorPos(x, y); float fontSize = state.getFontSize() / 1000f; - Font font = fontInfo.getFontInstance(triplet, state.getFontSize()); + Font font = parent.getFontInfo().getFontInstance(triplet, state.getFontSize()); int l = text.length(); int dxl = (dx != null ? dx.length : 0); @@ -512,16 +389,6 @@ public class PCLPainter extends AbstractBinaryWritingIFPainter implements PCLCon } } - /** {@inheritDoc} */ - public void handleExtensionObject(Object extension) throws IFException { - if (false) { - //TODO Handle extensions - } else { - log.debug("Ignored extension object: " - + extension + " (" + extension.getClass().getName() + ")"); - } - } - //---------------------------------------------------------------------------------------------- /** Saves the current graphics state on the stack. */ @@ -612,37 +479,6 @@ public class PCLPainter extends AbstractBinaryWritingIFPainter implements PCLCon gen.setCursorPos(transPoint.getX(), transPoint.getY()); } - private void selectPageFormat(long pagewidth, long pageheight) throws IOException { - //Only set the page format if it changes (otherwise duplex printing won't work) - if ((pagewidth != this.pageWidth) || (pageheight != this.pageHeight)) { - this.pageWidth = pagewidth; - this.pageHeight = pageheight; - - this.currentPageDefinition = PCLPageDefinition.getPageDefinition( - pagewidth, pageheight, 1000); - - if (this.currentPageDefinition == null) { - this.currentPageDefinition = PCLPageDefinition.getDefaultPageDefinition(); - log.warn("Paper type could not be determined. Falling back to: " - + this.currentPageDefinition.getName()); - } - if (log.isDebugEnabled()) { - log.debug("page size: " + currentPageDefinition.getPhysicalPageSize()); - log.debug("logical page: " + currentPageDefinition.getLogicalPageRect()); - } - - if (this.currentPageDefinition.isLandscapeFormat()) { - gen.writeCommand("&l1O"); //Landscape Orientation - } else { - gen.writeCommand("&l0O"); //Portrait Orientation - } - gen.selectPageSize(this.currentPageDefinition.getSelector()); - - gen.clearHorizontalMargins(); - gen.setTopMargin(0); - } - } - /** * Sets the current font (NOTE: Hard-coded font mappings ATM!) * @param name the font name (internal F* names for now) diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java new file mode 100644 index 000000000..8937d0d1d --- /dev/null +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java @@ -0,0 +1,295 @@ +/* + * 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.awt.Dimension; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.io.IOException; +import java.util.Iterator; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.xmlgraphics.xmp.Metadata; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.MimeConstants; +import org.apache.fop.fo.extensions.xmp.XMPMetadata; +import org.apache.fop.pdf.PDFAction; +import org.apache.fop.pdf.PDFAnnotList; +import org.apache.fop.pdf.PDFDocument; +import org.apache.fop.pdf.PDFOutline; +import org.apache.fop.pdf.PDFPage; +import org.apache.fop.pdf.PDFReference; +import org.apache.fop.pdf.PDFResourceContext; +import org.apache.fop.pdf.PDFResources; +import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler; +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.intermediate.extensions.AbstractAction; +import org.apache.fop.render.intermediate.extensions.Bookmark; +import org.apache.fop.render.intermediate.extensions.BookmarkTree; +import org.apache.fop.render.intermediate.extensions.GoToXYAction; +import org.apache.fop.render.intermediate.extensions.NamedDestination; + +/** + * {@code IFDocumentHandler} implementation that produces PDF. + */ +public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { + + /** logging instance */ + private static Log log = LogFactory.getLog(PDFDocumentHandler.class); + + /** the PDF Document being created */ + protected PDFDocument pdfDoc; + + /** + * Utility class which enables all sorts of features that are not directly connected to the + * normal rendering process. + */ + protected PDFRenderingUtil pdfUtil; + + /** the /Resources object of the PDF document being created */ + protected PDFResources pdfResources; + + /** The current content generator */ + protected PDFContentGenerator generator; + + /** the current annotation list to add annotations to */ + protected PDFResourceContext currentContext; + + /** the current page to add annotations to */ + protected PDFPage currentPage; + + /** the current page's PDF reference string (to avoid numerous function calls) */ + protected String currentPageRef; + + /** Used for bookmarks/outlines. */ + protected Map pageReferences = new java.util.HashMap(); + + /** + * Default constructor. + */ + public PDFDocumentHandler() { + } + + /** {@inheritDoc} */ + public boolean supportsPagesOutOfOrder() { + return true; + } + + /** {@inheritDoc} */ + public String getMimeType() { + return MimeConstants.MIME_PDF; + } + + /** {@inheritDoc} */ + public void setUserAgent(FOUserAgent ua) { + super.setUserAgent(ua); + this.pdfUtil = new PDFRenderingUtil(ua); + } + + /** {@inheritDoc} */ + public IFDocumentHandlerConfigurator getConfigurator() { + return new PDFRendererConfigurator(getUserAgent()); + } + + PDFRenderingUtil getPDFUtil() { + return this.pdfUtil; + } + + /** {@inheritDoc} */ + public void startDocument() throws IFException { + try { + if (getUserAgent() == null) { + throw new IllegalStateException( + "User agent must be set before starting PDF generation"); + } + if (this.outputStream == null) { + throw new IllegalStateException("OutputStream hasn't been set through setResult()"); + } + this.pdfDoc = pdfUtil.setupPDFDocument(this.outputStream); + } catch (IOException e) { + throw new IFException("I/O error in startDocument()", e); + } + } + + /** {@inheritDoc} */ + public void endDocumentHeader() throws IFException { + pdfUtil.generateDefaultXMPMetadata(); + } + + /** {@inheritDoc} */ + public void endDocument() throws IFException { + try { + pdfDoc.getResources().addFonts(pdfDoc, fontInfo); + pdfDoc.outputTrailer(this.outputStream); + + this.pdfDoc = null; + + pdfResources = null; + this.generator = null; + currentContext = null; + currentPage = null; + } catch (IOException ioe) { + throw new IFException("I/O error in endDocument()", ioe); + } + super.endDocument(); + } + + /** {@inheritDoc} */ + public void startPageSequence(String id) throws IFException { + //TODO page sequence title, country and language + } + + /** {@inheritDoc} */ + public void endPageSequence() throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void startPage(int index, String name, Dimension size) throws IFException { + this.pdfResources = this.pdfDoc.getResources(); + + this.currentPage = this.pdfDoc.getFactory().makePage( + this.pdfResources, + (int)Math.round(size.getWidth() / 1000), + (int)Math.round(size.getHeight() / 1000), + index); + //pageReferences.put(new Integer(index)/*page.getKey()*/, currentPage.referencePDF()); + //pvReferences.put(page.getKey(), page); + + pdfUtil.generatePageLabel(index, name); + + currentPageRef = currentPage.referencePDF(); + this.pageReferences.put(new Integer(index), new PageReference(currentPage, size)); + + this.generator = new PDFContentGenerator(this.pdfDoc, this.outputStream, this.currentPage); + // Transform the PDF's default coordinate system (0,0 at lower left) to the PDFPainter's + AffineTransform basicPageTransform = new AffineTransform(1, 0, 0, -1, 0, + size.height / 1000f); + generator.concatenate(basicPageTransform); + + } + + /** {@inheritDoc} */ + public IFPainter startPageContent() throws IFException { + return new PDFPainter(this); + } + + /** {@inheritDoc} */ + public void endPageContent() throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void endPage() throws IFException { + try { + this.pdfDoc.registerObject(generator.getStream()); + currentPage.setContents(generator.getStream()); + PDFAnnotList annots = currentPage.getAnnotations(); + if (annots != null) { + this.pdfDoc.addObject(annots); + } + this.pdfDoc.addObject(currentPage); + this.generator.flushPDFDoc(); + this.generator = null; + } catch (IOException ioe) { + throw new IFException("I/O error in endPage()", ioe); + } + } + + private void renderBookmarkTree(BookmarkTree tree) { + Iterator iter = tree.getBookmarks().iterator(); + while (iter.hasNext()) { + Bookmark b = (Bookmark)iter.next(); + renderBookmark(b, null); + } + } + + private void renderBookmark(Bookmark bookmark, PDFOutline parent) { + if (parent == null) { + parent = pdfDoc.getOutlineRoot(); + } + PDFAction action = getAction(bookmark.getAction()); + PDFOutline pdfOutline = pdfDoc.getFactory().makeOutline(parent, + bookmark.getTitle(), action, bookmark.isShown()); + Iterator iter = bookmark.getChildBookmarks().iterator(); + while (iter.hasNext()) { + Bookmark b = (Bookmark)iter.next(); + renderBookmark(b, pdfOutline); + } + } + + private void renderNamedDestination(NamedDestination destination) { + PDFAction action = getAction(destination.getAction()); + pdfDoc.getFactory().makeDestination( + destination.getName(), action.makeReference()); + } + + private PDFAction getAction(AbstractAction action) { + if (action instanceof GoToXYAction) { + GoToXYAction a = (GoToXYAction)action; + PageReference pageRef = (PageReference)this.pageReferences.get( + new Integer(a.getPageIndex())); + //Convert target location from millipoints to points and adjust for different + //page origin + Point2D p2d = new Point2D.Double( + a.getTargetLocation().x / 1000.0, + (pageRef.pageDimension.height - a.getTargetLocation().y) / 1000.0); + return pdfDoc.getFactory().getPDFGoTo(pageRef.pageRef.toString(), p2d); + } else { + throw new UnsupportedOperationException("Unsupported action type: " + + action + " (" + action.getClass().getName() + ")"); + } + } + + /** {@inheritDoc} */ + public void handleExtensionObject(Object extension) throws IFException { + if (extension instanceof XMPMetadata) { + pdfUtil.renderXMPMetadata((XMPMetadata)extension); + } else if (extension instanceof Metadata) { + XMPMetadata wrapper = new XMPMetadata(((Metadata)extension)); + pdfUtil.renderXMPMetadata(wrapper); + } else if (extension instanceof BookmarkTree) { + renderBookmarkTree((BookmarkTree)extension); + } else if (extension instanceof NamedDestination) { + renderNamedDestination((NamedDestination)extension); + } else { + log.debug("Don't know how to handle extension object. Ignoring: " + + extension + " (" + extension.getClass().getName() + ")"); + } + } + + private static final class PageReference { + + private PDFReference pageRef; + private Dimension pageDimension; + + private PageReference(PDFPage page, Dimension dim) { + this.pageRef = page.makeReference(); + this.pageDimension = new Dimension(dim); + } + } + +} diff --git a/src/java/org/apache/fop/render/pdf/PDFPainterMaker.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandlerMaker.java index f1fbe48fd..88ae60d2c 100644 --- a/src/java/org/apache/fop/render/pdf/PDFPainterMaker.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandlerMaker.java @@ -21,21 +21,23 @@ package org.apache.fop.render.pdf; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; -import org.apache.fop.render.intermediate.AbstractIFPainterMaker; -import org.apache.fop.render.intermediate.IFPainter; -import org.apache.fop.render.intermediate.IFPainterConfigurator; +import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker; +import org.apache.fop.render.intermediate.IFDocumentHandler; +import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; /** - * Painter factory for PDF output. + * Intermediate format document handler factory for PDF output. */ -public class PDFPainterMaker extends AbstractIFPainterMaker { +public class PDFDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { //TODO Revert to normal MIME after stabilization! private static final String[] MIMES = new String[] {MimeConstants.MIME_PDF + ";mode=painter"}; /** {@inheritDoc} */ - public IFPainter makePainter(FOUserAgent ua) { - return new PDFPainter(); + public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { + PDFDocumentHandler handler = new PDFDocumentHandler(); + handler.setUserAgent(ua); + return handler; } /** {@inheritDoc} */ @@ -48,7 +50,8 @@ public class PDFPainterMaker extends AbstractIFPainterMaker { return MIMES; } - public IFPainterConfigurator getConfigurator(FOUserAgent userAgent) { + /** {@inheritDoc} */ + public IFDocumentHandlerConfigurator getConfigurator(FOUserAgent userAgent) { return new PDFRendererConfigurator(userAgent); } diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java index 975f72c06..3764486b7 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java @@ -193,8 +193,8 @@ public class PDFImageHandlerSVG implements ImageHandler { public boolean isCompatible(RenderingContext targetContext, Image image) { return (image == null || (image instanceof ImageXMLDOM - && image.getFlavor().isCompatible(BatikImageFlavors.SVG_DOM)) - && targetContext instanceof PDFRenderingContext); + && image.getFlavor().isCompatible(BatikImageFlavors.SVG_DOM))) + && targetContext instanceof PDFRenderingContext; } } diff --git a/src/java/org/apache/fop/render/pdf/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java index 6501ea648..5273220e7 100644 --- a/src/java/org/apache/fop/render/pdf/PDFPainter.java +++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java @@ -25,9 +25,7 @@ import java.awt.Paint; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; import java.io.IOException; -import java.util.Iterator; import java.util.Map; import org.w3c.dom.Document; @@ -35,36 +33,21 @@ import org.w3c.dom.Document; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.xmlgraphics.xmp.Metadata; - import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.apps.MimeConstants; -import org.apache.fop.fo.extensions.xmp.XMPMetadata; 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.PDFAction; -import org.apache.fop.pdf.PDFAnnotList; import org.apache.fop.pdf.PDFDocument; import org.apache.fop.pdf.PDFNumber; -import org.apache.fop.pdf.PDFOutline; -import org.apache.fop.pdf.PDFPage; -import org.apache.fop.pdf.PDFReference; -import org.apache.fop.pdf.PDFResourceContext; -import org.apache.fop.pdf.PDFResources; import org.apache.fop.pdf.PDFTextUtil; import org.apache.fop.pdf.PDFXObject; import org.apache.fop.render.RenderingContext; -import org.apache.fop.render.intermediate.AbstractBinaryWritingIFPainter; +import org.apache.fop.render.intermediate.AbstractIFPainter; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFState; -import org.apache.fop.render.intermediate.extensions.AbstractAction; -import org.apache.fop.render.intermediate.extensions.Bookmark; -import org.apache.fop.render.intermediate.extensions.BookmarkTree; -import org.apache.fop.render.intermediate.extensions.GoToXYAction; -import org.apache.fop.render.intermediate.extensions.NamedDestination; import org.apache.fop.traits.BorderProps; import org.apache.fop.traits.RuleStyle; import org.apache.fop.util.CharUtilities; @@ -72,169 +55,48 @@ import org.apache.fop.util.CharUtilities; /** * IFPainter implementation that produces PDF. */ -public class PDFPainter extends AbstractBinaryWritingIFPainter { +public class PDFPainter extends AbstractIFPainter { /** logging instance */ private static Log log = LogFactory.getLog(PDFPainter.class); + private PDFDocumentHandler documentHandler; + /** Holds the intermediate format state */ protected IFState state; - /** the PDF Document being created */ - protected PDFDocument pdfDoc; - - /** - * Utility class which enables all sorts of features that are not directly connected to the - * normal rendering process. - */ - protected PDFRenderingUtil pdfUtil; - - /** the /Resources object of the PDF document being created */ - protected PDFResources pdfResources; - /** The current content generator */ protected PDFContentGenerator generator; private PDFBorderPainter borderPainter; - /** the current annotation list to add annotations to */ - protected PDFResourceContext currentContext; - - /** the current page to add annotations to */ - protected PDFPage currentPage; - - /** the current page's PDF reference string (to avoid numerous function calls) */ - protected String currentPageRef; - - /** Used for bookmarks/outlines. */ - private Map pageReferences = new java.util.HashMap(); - /** * Default constructor. + * @param documentHandler the parent document handler */ - public PDFPainter() { - } - - /** {@inheritDoc} */ - public boolean supportsPagesOutOfOrder() { - return true; - } - - /** {@inheritDoc} */ - public String getMimeType() { - return MimeConstants.MIME_PDF; + public PDFPainter(PDFDocumentHandler documentHandler) { + super(); + this.documentHandler = documentHandler; + this.generator = documentHandler.generator; + this.borderPainter = new PDFBorderPainter(this.generator); + this.state = IFState.create(); } /** {@inheritDoc} */ - public void setUserAgent(FOUserAgent ua) { - super.setUserAgent(ua); - this.pdfUtil = new PDFRenderingUtil(ua); + protected FOUserAgent getUserAgent() { + return this.documentHandler.getUserAgent(); } PDFRenderingUtil getPDFUtil() { - return this.pdfUtil; - } - - /** {@inheritDoc} */ - public void startDocument() throws IFException { - try { - if (getUserAgent() == null) { - throw new IllegalStateException( - "User agent must be set before starting PDF generation"); - } - if (this.outputStream == null) { - throw new IllegalStateException("OutputStream hasn't been set through setResult()"); - } - this.pdfDoc = pdfUtil.setupPDFDocument(this.outputStream); - } catch (IOException e) { - throw new IFException("I/O error in startDocument()", e); - } + return this.documentHandler.pdfUtil; } - /** {@inheritDoc} */ - public void endDocumentHeader() throws IFException { - pdfUtil.generateDefaultXMPMetadata(); + PDFDocument getPDFDoc() { + return this.documentHandler.pdfDoc; } - /** {@inheritDoc} */ - public void endDocument() throws IFException { - try { - pdfDoc.getResources().addFonts(pdfDoc, fontInfo); - pdfDoc.outputTrailer(this.outputStream); - - this.pdfDoc = null; - - pdfResources = null; - this.generator = null; - currentContext = null; - currentPage = null; - } catch (IOException ioe) { - throw new IFException("I/O error in endDocument()", ioe); - } - super.endDocument(); - } - - /** {@inheritDoc} */ - public void startPageSequence(String id) throws IFException { - //TODO page sequence title, country and language - } - - /** {@inheritDoc} */ - public void endPageSequence() throws IFException { - //nop - } - - /** {@inheritDoc} */ - public void startPage(int index, String name, Dimension size) throws IFException { - this.pdfResources = this.pdfDoc.getResources(); - - this.currentPage = this.pdfDoc.getFactory().makePage( - this.pdfResources, - (int)Math.round(size.getWidth() / 1000), - (int)Math.round(size.getHeight() / 1000), - index); - //pageReferences.put(new Integer(index)/*page.getKey()*/, currentPage.referencePDF()); - //pvReferences.put(page.getKey(), page); - - pdfUtil.generatePageLabel(index, name); - - currentPageRef = currentPage.referencePDF(); - this.pageReferences.put(new Integer(index), new PageReference(currentPage, size)); - - this.generator = new PDFContentGenerator(this.pdfDoc, this.outputStream, this.currentPage); - // Transform the PDF's default coordinate system (0,0 at lower left) to the PDFPainter's - AffineTransform basicPageTransform = new AffineTransform(1, 0, 0, -1, 0, - size.height / 1000f); - generator.concatenate(basicPageTransform); - - this.borderPainter = new PDFBorderPainter(this.generator); - } - - /** {@inheritDoc} */ - public void startPageContent() throws IFException { - this.state = IFState.create(); - } - - /** {@inheritDoc} */ - public void endPageContent() throws IFException { - assert this.state.pop() == null; - } - - /** {@inheritDoc} */ - public void endPage() throws IFException { - try { - this.pdfDoc.registerObject(generator.getStream()); - currentPage.setContents(generator.getStream()); - PDFAnnotList annots = currentPage.getAnnotations(); - if (annots != null) { - this.pdfDoc.addObject(annots); - } - this.pdfDoc.addObject(currentPage); - this.generator.flushPDFDoc(); - this.generator = null; - } catch (IOException ioe) { - throw new IFException("I/O error in endPage()", ioe); - } + FontInfo getFontInfo() { + return this.documentHandler.getFontInfo(); } /** {@inheritDoc} */ @@ -265,7 +127,7 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter { /** {@inheritDoc} */ public void drawImage(String uri, Rectangle rect, Map foreignAttributes) throws IFException { - PDFXObject xobject = pdfDoc.getXObject(uri); + PDFXObject xobject = getPDFDoc().getXObject(uri); if (xobject != null) { placeImage(rect, xobject); return; @@ -279,7 +141,7 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter { /** {@inheritDoc} */ protected RenderingContext createRenderingContext() { PDFRenderingContext pdfContext = new PDFRenderingContext( - getUserAgent(), generator, currentPage, getFontInfo()); + getUserAgent(), generator, this.documentHandler.currentPage, getFontInfo()); return pdfContext; } @@ -383,7 +245,7 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter { if (fontName == null) { throw new NullPointerException("fontName must not be null"); } - Typeface tf = (Typeface) fontInfo.getFonts().get(fontName); + Typeface tf = (Typeface)getFontInfo().getFonts().get(fontName); if (tf instanceof LazyFont) { tf = ((LazyFont)tf).getRealFont(); } @@ -399,7 +261,7 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter { state.getFontFamily(), state.getFontStyle(), state.getFontWeight()); //TODO Ignored: state.getFontVariant() //TODO Opportunity for font caching if font state is more heavily used - String fontKey = fontInfo.getInternalFontKey(triplet); + String fontKey = getFontInfo().getInternalFontKey(triplet); int sizeMillipoints = state.getFontSize(); float fontSize = sizeMillipoints / 1000f; @@ -409,7 +271,7 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter { if (tf instanceof SingleByteFont) { singleByteFont = (SingleByteFont)tf; } - Font font = fontInfo.getFontInstance(triplet, sizeMillipoints); + Font font = getFontInfo().getFontInstance(triplet, sizeMillipoints); String fontName = font.getFontName(); PDFTextUtil textutil = generator.getTextUtil(); @@ -485,77 +347,4 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter { } } - private void renderBookmarkTree(BookmarkTree tree) { - Iterator iter = tree.getBookmarks().iterator(); - while (iter.hasNext()) { - Bookmark b = (Bookmark)iter.next(); - renderBookmark(b, null); - } - } - - private void renderBookmark(Bookmark bookmark, PDFOutline parent) { - if (parent == null) { - parent = pdfDoc.getOutlineRoot(); - } - PDFAction action = getAction(bookmark.getAction()); - PDFOutline pdfOutline = pdfDoc.getFactory().makeOutline(parent, - bookmark.getTitle(), action, bookmark.isShown()); - Iterator iter = bookmark.getChildBookmarks().iterator(); - while (iter.hasNext()) { - Bookmark b = (Bookmark)iter.next(); - renderBookmark(b, pdfOutline); - } - } - - private void renderNamedDestination(NamedDestination destination) { - PDFAction action = getAction(destination.getAction()); - pdfDoc.getFactory().makeDestination( - destination.getName(), action.makeReference()); - } - - private PDFAction getAction(AbstractAction action) { - if (action instanceof GoToXYAction) { - GoToXYAction a = (GoToXYAction)action; - PageReference pageRef = (PageReference)this.pageReferences.get( - new Integer(a.getPageIndex())); - //Convert target location from millipoints to points and adjust for different - //page origin - Point2D p2d = new Point2D.Double( - a.getTargetLocation().x / 1000.0, - (pageRef.pageDimension.height - a.getTargetLocation().y) / 1000.0); - return pdfDoc.getFactory().getPDFGoTo(pageRef.pageRef.toString(), p2d); - } else { - throw new UnsupportedOperationException("Unsupported action type: " - + action + " (" + action.getClass().getName() + ")"); - } - } - - /** {@inheritDoc} */ - public void handleExtensionObject(Object extension) throws IFException { - if (extension instanceof XMPMetadata) { - pdfUtil.renderXMPMetadata((XMPMetadata)extension); - } else if (extension instanceof Metadata) { - XMPMetadata wrapper = new XMPMetadata(((Metadata)extension)); - pdfUtil.renderXMPMetadata(wrapper); - } else if (extension instanceof BookmarkTree) { - renderBookmarkTree((BookmarkTree)extension); - } else if (extension instanceof NamedDestination) { - renderNamedDestination((NamedDestination)extension); - } else { - log.warn("Don't know how to handle extension object: " - + extension + " (" + extension.getClass().getName()); - } - } - - private static final class PageReference { - - private PDFReference pageRef; - private Dimension pageDimension; - - private PageReference(PDFPage page, Dimension dim) { - this.pageRef = page.makeReference(); - this.pageDimension = new Dimension(dim); - } - } - } diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java b/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java index 50b489717..d416f1147 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java +++ b/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java @@ -42,15 +42,15 @@ import org.apache.fop.pdf.PDFXMode; import org.apache.fop.render.DefaultFontResolver; import org.apache.fop.render.PrintRendererConfigurator; import org.apache.fop.render.Renderer; -import org.apache.fop.render.intermediate.IFPainter; -import org.apache.fop.render.intermediate.IFPainterConfigurator; +import org.apache.fop.render.intermediate.IFDocumentHandler; +import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; import org.apache.fop.util.LogUtil; /** - * PDF renderer configurator + * PDF renderer configurator. */ public class PDFRendererConfigurator extends PrintRendererConfigurator - implements IFPainterConfigurator { + implements IFDocumentHandlerConfigurator { /** * Default constructor @@ -198,38 +198,38 @@ public class PDFRendererConfigurator extends PrintRendererConfigurator return filterMap; } - // ---=== IFPainter configuration ===--- + // ---=== IFDocumentHandler configuration ===--- /** {@inheritDoc} */ - public void configure(IFPainter painter) throws FOPException { - Configuration cfg = super.getRendererConfig(painter.getMimeType()); + public void configure(IFDocumentHandler documentHandler) throws FOPException { + Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); if (cfg != null) { - PDFPainter pdfPainter = (PDFPainter)painter; - PDFRenderingUtil pdfUtil = pdfPainter.getPDFUtil(); + PDFDocumentHandler pdfDocumentHandler = (PDFDocumentHandler)documentHandler; + PDFRenderingUtil pdfUtil = pdfDocumentHandler.getPDFUtil(); configure(cfg, pdfUtil); } } /** {@inheritDoc} */ - public void setupFontInfo(IFPainter painter) throws FOPException { + public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo) + throws FOPException { FontManager fontManager = userAgent.getFactory().getFontManager(); List fontCollections = new java.util.ArrayList(); fontCollections.add(new Base14FontCollection(fontManager.isBase14KerningEnabled())); - FontEventListener listener = new FontEventAdapter(userAgent.getEventBroadcaster()); - Configuration cfg = super.getRendererConfig(painter.getMimeType()); + 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 CustomFontCollection(fontResolver, fontList)); } - FontInfo fontInfo = new FontInfo(); - fontInfo.setEventListener(listener); fontManager.setup(fontInfo, (FontCollection[])fontCollections.toArray( new FontCollection[fontCollections.size()])); - painter.setFontInfo(fontInfo); + documentHandler.setFontInfo(fontInfo); } } diff --git a/src/java/org/apache/fop/render/xml/XMLRenderer.java b/src/java/org/apache/fop/render/xml/XMLRenderer.java index 38db7abdf..6e03d68dd 100644 --- a/src/java/org/apache/fop/render/xml/XMLRenderer.java +++ b/src/java/org/apache/fop/render/xml/XMLRenderer.java @@ -82,7 +82,6 @@ import org.apache.fop.fo.Constants; import org.apache.fop.fo.extensions.ExtensionAttachment; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontTriplet; -import org.apache.fop.render.PrintRenderer; import org.apache.fop.render.Renderer; import org.apache.fop.render.RendererContext; import org.apache.fop.render.XMLHandler; @@ -137,7 +136,7 @@ public class XMLRenderer extends AbstractXMLRenderer { } /** {@inheritDoc} */ - public void setupFontInfo(FontInfo inFontInfo) { + public void setupFontInfo(FontInfo inFontInfo) throws FOPException { if (mimic != null) { mimic.setupFontInfo(inFontInfo); } else { diff --git a/src/java/org/apache/fop/util/DelegatingContentHandler.java b/src/java/org/apache/fop/util/DelegatingContentHandler.java index ff712a82b..8a2acba1a 100644 --- a/src/java/org/apache/fop/util/DelegatingContentHandler.java +++ b/src/java/org/apache/fop/util/DelegatingContentHandler.java @@ -56,6 +56,27 @@ public class DelegatingContentHandler } /** + * Convenience constructor. If the given handler also implements any of the EntityResolver, + * DTDHandler, LexicalHandler or ErrorHandler interfaces, these are set automatically. + * @param handler the content handler to delegate to + */ + public DelegatingContentHandler(ContentHandler handler) { + setDelegateContentHandler(handler); + if (handler instanceof EntityResolver) { + setDelegateEntityResolver((EntityResolver)handler); + } + if (handler instanceof DTDHandler) { + setDelegateDTDHandler((DTDHandler)handler); + } + if (handler instanceof LexicalHandler) { + setDelegateLexicalHandler((LexicalHandler)handler); + } + if (handler instanceof ErrorHandler) { + setDelegateErrorHandler((ErrorHandler)handler); + } + } + + /** * @return the delegate that all ContentHandler events are forwarded to */ public ContentHandler getDelegateContentHandler() { diff --git a/src/java/org/apache/fop/util/GenerationHelperContentHandler.java b/src/java/org/apache/fop/util/GenerationHelperContentHandler.java new file mode 100644 index 000000000..11a7c8f6a --- /dev/null +++ b/src/java/org/apache/fop/util/GenerationHelperContentHandler.java @@ -0,0 +1,106 @@ +/* + * 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.util; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +/** + * This class is a delegating SAX ContentHandler which has the purpose to provide a few handy + * methods that make life easier when generating SAX events. + */ +public class GenerationHelperContentHandler extends DelegatingContentHandler { + + private static final Attributes EMPTY_ATTS = new AttributesImpl(); + + private String mainNamespace; + + /** + * Main constructor. If the given handler also implements any of the EntityResolver, + * DTDHandler, LexicalHandler or ErrorHandler interfaces, these are set automatically. + * @param handler the SAX content handler to delegate all calls to + * @param mainNamespace the main namespace used for generated XML content when abbreviated + * ContentHandler calls are used. + */ + public GenerationHelperContentHandler(ContentHandler handler, String mainNamespace) { + super(handler); + this.mainNamespace = mainNamespace; + } + + /** + * Returns the main namespace used for generated XML content. + * @return the main namespace + */ + public String getMainNamespace() { + return this.mainNamespace; + } + + /** + * Sets the main namespace used for generated XML content when abbreviated ContentHandler + * calls are used. + * @param namespaceURI the new main namespace URI + */ + public void setMainNamespace(String namespaceURI) { + this.mainNamespace = namespaceURI; + } + + /** + * Convenience method to generate a startElement SAX event. + * @param localName the local name of the element + * @param atts the attributes + * @throws SAXException if a SAX exception occurs + */ + public void startElement(String localName, Attributes atts) throws SAXException { + getDelegateContentHandler().startElement(getMainNamespace(), localName, localName, atts); + } + + /** + * Convenience method to generate a startElement SAX event. + * @param localName the local name of the element + * @throws SAXException if a SAX exception occurs + */ + public void startElement(String localName) throws SAXException { + getDelegateContentHandler().startElement(getMainNamespace(), localName, localName, + EMPTY_ATTS); + } + + /** + * Convenience method to generate a endElement SAX event. + * @param localName the local name of the element + * @throws SAXException if a SAX exception occurs + */ + public void endElement(String localName) throws SAXException { + getDelegateContentHandler().endElement(getMainNamespace(), localName, localName); + } + + /** + * Convenience method to generate an empty element. + * @param localName the local name of the element + * @param atts the attributes + * @throws SAXException if a SAX exception occurs + */ + public void element(String localName, Attributes atts) throws SAXException { + getDelegateContentHandler().startElement(getMainNamespace(), localName, localName, atts); + getDelegateContentHandler().endElement(getMainNamespace(), localName, localName); + } + +} diff --git a/src/java/org/apache/fop/util/XMLUtil.java b/src/java/org/apache/fop/util/XMLUtil.java index 13784ea19..e42bef90e 100644 --- a/src/java/org/apache/fop/util/XMLUtil.java +++ b/src/java/org/apache/fop/util/XMLUtil.java @@ -24,6 +24,7 @@ import java.awt.geom.Rectangle2D; import org.xml.sax.Attributes; import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; /** * A collection of utility method for XML handling. @@ -146,4 +147,27 @@ public class XMLUtil implements XMLConstants { } } + /** + * Adds an attribute to a given {@code AttributesImpl} instance. + * @param atts the attributes collection + * @param attribute the attribute to add + * @param value the attribute's CDATA value + */ + public static void addAttribute(AttributesImpl atts, + org.apache.xmlgraphics.util.QName attribute, String value) { + atts.addAttribute(attribute.getNamespaceURI(), + attribute.getLocalName(), attribute.getQName(), XMLUtil.CDATA, value); + } + + /** + * Adds an attribute to a given {@code AttributesImpl} instance. The attribute will be + * added in the default namespace. + * @param atts the attributes collection + * @param localName the local name of the attribute + * @param value the attribute's CDATA value + */ + public static void addAttribute(AttributesImpl atts, String localName, String value) { + atts.addAttribute("", localName, localName, XMLUtil.CDATA, value); + } + } diff --git a/src/sandbox/META-INF/services/org.apache.fop.render.intermediate.IFDocumentHandler b/src/sandbox/META-INF/services/org.apache.fop.render.intermediate.IFDocumentHandler new file mode 100644 index 000000000..5ed153ac3 --- /dev/null +++ b/src/sandbox/META-INF/services/org.apache.fop.render.intermediate.IFDocumentHandler @@ -0,0 +1,2 @@ +org.apache.fop.render.svg.SVGDocumentHandlerMaker
+org.apache.fop.render.svg.SVGPrintDocumentHandlerMaker
\ No newline at end of file diff --git a/src/sandbox/META-INF/services/org.apache.fop.render.intermediate.IFPainter b/src/sandbox/META-INF/services/org.apache.fop.render.intermediate.IFPainter deleted file mode 100644 index 7913529fa..000000000 --- a/src/sandbox/META-INF/services/org.apache.fop.render.intermediate.IFPainter +++ /dev/null @@ -1,2 +0,0 @@ -org.apache.fop.render.svg.SVGPainterMaker
-org.apache.fop.render.svg.SVGPrintPainterMaker
\ No newline at end of file diff --git a/src/sandbox/org/apache/fop/render/svg/AbstractSVGDocumentHandler.java b/src/sandbox/org/apache/fop/render/svg/AbstractSVGDocumentHandler.java new file mode 100644 index 000000000..fbb6728ca --- /dev/null +++ b/src/sandbox/org/apache/fop/render/svg/AbstractSVGDocumentHandler.java @@ -0,0 +1,116 @@ +/* + * 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.svg; + +import org.xml.sax.SAXException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.xmlgraphics.xmp.Metadata; + +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.render.intermediate.AbstractXMLWritingIFDocumentHandler; +import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; +import org.apache.fop.render.intermediate.IFException; +import org.apache.fop.render.intermediate.IFState; +import org.apache.fop.render.java2d.Java2DUtil; + +/** + * Abstract base class for SVG Painter implementations. + */ +public abstract class AbstractSVGDocumentHandler extends AbstractXMLWritingIFDocumentHandler + implements SVGConstants { + + /** logging instance */ + private static Log log = LogFactory.getLog(AbstractSVGDocumentHandler.class); + + /** Font configuration */ + protected FontInfo fontInfo; + + /** Holds the intermediate format state */ + protected IFState state; + + private static final int MODE_NORMAL = 0; + private static final int MODE_TEXT = 1; + + private int mode = MODE_NORMAL; + + /** {@inheritDoc} */ + protected String getMainNamespace() { + return NAMESPACE; + } + + /** {@inheritDoc} */ + public FontInfo getFontInfo() { + return this.fontInfo; + } + + /** {@inheritDoc} */ + public void setFontInfo(FontInfo fontInfo) { + this.fontInfo = fontInfo; + } + + /** {@inheritDoc} */ + public void setDefaultFontInfo(FontInfo fontInfo) { + FontInfo fi = Java2DUtil.buildDefaultJava2DBasedFontInfo(fontInfo, getUserAgent()); + setFontInfo(fi); + } + + /** {@inheritDoc} */ + public IFDocumentHandlerConfigurator getConfigurator() { + return null; //No configurator, yet. + } + + /** {@inheritDoc} */ + public void startDocumentHeader() throws IFException { + try { + handler.startElement("defs"); + } catch (SAXException e) { + throw new IFException("SAX error in startDocumentHeader()", e); + } + } + + /** {@inheritDoc} */ + public void endDocumentHeader() throws IFException { + try { + handler.endElement("defs"); + } catch (SAXException e) { + throw new IFException("SAX error in startDocumentHeader()", e); + } + } + + /** {@inheritDoc} */ + public void handleExtensionObject(Object extension) throws IFException { + if (extension instanceof Metadata) { + Metadata meta = (Metadata)extension; + try { + handler.startElement("metadata"); + meta.toSAX(this.handler); + handler.endElement("metadata"); + } catch (SAXException e) { + throw new IFException("SAX error while handling extension object", e); + } + } else { + log.debug("Don't know how to handle extension object. Ignoring: " + + extension + " (" + extension.getClass().getName() + ")"); + } + } +} diff --git a/src/sandbox/org/apache/fop/render/svg/AbstractSVGPainter.java b/src/sandbox/org/apache/fop/render/svg/AbstractSVGPainter.java deleted file mode 100644 index 8f0be026e..000000000 --- a/src/sandbox/org/apache/fop/render/svg/AbstractSVGPainter.java +++ /dev/null @@ -1,446 +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.svg; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Paint; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.geom.AffineTransform; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Map; - -import org.w3c.dom.Document; - -import org.xml.sax.SAXException; -import org.xml.sax.helpers.AttributesImpl; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.xmlgraphics.image.loader.ImageException; -import org.apache.xmlgraphics.image.loader.ImageInfo; -import org.apache.xmlgraphics.image.loader.ImageManager; -import org.apache.xmlgraphics.image.loader.ImageSessionContext; -import org.apache.xmlgraphics.util.MimeConstants; -import org.apache.xmlgraphics.util.QName; -import org.apache.xmlgraphics.xmp.Metadata; - -import org.apache.fop.events.ResourceEventProducer; -import org.apache.fop.fo.extensions.ExtensionElementMapping; -import org.apache.fop.render.RenderingContext; -import org.apache.fop.render.intermediate.AbstractXMLWritingIFPainter; -import org.apache.fop.render.intermediate.IFConstants; -import org.apache.fop.render.intermediate.IFException; -import org.apache.fop.render.intermediate.IFState; -import org.apache.fop.traits.BorderProps; -import org.apache.fop.traits.RuleStyle; -import org.apache.fop.util.ColorUtil; - -/** - * Abstract base class for SVG Painter implementations. - */ -public abstract class AbstractSVGPainter extends AbstractXMLWritingIFPainter - implements SVGConstants { - - /** logging instance */ - private static Log log = LogFactory.getLog(AbstractSVGPainter.class); - - /** Holds the intermediate format state */ - protected IFState state; - - private static final int MODE_NORMAL = 0; - private static final int MODE_TEXT = 1; - - private int mode = MODE_NORMAL; - - /** {@inheritDoc} */ - protected String getMainNamespace() { - return NAMESPACE; - } - - /** {@inheritDoc} */ - public void startDocumentHeader() throws IFException { - try { - startElement("defs"); - } catch (SAXException e) { - throw new IFException("SAX error in startDocumentHeader()", e); - } - } - - /** {@inheritDoc} */ - public void endDocumentHeader() throws IFException { - try { - endElement("defs"); - } catch (SAXException e) { - throw new IFException("SAX error in startDocumentHeader()", e); - } - } - - /** {@inheritDoc} */ - public void startPageContent() throws IFException { - this.state = IFState.create(); - } - - /** {@inheritDoc} */ - public void endPageContent() throws IFException { - assert this.state.pop() == null; - } - - /** {@inheritDoc} */ - public void startViewport(AffineTransform transform, Dimension size, Rectangle clipRect) - throws IFException { - startViewport(toString(transform), size, clipRect); - } - - /** {@inheritDoc} */ - public void startViewport(AffineTransform[] transforms, Dimension size, Rectangle clipRect) - throws IFException { - startViewport(toString(transforms), size, clipRect); - } - - private void startViewport(String transform, Dimension size, Rectangle clipRect) - throws IFException { - try { - establish(MODE_NORMAL); - AttributesImpl atts = new AttributesImpl(); - if (transform != null && transform.length() > 0) { - atts.addAttribute("", "transform", "transform", CDATA, transform); - } - startElement("g", atts); - - atts.clear(); - atts.addAttribute("", "width", "width", CDATA, Integer.toString(size.width)); - atts.addAttribute("", "height", "height", CDATA, Integer.toString(size.height)); - if (clipRect != null) { - int[] v = new int[] { - clipRect.y, - -clipRect.x + size.width - clipRect.width, - -clipRect.y + size.height - clipRect.height, - clipRect.x}; - int sum = 0; - for (int i = 0; i < 4; i++) { - sum += Math.abs(v[i]); - } - if (sum != 0) { - StringBuffer sb = new StringBuffer("rect("); - sb.append(v[0]).append(','); - sb.append(v[1]).append(','); - sb.append(v[2]).append(','); - sb.append(v[3]).append(')'); - atts.addAttribute("", "clip", "clip", CDATA, sb.toString()); - } - atts.addAttribute("", "overflow", "overflow", CDATA, "hidden"); - } else { - atts.addAttribute("", "overflow", "overflow", CDATA, "visible"); - } - startElement("svg", atts); - } catch (SAXException e) { - throw new IFException("SAX error in startBox()", e); - } - } - - /** {@inheritDoc} */ - public void endViewport() throws IFException { - try { - establish(MODE_NORMAL); - endElement("svg"); - endElement("g"); - } catch (SAXException e) { - throw new IFException("SAX error in endBox()", e); - } - } - - /** {@inheritDoc} */ - public void startGroup(AffineTransform[] transforms) throws IFException { - startGroup(toString(transforms)); - } - - /** {@inheritDoc} */ - public void startGroup(AffineTransform transform) throws IFException { - startGroup(toString(transform)); - } - - private void startGroup(String transform) throws IFException { - try { - AttributesImpl atts = new AttributesImpl(); - if (transform != null && transform.length() > 0) { - atts.addAttribute("", "transform", "transform", CDATA, transform); - } - startElement("g", atts); - } catch (SAXException e) { - throw new IFException("SAX error in startGroup()", e); - } - } - - /** {@inheritDoc} */ - public void endGroup() throws IFException { - try { - establish(MODE_NORMAL); - endElement("g"); - } catch (SAXException e) { - throw new IFException("SAX error in endGroup()", e); - } - } - - private static final QName CONVERSION_MODE - = new QName(ExtensionElementMapping.URI, null, "conversion-mode"); - - /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle rect, Map foreignAttributes) throws IFException { - try { - establish(MODE_NORMAL); - - ImageManager manager = getUserAgent().getFactory().getImageManager(); - ImageInfo info = null; - try { - ImageSessionContext sessionContext = getUserAgent().getImageSessionContext(); - info = manager.getImageInfo(uri, sessionContext); - - String mime = info.getMimeType(); - String conversionMode = (String)foreignAttributes.get(CONVERSION_MODE); - if ("reference".equals(conversionMode) - && (MimeConstants.MIME_GIF.equals(mime) - || MimeConstants.MIME_JPEG.equals(mime) - || MimeConstants.MIME_PNG.equals(mime) - || MimeConstants.MIME_SVG.equals(mime))) { - //Just reference the image - //TODO Some additional URI rewriting might be necessary - AttributesImpl atts = new AttributesImpl(); - addAttribute(atts, IFConstants.XLINK_HREF, uri); - atts.addAttribute("", "x", "x", CDATA, Integer.toString(rect.x)); - atts.addAttribute("", "y", "y", CDATA, Integer.toString(rect.y)); - atts.addAttribute("", "width", "width", CDATA, Integer.toString(rect.width)); - atts.addAttribute("", "height", "height", CDATA, Integer.toString(rect.height)); - element("image", atts); - } else { - drawImageUsingImageHandler(info, rect); - } - } catch (ImageException ie) { - ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.imageError(this, (info != null ? info.toString() : uri), ie, null); - } catch (FileNotFoundException fe) { - ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.imageNotFound(this, (info != null ? info.toString() : uri), fe, null); - } catch (IOException ioe) { - ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.imageIOError(this, (info != null ? info.toString() : uri), ioe, null); - } - } catch (SAXException e) { - throw new IFException("SAX error in drawImage()", e); - } - } - - /** {@inheritDoc} */ - public void drawImage(Document doc, Rectangle rect, Map foreignAttributes) throws IFException { - try { - establish(MODE_NORMAL); - - drawImageUsingDocument(doc, rect); - } catch (SAXException e) { - throw new IFException("SAX error in drawImage()", e); - } - } - - /** {@inheritDoc} */ - protected RenderingContext createRenderingContext() { - SVGRenderingContext svgContext = new SVGRenderingContext( - getUserAgent(), handler); - return svgContext; - } - - private static String toString(Paint paint) { - //TODO Paint serialization: Fine-tune and extend! - if (paint instanceof Color) { - return ColorUtil.colorToString((Color)paint); - } else { - throw new UnsupportedOperationException("Paint not supported: " + paint); - } - } - - /** {@inheritDoc} */ - public void clipRect(Rectangle rect) throws IFException { - //TODO Implement me!!! - } - - /** {@inheritDoc} */ - public void fillRect(Rectangle rect, Paint fill) throws IFException { - if (fill == null) { - return; - } - try { - establish(MODE_NORMAL); - AttributesImpl atts = new AttributesImpl(); - atts.addAttribute("", "x", "x", CDATA, Integer.toString(rect.x)); - atts.addAttribute("", "y", "y", CDATA, Integer.toString(rect.y)); - atts.addAttribute("", "width", "width", CDATA, Integer.toString(rect.width)); - atts.addAttribute("", "height", "height", CDATA, Integer.toString(rect.height)); - if (fill != null) { - atts.addAttribute("", "fill", "fill", CDATA, toString(fill)); - } - /* disabled - if (stroke != null) { - atts.addAttribute("", "stroke", "stroke", CDATA, toString(stroke)); - }*/ - element("rect", atts); - } catch (SAXException e) { - throw new IFException("SAX error in fillRect()", e); - } - } - - /** {@inheritDoc} */ - public void drawBorderRect(Rectangle rect, BorderProps before, BorderProps after, - BorderProps start, BorderProps end) throws IFException { - // TODO Auto-generated method stub - } - - /** {@inheritDoc} */ - public void drawLine(Point start, Point end, int width, Color color, RuleStyle style) - throws IFException { - try { - establish(MODE_NORMAL); - AttributesImpl atts = new AttributesImpl(); - atts.addAttribute("", "x1", "x1", CDATA, Integer.toString(start.x)); - atts.addAttribute("", "y1", "y1", CDATA, Integer.toString(start.y)); - atts.addAttribute("", "x2", "x2", CDATA, Integer.toString(end.x)); - atts.addAttribute("", "y2", "y2", CDATA, Integer.toString(end.y)); - atts.addAttribute("", "stroke-width", "stroke-width", CDATA, toString(color)); - atts.addAttribute("", "fill", "fill", CDATA, toString(color)); - //TODO Handle style parameter - element("line", atts); - } catch (SAXException e) { - throw new IFException("SAX error in drawLine()", e); - } - } - - /** {@inheritDoc} */ - public void drawText(int x, int y, int[] dx, int[] dy, String text) throws IFException { - try { - establish(MODE_TEXT); - AttributesImpl atts = new AttributesImpl(); - atts.addAttribute("", "x", "x", CDATA, Integer.toString(x)); - atts.addAttribute("", "y", "y", CDATA, Integer.toString(y)); - if (dx != null) { - atts.addAttribute("", "dx", "dx", CDATA, toString(dx)); - } - if (dy != null) { - atts.addAttribute("", "dy", "dy", CDATA, toString(dy)); - } - startElement("text", atts); - char[] chars = text.toCharArray(); - handler.characters(chars, 0, chars.length); - endElement("text"); - } catch (SAXException e) { - throw new IFException("SAX error in setFont()", e); - } - } - - /** {@inheritDoc} */ - public void setFont(String family, String style, Integer weight, String variant, Integer size, - Color color) throws IFException { - if (family != null) { - state.setFontFamily(family); - } - if (style != null) { - state.setFontStyle(style); - } - if (weight != null) { - state.setFontWeight(weight.intValue()); - } - if (variant != null) { - state.setFontVariant(variant); - } - if (size != null) { - state.setFontSize(size.intValue()); - } - if (color != null) { - state.setTextColor(color); - } - } - - private void leaveTextMode() throws SAXException { - assert this.mode == MODE_TEXT; - endElement("g"); - this.mode = MODE_NORMAL; - } - - private void establish(int newMode) throws SAXException { - switch (newMode) { - case MODE_TEXT: - enterTextMode(); - break; - default: - if (this.mode == MODE_TEXT) { - leaveTextMode(); - } - } - } - - private void enterTextMode() throws SAXException { - if (state.isFontChanged() && this.mode == MODE_TEXT) { - leaveTextMode(); - } - if (this.mode != MODE_TEXT) { - startTextGroup(); - this.mode = MODE_TEXT; - } - } - - private void startTextGroup() throws SAXException { - AttributesImpl atts = new AttributesImpl(); - atts.addAttribute("", "font-family", "font-family", - CDATA, state.getFontFamily()); - atts.addAttribute("", "font-style", "font-style", - CDATA, state.getFontStyle()); - atts.addAttribute("", "font-weight", "font-weight", - CDATA, Integer.toString(state.getFontWeight())); - atts.addAttribute("", "font-variant", "font-variant", - CDATA, state.getFontVariant()); - atts.addAttribute("", "font-size", "font-size", - CDATA, Integer.toString(state.getFontSize())); - atts.addAttribute("", "fill", "fill", - CDATA, toString(state.getTextColor())); - startElement("g", atts); - state.resetFontChanged(); - } - - /** {@inheritDoc} */ - public void handleExtensionObject(Object extension) throws IFException { - if (extension instanceof Metadata) { - Metadata meta = (Metadata)extension; - try { - establish(MODE_NORMAL); - startElement("metadata"); - meta.toSAX(this.handler); - endElement("metadata"); - } catch (SAXException e) { - throw new IFException("SAX error while handling extension object", e); - } - } else { - throw new UnsupportedOperationException( - "Don't know how to handle extension object: " + extension); - } - } -} diff --git a/src/sandbox/org/apache/fop/render/svg/SVGDocumentHandler.java b/src/sandbox/org/apache/fop/render/svg/SVGDocumentHandler.java new file mode 100644 index 000000000..bd3dbc4e1 --- /dev/null +++ b/src/sandbox/org/apache/fop/render/svg/SVGDocumentHandler.java @@ -0,0 +1,272 @@ +/* + * 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.svg; + +import java.awt.Dimension; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.sax.TransformerHandler; +import javax.xml.transform.stream.StreamResult; + +import org.w3c.dom.Document; + +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +import org.apache.commons.io.IOUtils; + +import org.apache.fop.render.bitmap.MultiFileRenderingUtil; +import org.apache.fop.render.intermediate.DelegatingFragmentContentHandler; +import org.apache.fop.render.intermediate.IFException; +import org.apache.fop.render.intermediate.IFPainter; +import org.apache.fop.util.GenerationHelperContentHandler; +import org.apache.fop.util.XMLUtil; + +/** + * {@code IFDocumentHandler} implementation that writes SVG 1.1. + */ +public class SVGDocumentHandler extends AbstractSVGDocumentHandler { + + /** Helper class for generating multiple files */ + private MultiFileRenderingUtil multiFileUtil; + + private StreamResult firstStream; + private StreamResult currentStream; + + private Document reusedParts; + + /** + * Default constructor. + */ + public SVGDocumentHandler() { + //nop + } + + /** {@inheritDoc} */ + public boolean supportsPagesOutOfOrder() { + return true; + } + + /** {@inheritDoc} */ + public String getMimeType() { + return MIME_TYPE; + } + + /** {@inheritDoc} */ + public void setResult(Result result) throws IFException { + if (result instanceof StreamResult) { + multiFileUtil = new MultiFileRenderingUtil(FILE_EXTENSION_SVG, + getUserAgent().getOutputFile()); + this.firstStream = (StreamResult)result; + } else { + throw new UnsupportedOperationException("Result is not supported: " + result); + } + } + + /** {@inheritDoc} */ + public void startDocument() throws IFException { + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + builderFactory.setNamespaceAware(true); + builderFactory.setValidating(false); + try { + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + this.reusedParts = builder.newDocument(); + } catch (ParserConfigurationException e) { + throw new IFException("Error while setting up a DOM for SVG generation", e); + } + + try { + TransformerHandler toDOMHandler = tFactory.newTransformerHandler(); + toDOMHandler.setResult(new DOMResult(this.reusedParts)); + this.handler = decorate(toDOMHandler); + this.handler.startDocument(); + } catch (SAXException se) { + throw new IFException("SAX error in startDocument()", se); + } catch (TransformerConfigurationException e) { + throw new IFException( + "Error while setting up a TransformerHandler for SVG generation", e); + } + } + + /** {@inheritDoc} */ + public void endDocument() throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void endDocumentHeader() throws IFException { + super.endDocumentHeader(); + try { + //Stop recording parts reused for each page + this.handler.endDocument(); + this.handler = null; + } catch (SAXException e) { + throw new IFException("SAX error in endDocumentHeader()", e); + } + } + + /** {@inheritDoc} */ + public void startPageSequence(String id) throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void endPageSequence() throws IFException { + //nop + } + + /** {@inheritDoc} */ + public void startPage(int index, String name, Dimension size) throws IFException { + OutputStream out; + try { + if (index == 0) { + out = null; + } else { + out = this.multiFileUtil.createOutputStream(index); + if (out == null) { + //TODO Convert to event + throw new IFException( + "No filename information available. Stopping after first page.", null); + } + } + } catch (IOException ioe) { + throw new IFException("I/O exception while setting up output file", ioe); + } + if (out == null) { + this.handler = decorate(createContentHandler(this.firstStream)); + } else { + this.currentStream = new StreamResult(out); + this.handler = decorate(createContentHandler(this.currentStream)); + } + if (false) { + final ContentHandler originalHandler = this.handler; + this.handler = decorate((ContentHandler)Proxy.newProxyInstance( + ContentHandler.class.getClassLoader(), + new Class[] {ContentHandler.class}, + new InvocationHandler() { + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + String methodName = method.getName(); + System.out.println(methodName + ":"); + if (args != null) { + for (int i = 0; i < args.length; i++) { + System.out.println(" " + args[i]); + } + } + return method.invoke(originalHandler, args); + } + })); + } + try { + handler.startDocument(); + handler.startPrefixMapping("", NAMESPACE); + handler.startPrefixMapping(XLINK_PREFIX, XLINK_NAMESPACE); + AttributesImpl atts = new AttributesImpl(); + XMLUtil.addAttribute(atts, "version", "1.1"); //SVG 1.1 + /* + XMLUtil.addAttribute(atts, "index", Integer.toString(index)); + XMLUtil.addAttribute(atts, "name", name); + */ + XMLUtil.addAttribute(atts, "width", Float.toString(size.width / 1000f) + "pt"); + XMLUtil.addAttribute(atts, "height", Float.toString(size.height / 1000f) + "pt"); + XMLUtil.addAttribute(atts, "viewBox", + "0 0 " + Integer.toString(size.width) + " " + Integer.toString(size.height)); + handler.startElement("svg", atts); + + try { + Transformer transformer = tFactory.newTransformer(); + Source src = new DOMSource(this.reusedParts.getDocumentElement()); + Result res = new SAXResult(new DelegatingFragmentContentHandler(this.handler)); + transformer.transform(src, res); + } catch (TransformerConfigurationException tce) { + throw new IFException("Error setting up a Transformer", tce); + } catch (TransformerException te) { + if (te.getCause() instanceof SAXException) { + throw (SAXException)te.getCause(); + } else { + throw new IFException("Error while serializing reused parts", te); + } + } + } catch (SAXException e) { + throw new IFException("SAX error in startPage()", e); + } + } + + private GenerationHelperContentHandler decorate(ContentHandler contentHandler) { + return new GenerationHelperContentHandler(contentHandler, getMainNamespace()); + } + + private void closeCurrentStream() { + if (this.currentStream != null) { + IOUtils.closeQuietly(currentStream.getOutputStream()); + currentStream.setOutputStream(null); + IOUtils.closeQuietly(currentStream.getWriter()); + currentStream.setWriter(null); + this.currentStream = null; + } + } + + /** {@inheritDoc} */ + public IFPainter startPageContent() throws IFException { + try { + handler.startElement("g"); + } catch (SAXException e) { + throw new IFException("SAX error in startPageContent()", e); + } + return new SVGPainter(this, handler); + } + + /** {@inheritDoc} */ + public void endPageContent() throws IFException { + try { + handler.endElement("g"); + } catch (SAXException e) { + throw new IFException("SAX error in endPageContent()", e); + } + } + + /** {@inheritDoc} */ + public void endPage() throws IFException { + try { + handler.endElement("svg"); + this.handler.endDocument(); + } catch (SAXException e) { + throw new IFException("SAX error in endPage()", e); + } + closeCurrentStream(); + } + +} diff --git a/src/sandbox/org/apache/fop/render/svg/SVGPainterMaker.java b/src/sandbox/org/apache/fop/render/svg/SVGDocumentHandlerMaker.java index a25a2f3b7..0296135fd 100644 --- a/src/sandbox/org/apache/fop/render/svg/SVGPainterMaker.java +++ b/src/sandbox/org/apache/fop/render/svg/SVGDocumentHandlerMaker.java @@ -20,20 +20,22 @@ package org.apache.fop.render.svg; import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.render.intermediate.AbstractIFPainterMaker; -import org.apache.fop.render.intermediate.IFPainter; -import org.apache.fop.render.intermediate.IFPainterConfigurator; +import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker; +import org.apache.fop.render.intermediate.IFDocumentHandler; +import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; /** - * Painter factory for SVG output. + * Document handler factory for SVG output. */ -public class SVGPainterMaker extends AbstractIFPainterMaker { +public class SVGDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { private static final String[] MIMES = new String[] {SVGConstants.MIME_TYPE}; /** {@inheritDoc} */ - public IFPainter makePainter(FOUserAgent ua) { - return new SVGPainter(); + public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { + SVGDocumentHandler handler = new SVGDocumentHandler(); + handler.setUserAgent(ua); + return handler; } /** {@inheritDoc} */ @@ -47,8 +49,7 @@ public class SVGPainterMaker extends AbstractIFPainterMaker { } /** {@inheritDoc} */ - public IFPainterConfigurator getConfigurator(FOUserAgent userAgent) { - // TODO Auto-generated method stub + public IFDocumentHandlerConfigurator getConfigurator(FOUserAgent userAgent) { return null; } diff --git a/src/sandbox/org/apache/fop/render/svg/SVGPainter.java b/src/sandbox/org/apache/fop/render/svg/SVGPainter.java index aa52673a9..e0d12d9c7 100644 --- a/src/sandbox/org/apache/fop/render/svg/SVGPainter.java +++ b/src/sandbox/org/apache/fop/render/svg/SVGPainter.java @@ -19,250 +19,416 @@ package org.apache.fop.render.svg; +import java.awt.Color; import java.awt.Dimension; +import java.awt.Paint; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.io.FileNotFoundException; import java.io.IOException; -import java.io.OutputStream; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerException; -import javax.xml.transform.dom.DOMResult; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.sax.SAXResult; -import javax.xml.transform.sax.TransformerHandler; -import javax.xml.transform.stream.StreamResult; +import java.util.Map; import org.w3c.dom.Document; -import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; -import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; -import org.apache.fop.render.bitmap.MultiFileRenderingUtil; -import org.apache.fop.render.intermediate.DelegatingFragmentContentHandler; +import org.apache.xmlgraphics.image.loader.ImageException; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.ImageManager; +import org.apache.xmlgraphics.image.loader.ImageSessionContext; +import org.apache.xmlgraphics.util.QName; +import org.apache.xmlgraphics.xmp.Metadata; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.MimeConstants; +import org.apache.fop.events.ResourceEventProducer; +import org.apache.fop.fo.extensions.ExtensionElementMapping; +import org.apache.fop.render.RenderingContext; +import org.apache.fop.render.intermediate.AbstractIFPainter; +import org.apache.fop.render.intermediate.IFConstants; import org.apache.fop.render.intermediate.IFException; +import org.apache.fop.render.intermediate.IFState; +import org.apache.fop.render.intermediate.IFUtil; +import org.apache.fop.traits.BorderProps; +import org.apache.fop.traits.RuleStyle; +import org.apache.fop.util.ColorUtil; +import org.apache.fop.util.GenerationHelperContentHandler; +import org.apache.fop.util.XMLUtil; /** * IFPainter implementation that writes SVG. */ -public class SVGPainter extends AbstractSVGPainter { +public class SVGPainter extends AbstractIFPainter implements SVGConstants { + + /** logging instance */ + private static Log log = LogFactory.getLog(SVGPainter.class); + + /** Holds the intermediate format state */ + protected IFState state; - /** Helper class for generating multiple files */ - private MultiFileRenderingUtil multiFileUtil; + private AbstractSVGDocumentHandler parent; - private StreamResult firstStream; - private StreamResult currentStream; + /** The SAX content handler that receives the generated XML events. */ + protected GenerationHelperContentHandler handler; - private Document reusedParts; + private static final int MODE_NORMAL = 0; + private static final int MODE_TEXT = 1; + + private int mode = MODE_NORMAL; /** - * Default constructor. + * Main constructor. + * @param parent the parent document handler + * @param contentHandler the target SAX content handler */ - public SVGPainter() { - //nop + public SVGPainter(AbstractSVGDocumentHandler parent, + GenerationHelperContentHandler contentHandler) { + super(); + this.parent = parent; + this.handler = contentHandler; + this.state = IFState.create(); } /** {@inheritDoc} */ - public boolean supportsPagesOutOfOrder() { - return true; + protected FOUserAgent getUserAgent() { + return parent.getUserAgent(); } /** {@inheritDoc} */ - public String getMimeType() { - return MIME_TYPE; + public void startViewport(AffineTransform transform, Dimension size, Rectangle clipRect) + throws IFException { + startViewport(IFUtil.toString(transform), size, clipRect); } /** {@inheritDoc} */ - public void setResult(Result result) throws IFException { - if (result instanceof StreamResult) { - multiFileUtil = new MultiFileRenderingUtil(FILE_EXTENSION_SVG, - getUserAgent().getOutputFile()); - this.firstStream = (StreamResult)result; - } else { - throw new UnsupportedOperationException("Result is not supported: " + result); - } + public void startViewport(AffineTransform[] transforms, Dimension size, Rectangle clipRect) + throws IFException { + startViewport(IFUtil.toString(transforms), size, clipRect); } - /** {@inheritDoc} */ - public void startDocument() throws IFException { - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - builderFactory.setNamespaceAware(true); - builderFactory.setValidating(false); + private void startViewport(String transform, Dimension size, Rectangle clipRect) + throws IFException { try { - DocumentBuilder builder = builderFactory.newDocumentBuilder(); - this.reusedParts = builder.newDocument(); - } catch (ParserConfigurationException e) { - throw new IFException("Error while setting up a DOM for SVG generation", e); + establish(MODE_NORMAL); + AttributesImpl atts = new AttributesImpl(); + if (transform != null && transform.length() > 0) { + XMLUtil.addAttribute(atts, "transform", transform); + } + handler.startElement("g", atts); + + atts.clear(); + XMLUtil.addAttribute(atts, "width", Integer.toString(size.width)); + XMLUtil.addAttribute(atts, "height", Integer.toString(size.height)); + if (clipRect != null) { + int[] v = new int[] { + clipRect.y, + -clipRect.x + size.width - clipRect.width, + -clipRect.y + size.height - clipRect.height, + clipRect.x}; + int sum = 0; + for (int i = 0; i < 4; i++) { + sum += Math.abs(v[i]); + } + if (sum != 0) { + StringBuffer sb = new StringBuffer("rect("); + sb.append(v[0]).append(','); + sb.append(v[1]).append(','); + sb.append(v[2]).append(','); + sb.append(v[3]).append(')'); + XMLUtil.addAttribute(atts, "clip", sb.toString()); + } + XMLUtil.addAttribute(atts, "overflow", "hidden"); + } else { + XMLUtil.addAttribute(atts, "overflow", "visible"); + } + handler.startElement("svg", atts); + } catch (SAXException e) { + throw new IFException("SAX error in startBox()", e); } + } + /** {@inheritDoc} */ + public void endViewport() throws IFException { try { - TransformerHandler toDOMHandler = tFactory.newTransformerHandler(); - toDOMHandler.setResult(new DOMResult(this.reusedParts)); - this.handler = toDOMHandler; - this.handler.startDocument(); - } catch (SAXException se) { - throw new IFException("SAX error in startDocument()", se); - } catch (TransformerConfigurationException e) { - throw new IFException( - "Error while setting up a TransformerHandler for SVG generation", e); + establish(MODE_NORMAL); + handler.endElement("svg"); + handler.endElement("g"); + } catch (SAXException e) { + throw new IFException("SAX error in endBox()", e); } } /** {@inheritDoc} */ - public void endDocument() throws IFException { - //nop + public void startGroup(AffineTransform[] transforms) throws IFException { + startGroup(IFUtil.toString(transforms)); } /** {@inheritDoc} */ - public void endDocumentHeader() throws IFException { - super.endDocumentHeader(); + public void startGroup(AffineTransform transform) throws IFException { + startGroup(IFUtil.toString(transform)); + } + + private void startGroup(String transform) throws IFException { try { - //Stop recording parts reused for each page - this.handler.endDocument(); - this.handler = null; + AttributesImpl atts = new AttributesImpl(); + if (transform != null && transform.length() > 0) { + XMLUtil.addAttribute(atts, "transform", transform); + } + handler.startElement("g", atts); } catch (SAXException e) { - throw new IFException("SAX error in endDocumentHeader()", e); + throw new IFException("SAX error in startGroup()", e); } } /** {@inheritDoc} */ - public void startPageSequence(String id) throws IFException { - //nop + public void endGroup() throws IFException { + try { + establish(MODE_NORMAL); + handler.endElement("g"); + } catch (SAXException e) { + throw new IFException("SAX error in endGroup()", e); + } } - /** {@inheritDoc} */ - public void endPageSequence() throws IFException { - //nop - } + private static final QName CONVERSION_MODE + = new QName(ExtensionElementMapping.URI, null, "conversion-mode"); /** {@inheritDoc} */ - public void startPage(int index, String name, Dimension size) throws IFException { - OutputStream out; + public void drawImage(String uri, Rectangle rect, Map foreignAttributes) throws IFException { try { - if (index == 0) { - out = null; - } else { - out = this.multiFileUtil.createOutputStream(index); - if (out == null) { - //TODO Convert to event - throw new IFException( - "No filename information available. Stopping after first page.", null); + establish(MODE_NORMAL); + + ImageManager manager = getUserAgent().getFactory().getImageManager(); + ImageInfo info = null; + try { + ImageSessionContext sessionContext = getUserAgent().getImageSessionContext(); + info = manager.getImageInfo(uri, sessionContext); + + String mime = info.getMimeType(); + String conversionMode = (String)foreignAttributes.get(CONVERSION_MODE); + if ("reference".equals(conversionMode) + && (MimeConstants.MIME_GIF.equals(mime) + || MimeConstants.MIME_JPEG.equals(mime) + || MimeConstants.MIME_PNG.equals(mime) + || MimeConstants.MIME_SVG.equals(mime))) { + //Just reference the image + //TODO Some additional URI rewriting might be necessary + AttributesImpl atts = new AttributesImpl(); + XMLUtil.addAttribute(atts, IFConstants.XLINK_HREF, uri); + XMLUtil.addAttribute(atts, "x", Integer.toString(rect.x)); + XMLUtil.addAttribute(atts, "y", Integer.toString(rect.y)); + XMLUtil.addAttribute(atts, "width", Integer.toString(rect.width)); + XMLUtil.addAttribute(atts, "height", Integer.toString(rect.height)); + handler.element("image", atts); + } else { + drawImageUsingImageHandler(info, rect); } + } catch (ImageException ie) { + ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.imageError(this, (info != null ? info.toString() : uri), ie, null); + } catch (FileNotFoundException fe) { + ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.imageNotFound(this, (info != null ? info.toString() : uri), fe, null); + } catch (IOException ioe) { + ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.imageIOError(this, (info != null ? info.toString() : uri), ioe, null); } - } catch (IOException ioe) { - throw new IFException("I/O exception while setting up output file", ioe); + } catch (SAXException e) { + throw new IFException("SAX error in drawImage()", e); } - if (out == null) { - this.handler = createContentHandler(this.firstStream); + } + + /** {@inheritDoc} */ + public void drawImage(Document doc, Rectangle rect, Map foreignAttributes) throws IFException { + try { + establish(MODE_NORMAL); + + drawImageUsingDocument(doc, rect); + } catch (SAXException e) { + throw new IFException("SAX error in drawImage()", e); + } + } + + /** {@inheritDoc} */ + protected RenderingContext createRenderingContext() { + SVGRenderingContext svgContext = new SVGRenderingContext( + getUserAgent(), handler); + return svgContext; + } + + private static String toString(Paint paint) { + //TODO Paint serialization: Fine-tune and extend! + if (paint instanceof Color) { + return ColorUtil.colorToString((Color)paint); } else { - this.currentStream = new StreamResult(out); - this.handler = createContentHandler(this.currentStream); + throw new UnsupportedOperationException("Paint not supported: " + paint); } - if (false) { - final ContentHandler originalHandler = this.handler; - this.handler = (ContentHandler)Proxy.newProxyInstance( - ContentHandler.class.getClassLoader(), - new Class[] {ContentHandler.class}, - new InvocationHandler() { - public Object invoke(Object proxy, Method method, Object[] args) - throws Throwable { - String methodName = method.getName(); - System.out.println(methodName + ":"); - if (args != null) { - for (int i = 0; i < args.length; i++) { - System.out.println(" " + args[i]); - } - } - return method.invoke(originalHandler, args); - } - }); + } + + /** {@inheritDoc} */ + public void clipRect(Rectangle rect) throws IFException { + //TODO Implement me!!! + } + + /** {@inheritDoc} */ + public void fillRect(Rectangle rect, Paint fill) throws IFException { + if (fill == null) { + return; } try { - handler.startDocument(); - handler.startPrefixMapping("", NAMESPACE); - handler.startPrefixMapping(XLINK_PREFIX, XLINK_NAMESPACE); + establish(MODE_NORMAL); AttributesImpl atts = new AttributesImpl(); - atts.addAttribute("", "version", "version", CDATA, "1.1"); //SVG 1.1 - /* - atts.addAttribute("", "index", "index", CDATA, Integer.toString(index)); - atts.addAttribute("", "name", "name", CDATA, name); - */ - atts.addAttribute("", "width", "width", CDATA, - Float.toString(size.width / 1000f) + "pt"); - atts.addAttribute("", "height", "height", CDATA, - Float.toString(size.height / 1000f) + "pt"); - atts.addAttribute("", "viewBox", "viewBox", CDATA, - "0 0 " + Integer.toString(size.width) + " " + Integer.toString(size.height)); - startElement("svg", atts); - - try { - Transformer transformer = tFactory.newTransformer(); - Source src = new DOMSource(this.reusedParts.getDocumentElement()); - Result res = new SAXResult(new DelegatingFragmentContentHandler(this.handler)); - transformer.transform(src, res); - } catch (TransformerConfigurationException tce) { - throw new IFException("Error setting up a Transformer", tce); - } catch (TransformerException te) { - if (te.getCause() instanceof SAXException) { - throw (SAXException)te.getCause(); - } else { - throw new IFException("Error while serializing reused parts", te); - } + XMLUtil.addAttribute(atts, "x", Integer.toString(rect.x)); + XMLUtil.addAttribute(atts, "y", Integer.toString(rect.y)); + XMLUtil.addAttribute(atts, "width", Integer.toString(rect.width)); + XMLUtil.addAttribute(atts, "height", Integer.toString(rect.height)); + if (fill != null) { + XMLUtil.addAttribute(atts, "fill", toString(fill)); } + /* disabled + if (stroke != null) { + XMLUtil.addAttribute(atts, "stroke", toString(stroke)); + }*/ + handler.element("rect", atts); } catch (SAXException e) { - throw new IFException("SAX error in startPage()", e); + throw new IFException("SAX error in fillRect()", e); } } - private void closeCurrentStream() { - if (this.currentStream != null) { - IOUtils.closeQuietly(currentStream.getOutputStream()); - currentStream.setOutputStream(null); - IOUtils.closeQuietly(currentStream.getWriter()); - currentStream.setWriter(null); - this.currentStream = null; - } + /** {@inheritDoc} */ + public void drawBorderRect(Rectangle rect, BorderProps before, BorderProps after, + BorderProps start, BorderProps end) throws IFException { + // TODO Auto-generated method stub } /** {@inheritDoc} */ - public void startPageContent() throws IFException { - super.startPageContent(); + public void drawLine(Point start, Point end, int width, Color color, RuleStyle style) + throws IFException { try { - startElement("g"); + establish(MODE_NORMAL); + AttributesImpl atts = new AttributesImpl(); + XMLUtil.addAttribute(atts, "x1", Integer.toString(start.x)); + XMLUtil.addAttribute(atts, "y1", Integer.toString(start.y)); + XMLUtil.addAttribute(atts, "x2", Integer.toString(end.x)); + XMLUtil.addAttribute(atts, "y2", Integer.toString(end.y)); + XMLUtil.addAttribute(atts, "stroke-width", toString(color)); + XMLUtil.addAttribute(atts, "fill", toString(color)); + //TODO Handle style parameter + handler.element("line", atts); } catch (SAXException e) { - throw new IFException("SAX error in startPageContent()", e); + throw new IFException("SAX error in drawLine()", e); } } /** {@inheritDoc} */ - public void endPageContent() throws IFException { + public void drawText(int x, int y, int[] dx, int[] dy, String text) throws IFException { try { - endElement("g"); + establish(MODE_TEXT); + AttributesImpl atts = new AttributesImpl(); + XMLUtil.addAttribute(atts, "x", Integer.toString(x)); + XMLUtil.addAttribute(atts, "y", Integer.toString(y)); + if (dx != null) { + XMLUtil.addAttribute(atts, "dx", IFUtil.toString(dx)); + } + if (dy != null) { + XMLUtil.addAttribute(atts, "dy", IFUtil.toString(dy)); + } + handler.startElement("text", atts); + char[] chars = text.toCharArray(); + handler.characters(chars, 0, chars.length); + handler.endElement("text"); } catch (SAXException e) { - throw new IFException("SAX error in endPageContent()", e); + throw new IFException("SAX error in setFont()", e); } - super.endPageContent(); } /** {@inheritDoc} */ - public void endPage() throws IFException { - try { - endElement("svg"); - this.handler.endDocument(); - } catch (SAXException e) { - throw new IFException("SAX error in endPage()", e); + public void setFont(String family, String style, Integer weight, String variant, Integer size, + Color color) throws IFException { + if (family != null) { + state.setFontFamily(family); + } + if (style != null) { + state.setFontStyle(style); + } + if (weight != null) { + state.setFontWeight(weight.intValue()); + } + if (variant != null) { + state.setFontVariant(variant); + } + if (size != null) { + state.setFontSize(size.intValue()); + } + if (color != null) { + state.setTextColor(color); + } + } + + private void leaveTextMode() throws SAXException { + assert this.mode == MODE_TEXT; + handler.endElement("g"); + this.mode = MODE_NORMAL; + } + + private void establish(int newMode) throws SAXException { + switch (newMode) { + case MODE_TEXT: + enterTextMode(); + break; + default: + if (this.mode == MODE_TEXT) { + leaveTextMode(); + } + } + } + + private void enterTextMode() throws SAXException { + if (state.isFontChanged() && this.mode == MODE_TEXT) { + leaveTextMode(); + } + if (this.mode != MODE_TEXT) { + startTextGroup(); + this.mode = MODE_TEXT; + } + } + + private void startTextGroup() throws SAXException { + AttributesImpl atts = new AttributesImpl(); + XMLUtil.addAttribute(atts, "font-family", state.getFontFamily()); + XMLUtil.addAttribute(atts, "font-style", state.getFontStyle()); + XMLUtil.addAttribute(atts, "font-weight", Integer.toString(state.getFontWeight())); + XMLUtil.addAttribute(atts, "font-variant", state.getFontVariant()); + XMLUtil.addAttribute(atts, "font-size", Integer.toString(state.getFontSize())); + XMLUtil.addAttribute(atts, "fill", toString(state.getTextColor())); + handler.startElement("g", atts); + state.resetFontChanged(); + } + + /** {@inheritDoc} */ + public void handleExtensionObject(Object extension) throws IFException { + if (extension instanceof Metadata) { + Metadata meta = (Metadata)extension; + try { + establish(MODE_NORMAL); + handler.startElement("metadata"); + meta.toSAX(this.handler); + handler.endElement("metadata"); + } catch (SAXException e) { + throw new IFException("SAX error while handling extension object", e); + } + } else { + throw new UnsupportedOperationException( + "Don't know how to handle extension object: " + extension); } - closeCurrentStream(); } } diff --git a/src/sandbox/org/apache/fop/render/svg/SVGPrintPainter.java b/src/sandbox/org/apache/fop/render/svg/SVGPrintDocumentHandler.java index 7f5c84cef..ee69f95ae 100644 --- a/src/sandbox/org/apache/fop/render/svg/SVGPrintPainter.java +++ b/src/sandbox/org/apache/fop/render/svg/SVGPrintDocumentHandler.java @@ -28,16 +28,18 @@ import org.xml.sax.helpers.AttributesImpl; import org.apache.fop.render.intermediate.IFConstants; import org.apache.fop.render.intermediate.IFException; +import org.apache.fop.render.intermediate.IFPainter; +import org.apache.fop.util.XMLUtil; /** - * IFPainter implementation that writes SVG Print. + * {@code IFDocumentHandler} implementation that writes SVG Print. */ -public class SVGPrintPainter extends AbstractSVGPainter { +public class SVGPrintDocumentHandler extends AbstractSVGDocumentHandler { /** * Default constructor. */ - public SVGPrintPainter() { + public SVGPrintDocumentHandler() { //nop } @@ -47,7 +49,7 @@ public class SVGPrintPainter extends AbstractSVGPainter { * @param result the JAXP Result object to receive the generated content * @throws IFException if an error occurs setting up the output */ - public SVGPrintPainter(Result result) throws IFException { + public SVGPrintDocumentHandler(Result result) throws IFException { setResult(result); } @@ -69,8 +71,8 @@ public class SVGPrintPainter extends AbstractSVGPainter { handler.startPrefixMapping(XLINK_PREFIX, XLINK_NAMESPACE); handler.startPrefixMapping("if", IFConstants.NAMESPACE); AttributesImpl atts = new AttributesImpl(); - atts.addAttribute("", "version", "version", CDATA, "1.2"); //SVG Print is SVG 1.2 - startElement("svg", atts); + XMLUtil.addAttribute(atts, "version", "1.2"); //SVG Print is SVG 1.2 + handler.startElement("svg", atts); } catch (SAXException e) { throw new IFException("SAX error in startDocument()", e); } @@ -79,7 +81,7 @@ public class SVGPrintPainter extends AbstractSVGPainter { /** {@inheritDoc} */ public void endDocument() throws IFException { try { - endElement("svg"); + handler.endElement("svg"); handler.endDocument(); } catch (SAXException e) { throw new IFException("SAX error in endDocument()", e); @@ -93,7 +95,7 @@ public class SVGPrintPainter extends AbstractSVGPainter { if (id != null) { atts.addAttribute(XML_NAMESPACE, "id", "xml:id", CDATA, id); } - startElement("pageSet", atts); + handler.startElement("pageSet", atts); } catch (SAXException e) { throw new IFException("SAX error in startPageSequence()", e); } @@ -102,7 +104,7 @@ public class SVGPrintPainter extends AbstractSVGPainter { /** {@inheritDoc} */ public void endPageSequence() throws IFException { try { - endElement("pageSet"); + handler.endElement("pageSet"); } catch (SAXException e) { throw new IFException("SAX error in endPageSequence()", e); } @@ -113,8 +115,8 @@ public class SVGPrintPainter extends AbstractSVGPainter { try { AttributesImpl atts = new AttributesImpl(); /* - atts.addAttribute("", "index", "index", CDATA, Integer.toString(index)); - atts.addAttribute("", "name", "name", CDATA, name); + XMLUtil.addAttribute(atts, "index", Integer.toString(index)); + XMLUtil.addAttribute(atts, "name", name); */ //NOTE: SVG Print doesn't support individual page sizes for each page atts.addAttribute(IFConstants.NAMESPACE, "width", "if:width", @@ -123,7 +125,7 @@ public class SVGPrintPainter extends AbstractSVGPainter { CDATA, Integer.toString(size.height)); atts.addAttribute(IFConstants.NAMESPACE, "viewBox", "if:viewBox", CDATA, "0 0 " + Integer.toString(size.width) + " " + Integer.toString(size.height)); - startElement("page", atts); + handler.startElement("page", atts); } catch (SAXException e) { throw new IFException("SAX error in startPage()", e); } @@ -138,23 +140,22 @@ public class SVGPrintPainter extends AbstractSVGPainter { } /** {@inheritDoc} */ - public void startPageContent() throws IFException { - super.startPageContent(); + public IFPainter startPageContent() throws IFException { try { - startElement("g"); + handler.startElement("g"); } catch (SAXException e) { throw new IFException("SAX error in startPageContent()", e); } + return new SVGPainter(this, handler); } /** {@inheritDoc} */ public void endPageContent() throws IFException { try { - endElement("g"); + handler.endElement("g"); } catch (SAXException e) { throw new IFException("SAX error in endPageContent()", e); } - super.endPageContent(); } /** {@inheritDoc} */ @@ -168,7 +169,7 @@ public class SVGPrintPainter extends AbstractSVGPainter { /** {@inheritDoc} */ public void endPage() throws IFException { try { - endElement("page"); + handler.endElement("page"); } catch (SAXException e) { throw new IFException("SAX error in endPage()", e); } diff --git a/src/sandbox/org/apache/fop/render/svg/SVGPrintPainterMaker.java b/src/sandbox/org/apache/fop/render/svg/SVGPrintDocumentHandlerMaker.java index 55a7bf753..61993da13 100644 --- a/src/sandbox/org/apache/fop/render/svg/SVGPrintPainterMaker.java +++ b/src/sandbox/org/apache/fop/render/svg/SVGPrintDocumentHandlerMaker.java @@ -20,20 +20,22 @@ package org.apache.fop.render.svg; import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.render.intermediate.AbstractIFPainterMaker; -import org.apache.fop.render.intermediate.IFPainter; -import org.apache.fop.render.intermediate.IFPainterConfigurator; +import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker; +import org.apache.fop.render.intermediate.IFDocumentHandler; +import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; /** - * Painter factory for SVG Print output. + * Document handler factory for SVG Print output. */ -public class SVGPrintPainterMaker extends AbstractIFPainterMaker { +public class SVGPrintDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { private static final String[] MIMES = new String[] {SVGConstants.MIME_SVG_PRINT}; /** {@inheritDoc} */ - public IFPainter makePainter(FOUserAgent ua) { - return new SVGPrintPainter(); + public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { + SVGPrintDocumentHandler handler = new SVGPrintDocumentHandler(); + handler.setUserAgent(ua); + return handler; } /** {@inheritDoc} */ @@ -47,8 +49,7 @@ public class SVGPrintPainterMaker extends AbstractIFPainterMaker { } /** {@inheritDoc} */ - public IFPainterConfigurator getConfigurator(FOUserAgent userAgent) { - // TODO Auto-generated method stub + public IFDocumentHandlerConfigurator getConfigurator(FOUserAgent userAgent) { return null; } |