]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Split IFPainter into IFDocumentHandler and IFPainter. This makes the implementation...
authorJeremias Maerki <jeremias@apache.org>
Sun, 28 Sep 2008 13:17:57 +0000 (13:17 +0000)
committerJeremias Maerki <jeremias@apache.org>
Sun, 28 Sep 2008 13:17:57 +0000 (13:17 +0000)
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

70 files changed:
src/java/META-INF/services/org.apache.fop.render.ImageHandler
src/java/META-INF/services/org.apache.fop.render.intermediate.IFDocumentHandler [new file with mode: 0644]
src/java/META-INF/services/org.apache.fop.render.intermediate.IFPainter [deleted file]
src/java/org/apache/fop/apps/FopFactory.java
src/java/org/apache/fop/render/AbstractRenderer.java
src/java/org/apache/fop/render/PrintRenderer.java
src/java/org/apache/fop/render/Renderer.java
src/java/org/apache/fop/render/RendererFactory.java
src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java [new file with mode: 0644]
src/java/org/apache/fop/render/bitmap/TIFFConstants.java [new file with mode: 0644]
src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java [new file with mode: 0644]
src/java/org/apache/fop/render/bitmap/TIFFDocumentHandlerMaker.java [new file with mode: 0644]
src/java/org/apache/fop/render/bitmap/TIFFRenderer.java
src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java
src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFDocumentHandler.java [new file with mode: 0644]
src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFPainter.java [deleted file]
src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java [new file with mode: 0644]
src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandlerMaker.java [new file with mode: 0644]
src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
src/java/org/apache/fop/render/intermediate/AbstractIFPainterMaker.java [deleted file]
src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFDocumentHandler.java [new file with mode: 0644]
src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFPainter.java [deleted file]
src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java [new file with mode: 0644]
src/java/org/apache/fop/render/intermediate/IFDocumentHandlerConfigurator.java [new file with mode: 0644]
src/java/org/apache/fop/render/intermediate/IFGraphicContext.java
src/java/org/apache/fop/render/intermediate/IFPainter.java
src/java/org/apache/fop/render/intermediate/IFPainterConfigurator.java [deleted file]
src/java/org/apache/fop/render/intermediate/IFParser.java
src/java/org/apache/fop/render/intermediate/IFRenderer.java
src/java/org/apache/fop/render/intermediate/IFSerializer.java
src/java/org/apache/fop/render/intermediate/IFSerializerConfiguration.java [new file with mode: 0644]
src/java/org/apache/fop/render/intermediate/IFUtil.java [new file with mode: 0644]
src/java/org/apache/fop/render/java2d/Java2DBorderPainter.java [new file with mode: 0644]
src/java/org/apache/fop/render/java2d/Java2DFontMetrics.java
src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java
src/java/org/apache/fop/render/java2d/Java2DImageHandlerGraphics2D.java [new file with mode: 0644]
src/java/org/apache/fop/render/java2d/Java2DImageHandlerRenderedImage.java [new file with mode: 0644]
src/java/org/apache/fop/render/java2d/Java2DPainter.java [new file with mode: 0644]
src/java/org/apache/fop/render/java2d/Java2DRenderer.java
src/java/org/apache/fop/render/java2d/Java2DRenderingContext.java [new file with mode: 0644]
src/java/org/apache/fop/render/java2d/Java2DRenderingSettings.java [new file with mode: 0644]
src/java/org/apache/fop/render/java2d/Java2DUtil.java [new file with mode: 0644]
src/java/org/apache/fop/render/pcl/PCLDocumentHandler.java [new file with mode: 0644]
src/java/org/apache/fop/render/pcl/PCLDocumentHandlerMaker.java [new file with mode: 0644]
src/java/org/apache/fop/render/pcl/PCLPainter.java
src/java/org/apache/fop/render/pcl/PCLPainterMaker.java [deleted file]
src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java [new file with mode: 0644]
src/java/org/apache/fop/render/pdf/PDFDocumentHandlerMaker.java [new file with mode: 0644]
src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java
src/java/org/apache/fop/render/pdf/PDFPainter.java
src/java/org/apache/fop/render/pdf/PDFPainterMaker.java [deleted file]
src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java
src/java/org/apache/fop/render/xml/XMLRenderer.java
src/java/org/apache/fop/util/DelegatingContentHandler.java
src/java/org/apache/fop/util/GenerationHelperContentHandler.java [new file with mode: 0644]
src/java/org/apache/fop/util/XMLUtil.java
src/sandbox/META-INF/services/org.apache.fop.render.intermediate.IFDocumentHandler [new file with mode: 0644]
src/sandbox/META-INF/services/org.apache.fop.render.intermediate.IFPainter [deleted file]
src/sandbox/org/apache/fop/render/svg/AbstractSVGDocumentHandler.java [new file with mode: 0644]
src/sandbox/org/apache/fop/render/svg/AbstractSVGPainter.java [deleted file]
src/sandbox/org/apache/fop/render/svg/SVGDocumentHandler.java [new file with mode: 0644]
src/sandbox/org/apache/fop/render/svg/SVGDocumentHandlerMaker.java [new file with mode: 0644]
src/sandbox/org/apache/fop/render/svg/SVGPainter.java
src/sandbox/org/apache/fop/render/svg/SVGPainterMaker.java [deleted file]
src/sandbox/org/apache/fop/render/svg/SVGPrintDocumentHandler.java [new file with mode: 0644]
src/sandbox/org/apache/fop/render/svg/SVGPrintDocumentHandlerMaker.java [new file with mode: 0644]
src/sandbox/org/apache/fop/render/svg/SVGPrintPainter.java [deleted file]
src/sandbox/org/apache/fop/render/svg/SVGPrintPainterMaker.java [deleted file]
test/java/org/apache/fop/intermediate/IFParserTestCase.java
test/java/org/apache/fop/intermediate/IFTester.java

index 81accc88adcb5e104af973aaa3e72de544d3b475..d9f2ccbba26af03e2d5177f0dc7c25b099167182 100644 (file)
@@ -3,3 +3,5 @@ org.apache.fop.render.pdf.PDFImageHandlerRenderedImage
 org.apache.fop.render.pdf.PDFImageHandlerRawJPEG\r
 org.apache.fop.render.pdf.PDFImageHandlerRawCCITTFax\r
 org.apache.fop.render.pdf.PDFImageHandlerSVG\r
+org.apache.fop.render.java2d.Java2DImageHandlerRenderedImage\r
+org.apache.fop.render.java2d.Java2DImageHandlerGraphics2D\r
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 (file)
index 0000000..4e8309f
--- /dev/null
@@ -0,0 +1,3 @@
+org.apache.fop.render.pdf.PDFDocumentHandlerMaker\r
+org.apache.fop.render.pcl.PCLDocumentHandlerMaker\r
+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 (file)
index 8b7fd45..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-org.apache.fop.render.pdf.PDFPainterMaker\r
-org.apache.fop.render.pcl.PCLPainterMaker
\ No newline at end of file
index 883afdcfad35c1f7e1c2a734d04a3fceea9878a2..96c22f964a5dfc1c6d1fc09a174610f0c9a47fc0 100644 (file)
@@ -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;
index 18c540fed43c25e4061b62961040dcde6abd2d3d..2be9150b07041cb9bf1a43ee584b6d5b761803cf 100644 (file)
@@ -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) {
index 56504ff53855c3cf1edb9eb0c32e958e95e48929..818e31568777984d59fa255ea4b319d9ea4ecf28 100644 (file)
@@ -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[] {
index 0ff37db0ee6a457fa42257956c0c3e2a2fe7e004..5fa9ca5b26316e891b43925b9f163c6ac2ab9dba 100644 (file)
@@ -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>
index 412f3e2cdfb541d8125c6d8f7d8b13a3ce454db3..5a82151e59d360da77862e97213b4f29cd0a656f 100644 (file)
@@ -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 (file)
index 0000000..937a074
--- /dev/null
@@ -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 (file)
index 0000000..437cf53
--- /dev/null
@@ -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 (file)
index 0000000..0da1c02
--- /dev/null
@@ -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 (file)
index 0000000..dd1cb10
--- /dev/null
@@ -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);
+    }
+
+}
index fea831a9bddea36113d4308b756db97af819ea44..c524ccc3a50430c8b9f1778efff15edc10f71e4c 100644 (file)
@@ -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;
index ff5e22ceb4a53e10bb85db00ff26fcef85af0fd3..a5b8e553185835246c4ae0127b4e33bc34d62fa3 100644 (file)
 
 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/AbstractBinaryWritingIFDocumentHandler.java b/src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFDocumentHandler.java
new file mode 100644 (file)
index 0000000..758b18d
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 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.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URL;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+
+import org.apache.fop.fonts.FontCollection;
+import org.apache.fop.fonts.FontEventAdapter;
+import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.fonts.FontManager;
+import org.apache.fop.fonts.base14.Base14FontCollection;
+
+/**
+ * Abstract base class for binary-writing {@code IFDocumentHandler} implementations.
+ */
+public abstract class AbstractBinaryWritingIFDocumentHandler extends AbstractIFDocumentHandler {
+
+    /** The output stream to write the document to */
+    protected OutputStream outputStream;
+
+    private boolean ownOutputStream;
+
+    /** Font configuration */
+    protected FontInfo fontInfo;
+
+    /** {@inheritDoc} */
+    public void setResult(Result result) throws IFException {
+        if (result instanceof StreamResult) {
+            StreamResult streamResult = (StreamResult)result;
+            OutputStream out = streamResult.getOutputStream();
+            if (out == null) {
+                if (streamResult.getWriter() != null) {
+                    throw new IllegalArgumentException(
+                            "FOP cannot use a Writer. Please supply an OutputStream!");
+                }
+                try {
+                    URL url = new URL(streamResult.getSystemId());
+                    File f = FileUtils.toFile(url);
+                    if (f != null) {
+                        out = new java.io.FileOutputStream(f);
+                    } else {
+                        out = url.openConnection().getOutputStream();
+                    }
+                } catch (IOException ioe) {
+                    throw new IFException("I/O error while opening output stream" , ioe);
+                }
+                out = new java.io.BufferedOutputStream(out);
+                this.ownOutputStream = true;
+            }
+            if (out == null) {
+                throw new IllegalArgumentException("Need a StreamResult with an OutputStream");
+            }
+            this.outputStream = out;
+        } else {
+            throw new UnsupportedOperationException(
+                    "Unsupported Result subclass: " + result.getClass().getName());
+        }
+    }
+
+    /** {@inheritDoc} */
+    public FontInfo getFontInfo() {
+        return this.fontInfo;
+    }
+
+    /** {@inheritDoc} */
+    public void setFontInfo(FontInfo fontInfo) {
+        this.fontInfo = fontInfo;
+    }
+
+    /** {@inheritDoc} */
+    public void setDefaultFontInfo(FontInfo fontInfo) {
+        FontManager fontManager = getUserAgent().getFactory().getFontManager();
+        FontCollection[] fontCollections = new FontCollection[] {
+                new Base14FontCollection(fontManager.isBase14KerningEnabled())
+        };
+
+        FontInfo fi = (fontInfo != null ? fontInfo : new FontInfo());
+        fi.setEventListener(new FontEventAdapter(getUserAgent().getEventBroadcaster()));
+        fontManager.setup(fi, fontCollections);
+        setFontInfo(fi);
+    }
+
+    /** {@inheritDoc} */
+    public void endDocument() throws IFException {
+        if (this.ownOutputStream) {
+            IOUtils.closeQuietly(this.outputStream);
+            this.outputStream = null;
+        }
+    }
+
+}
diff --git a/src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFPainter.java b/src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFPainter.java
deleted file mode 100644 (file)
index 7f82f3d..0000000
+++ /dev/null
@@ -1,120 +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.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.URL;
-
-import javax.xml.transform.Result;
-import javax.xml.transform.stream.StreamResult;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
-
-import org.apache.fop.fonts.FontCollection;
-import org.apache.fop.fonts.FontEventAdapter;
-import org.apache.fop.fonts.FontInfo;
-import org.apache.fop.fonts.FontManager;
-import org.apache.fop.fonts.base14.Base14FontCollection;
-
-/**
- * Abstract base class for binary-writing IFPainter implementations.
- */
-public abstract class AbstractBinaryWritingIFPainter extends AbstractIFPainter {
-
-    /** The output stream to write the document to */
-    protected OutputStream outputStream;
-
-    private boolean ownOutputStream;
-
-    /** Font configuration */
-    protected FontInfo fontInfo;
-
-    /** {@inheritDoc} */
-    public void setResult(Result result) throws IFException {
-        if (result instanceof StreamResult) {
-            StreamResult streamResult = (StreamResult)result;
-            OutputStream out = streamResult.getOutputStream();
-            if (out == null) {
-                if (streamResult.getWriter() != null) {
-                    throw new IllegalArgumentException(
-                            "FOP cannot use a Writer. Please supply an OutputStream!");
-                }
-                try {
-                    URL url = new URL(streamResult.getSystemId());
-                    File f = FileUtils.toFile(url);
-                    if (f != null) {
-                        out = new java.io.FileOutputStream(f);
-                    } else {
-                        out = url.openConnection().getOutputStream();
-                    }
-                } catch (IOException ioe) {
-                    throw new IFException("I/O error while opening output stream" , ioe);
-                }
-                out = new java.io.BufferedOutputStream(out);
-                this.ownOutputStream = true;
-            }
-            if (out == null) {
-                throw new IllegalArgumentException("Need a StreamResult with an OutputStream");
-            }
-            this.outputStream = out;
-        } else {
-            throw new UnsupportedOperationException(
-                    "Unsupported Result subclass: " + result.getClass().getName());
-        }
-    }
-
-    /**
-     * Returns the {@code FontInfo} object.
-     * @return the font info
-     */
-    public FontInfo getFontInfo() {
-        return this.fontInfo;
-    }
-
-    /** {@inheritDoc} */
-    public void setFontInfo(FontInfo fontInfo) {
-        this.fontInfo = fontInfo;
-    }
-
-    /** {@inheritDoc} */
-    public void setDefaultFontInfo() {
-        FontManager fontManager = getUserAgent().getFactory().getFontManager();
-        FontCollection[] fontCollections = new FontCollection[] {
-                new Base14FontCollection(fontManager.isBase14KerningEnabled())
-        };
-
-        FontInfo fi = new FontInfo();
-        fi.setEventListener(new FontEventAdapter(getUserAgent().getEventBroadcaster()));
-        fontManager.setup(fi, fontCollections);
-        setFontInfo(fi);
-    }
-
-    /** {@inheritDoc} */
-    public void endDocument() throws IFException {
-        if (this.ownOutputStream) {
-            IOUtils.closeQuietly(this.outputStream);
-            this.outputStream = null;
-        }
-    }
-
-}
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 (file)
index 0000000..b1f1f20
--- /dev/null
@@ -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/AbstractIFDocumentHandlerMaker.java b/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandlerMaker.java
new file mode 100644 (file)
index 0000000..f163c37
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.intermediate;
+
+import org.apache.fop.apps.FOUserAgent;
+
+/**
+ * Base class for factory classes which instantiate {@code IFDocumentHandler}s and provide
+ * information about them.
+ */
+public abstract class AbstractIFDocumentHandlerMaker {
+
+    /**
+     * Instantiates a new {@code IFDocumentHandler}.
+     * @param userAgent the user agent
+     * @return the newly instantiated document handler
+     */
+    public abstract IFDocumentHandler makeIFDocumentHandler(FOUserAgent userAgent);
+
+    /**
+     * @return Indicates whether this document handler requires an OutputStream to work with.
+     */
+    public abstract boolean needsOutputStream();
+
+    /**
+     * @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 document handler.
+     * @param userAgent the user agent
+     * @return a configurator object that can be used to configure the document handler
+     */
+    public abstract IFDocumentHandlerConfigurator getConfigurator(FOUserAgent userAgent);
+
+    /**
+     * 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
+     */
+    public boolean isMimeTypeSupported(String mimeType) {
+        String[] mimes = getSupportedMimeTypes();
+        for (int i = 0; i < mimes.length; i++) {
+            if (mimes[i].equals(mimeType)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
index 90876b18c9b125b64f31bf71e43efa820b3f3db3..a54e62bd01f0cc2fb64ef42fd6eb0eb1eb995582 100644 (file)
@@ -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/AbstractIFPainterMaker.java b/src/java/org/apache/fop/render/intermediate/AbstractIFPainterMaker.java
deleted file mode 100644 (file)
index aa653cd..0000000
+++ /dev/null
@@ -1,69 +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 org.apache.fop.apps.FOUserAgent;
-
-/**
- * Base class for factory classes which instantiate {@code IFPainter}s and provide information
- * about them.
- */
-public abstract class AbstractIFPainterMaker {
-
-    /**
-     * Instantiates a new {@code IFPainter}.
-     * @param userAgent the user agent
-     * @return the newly instantiated painter
-     */
-    public abstract IFPainter makePainter(FOUserAgent userAgent);
-
-    /**
-     * @return Indicates whether this painter requires an OutputStream to work with.
-     */
-    public abstract boolean needsOutputStream();
-
-    /**
-     * @return an array of MIME types the painter supports.
-     */
-    public abstract String[] getSupportedMimeTypes();
-
-    /**
-     * Returns a configurator object that can be used to
-     * configure the painter.
-     * @param userAgent the user agent
-     * @return a configurator object that can be used to configure the painter
-     */
-    public abstract IFPainterConfigurator getConfigurator(FOUserAgent userAgent);
-
-    /**
-     * Indicates whether a specific MIME type is supported by this painter.
-     * @param mimeType the MIME type (ex. "application/pdf")
-     * @return true if the MIME type is supported
-     */
-    public boolean isMimeTypeSupported(String mimeType) {
-        String[] mimes = getSupportedMimeTypes();
-        for (int i = 0; i < mimes.length; i++) {
-            if (mimes[i].equals(mimeType)) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
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 (file)
index 0000000..98706c0
--- /dev/null
@@ -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 (file)
index 1c90c47..0000000
+++ /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 (file)
index 0000000..6109376
--- /dev/null
@@ -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/IFDocumentHandlerConfigurator.java b/src/java/org/apache/fop/render/intermediate/IFDocumentHandlerConfigurator.java
new file mode 100644 (file)
index 0000000..633e564
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.intermediate;
+
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fonts.FontInfo;
+
+/**
+ * This interface is implemented by classes that configure an {@code IFDocumentHandler} instance.
+ */
+public interface IFDocumentHandlerConfigurator {
+
+    /**
+     * Configures a intermediate format document handler.
+     * @param documentHandler the document handler instance
+     * @throws FOPException if an error occurs while configuring the object
+     */
+    void configure(IFDocumentHandler documentHandler) throws FOPException;
+
+    /**
+     * 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(IFDocumentHandler documentHandler, FontInfo fontInfo) throws FOPException;
+
+}
index 7250dcc39c27e39d48460b2769ae95a508566df9..34ac0bcb20c851fb5afa90ca7a6ccf2fb90d180e 100644 (file)
@@ -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());
index b354510f8a138e9ffec51a76dacda09b21f2cc46..2c704db8bce3972a683cc11fa516973844803b4b 100644 (file)
@@ -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/IFPainterConfigurator.java b/src/java/org/apache/fop/render/intermediate/IFPainterConfigurator.java
deleted file mode 100644 (file)
index 71a3a48..0000000
+++ /dev/null
@@ -1,42 +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 org.apache.fop.apps.FOPException;
-
-/**
- * This interface is implemented by classes that configure an {@code IFPainter} instance.
- */
-public interface IFPainterConfigurator {
-
-    /**
-     * Configures a painter.
-     * @param painter the painter instance
-     * @throws FOPException if an error occurs while configuring the object
-     */
-    void configure(IFPainter painter) throws FOPException;
-
-    /**
-     * Sets up the {@code FontInfo} object for the IFPainter.
-     * @param painter the painter instance
-     * @throws FOPException if an error occurs while configuring the object
-     */
-    void setupFontInfo(IFPainter painter) throws FOPException;
-}
index cc125a6f763c0d427199f41bbf5c661d466f8fba..5eaef13ae5bba962a71700de35ab2526759af930 100644 (file)
@@ -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);
             }
index 8831656e17d1e708a96526f367bd302f7eebf3f4..eddd5f1bd57a69dc0dbaffff00c24dc084785ef8 100644 (file)
@@ -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);
         }
index 20db35c6ab079b1fada4edc6df65ec6428fd6a53..95d1f20fe347a4315bb1a37b64efb8d40a0d44b0 100644 (file)
@@ -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.
@@ -71,13 +74,49 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst
         return MIME_TYPE;
     }
 
+    /** {@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 (file)
index 0000000..8f47c55
--- /dev/null
@@ -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 (file)
index 0000000..513e1c7
--- /dev/null
@@ -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 (file)
index 0000000..cd0cec0
--- /dev/null
@@ -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;
+    }
+
+}
index 10af3aa867fb3f6061967efb7babea874903bed2..88ceb127019873b3bb38db1dae9aac0a492df5cd 100644 (file)
@@ -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;
 
 /**
@@ -109,6 +111,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
index 1c5fa84277fe4eefd359329c6ded9fbde81dc17b..a40ee1d5c82abd11f854194720deb07c2e4aeaf7 100644 (file)
@@ -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 (file)
index 0000000..3fc1787
--- /dev/null
@@ -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 (file)
index 0000000..9c2d24c
--- /dev/null
@@ -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 (file)
index 0000000..9a68f62
--- /dev/null
@@ -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);
+    }
+
+}
index e3f79dea26cb14f21860bfa5fffea5cd283c9869..65e6ac0fe923851e2aa3fab5781871f5a00e000e 100644 (file)
@@ -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 (file)
index 0000000..7bc5550
--- /dev/null
@@ -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 (file)
index 0000000..f7bad64
--- /dev/null
@@ -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 (file)
index 0000000..30f84ba
--- /dev/null
@@ -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 (file)
index 0000000..ce032ac
--- /dev/null
@@ -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/PCLDocumentHandlerMaker.java b/src/java/org/apache/fop/render/pcl/PCLDocumentHandlerMaker.java
new file mode 100644 (file)
index 0000000..5d42d33
--- /dev/null
@@ -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.pcl;
+
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.apps.MimeConstants;
+import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker;
+import org.apache.fop.render.intermediate.IFDocumentHandler;
+import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator;
+
+/**
+ * Document handler factory for PCL output.
+ */
+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 IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) {
+        PCLDocumentHandler handler = new PCLDocumentHandler();
+        handler.setUserAgent(ua);
+        return handler;
+    }
+
+    /** {@inheritDoc} */
+    public boolean needsOutputStream() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    public String[] getSupportedMimeTypes() {
+        return MIMES;
+    }
+
+    /** {@inheritDoc} */
+    public IFDocumentHandlerConfigurator getConfigurator(FOUserAgent userAgent) {
+        return null;
+    }
+
+}
index 9f194df250a07105b906883591bedfc4de8fba1b..d4e04175e7684daf6db407aabfd2292d6d2846d6 100644 (file)
@@ -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 */
@@ -118,116 +105,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 {
@@ -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/pcl/PCLPainterMaker.java b/src/java/org/apache/fop/render/pcl/PCLPainterMaker.java
deleted file mode 100644 (file)
index eb5dfda..0000000
+++ /dev/null
@@ -1,55 +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.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;
-
-/**
- * Painter factory for PCL output.
- */
-public class PCLPainterMaker extends AbstractIFPainterMaker {
-
-    //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();
-    }
-
-    /** {@inheritDoc} */
-    public boolean needsOutputStream() {
-        return true;
-    }
-
-    /** {@inheritDoc} */
-    public String[] getSupportedMimeTypes() {
-        return MIMES;
-    }
-
-    public IFPainterConfigurator getConfigurator(FOUserAgent userAgent) {
-        return null; //new PDFRendererConfigurator(userAgent);
-    }
-
-}
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 (file)
index 0000000..8937d0d
--- /dev/null
@@ -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/PDFDocumentHandlerMaker.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandlerMaker.java
new file mode 100644 (file)
index 0000000..88ae60d
--- /dev/null
@@ -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.pdf;
+
+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;
+
+/**
+ * Intermediate format document handler factory for PDF output.
+ */
+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 IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) {
+        PDFDocumentHandler handler = new PDFDocumentHandler();
+        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 PDFRendererConfigurator(userAgent);
+    }
+
+}
index 975f72c069a18976e78aa2a1c836ebcf09d8d898..3764486b78ad3169ab865f2c937ed2dc773eaa35 100644 (file)
@@ -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;
     }
 
 }
index 6501ea64866e3dd4f49f1b721a7d19377ba846a8..5273220e7c19672a563060e38144a1aca1ba0a55 100644 (file)
@@ -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/PDFPainterMaker.java b/src/java/org/apache/fop/render/pdf/PDFPainterMaker.java
deleted file mode 100644 (file)
index f1fbe48..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.render.pdf;
-
-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;
-
-/**
- * Painter factory for PDF output.
- */
-public class PDFPainterMaker extends AbstractIFPainterMaker {
-
-    //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();
-    }
-
-    /** {@inheritDoc} */
-    public boolean needsOutputStream() {
-        return true;
-    }
-
-    /** {@inheritDoc} */
-    public String[] getSupportedMimeTypes() {
-        return MIMES;
-    }
-
-    public IFPainterConfigurator getConfigurator(FOUserAgent userAgent) {
-        return new PDFRendererConfigurator(userAgent);
-    }
-
-}
index 50b48971721a97df2eb156df8ec228f086575e95..d416f11472cb62b2d3c223655af9a9ec6394049a 100644 (file)
@@ -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);
     }
 
 }
index 38db7abdf927fdcdba5cf4b1b49f23b82daea564..6e03d68dd1086617a0ae893a81a5c2b556b3b695 100644 (file)
@@ -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 {
index ff712a82b4b9177206a9f5c36b0ecb26864ee76d..8a2acba1a21fc2c790d1934fe9734a54bf5a1020 100644 (file)
@@ -55,6 +55,27 @@ public class DelegatingContentHandler
         //nop
     }
 
+    /**
+     * 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
      */
diff --git a/src/java/org/apache/fop/util/GenerationHelperContentHandler.java b/src/java/org/apache/fop/util/GenerationHelperContentHandler.java
new file mode 100644 (file)
index 0000000..11a7c8f
--- /dev/null
@@ -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);
+    }
+
+}
index 13784ea19d0c8c45dd7d70ae8d3ff3daec749eec..e42bef90e45fd1fe05d5323bfd3bee62e248aa1a 100644 (file)
@@ -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 (file)
index 0000000..5ed153a
--- /dev/null
@@ -0,0 +1,2 @@
+org.apache.fop.render.svg.SVGDocumentHandlerMaker\r
+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 (file)
index 7913529..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-org.apache.fop.render.svg.SVGPainterMaker\r
-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 (file)
index 0000000..fbb6728
--- /dev/null
@@ -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 (file)
index 8f0be02..0000000
+++ /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 (file)
index 0000000..bd3dbc4
--- /dev/null
@@ -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/SVGDocumentHandlerMaker.java b/src/sandbox/org/apache/fop/render/svg/SVGDocumentHandlerMaker.java
new file mode 100644 (file)
index 0000000..0296135
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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.apache.fop.apps.FOUserAgent;
+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 SVG output.
+ */
+public class SVGDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker {
+
+    private static final String[] MIMES = new String[] {SVGConstants.MIME_TYPE};
+
+    /** {@inheritDoc} */
+    public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) {
+        SVGDocumentHandler handler = new SVGDocumentHandler();
+        handler.setUserAgent(ua);
+        return handler;
+    }
+
+    /** {@inheritDoc} */
+    public boolean needsOutputStream() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    public String[] getSupportedMimeTypes() {
+        return MIMES;
+    }
+
+    /** {@inheritDoc} */
+    public IFDocumentHandlerConfigurator getConfigurator(FOUserAgent userAgent) {
+        return null;
+    }
+
+}
index aa52673a9de1ee4d60077098fcadecdce8fe4c6e..e0d12d9c7ae12d26966616c6c2ad51fa1a83f7b7 100644 (file)
 
 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/SVGPainterMaker.java b/src/sandbox/org/apache/fop/render/svg/SVGPainterMaker.java
deleted file mode 100644 (file)
index a25a2f3..0000000
+++ /dev/null
@@ -1,55 +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 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;
-
-/**
- * Painter factory for SVG output.
- */
-public class SVGPainterMaker extends AbstractIFPainterMaker {
-
-    private static final String[] MIMES = new String[] {SVGConstants.MIME_TYPE};
-
-    /** {@inheritDoc} */
-    public IFPainter makePainter(FOUserAgent ua) {
-        return new SVGPainter();
-    }
-
-    /** {@inheritDoc} */
-    public boolean needsOutputStream() {
-        return true;
-    }
-
-    /** {@inheritDoc} */
-    public String[] getSupportedMimeTypes() {
-        return MIMES;
-    }
-
-    /** {@inheritDoc} */
-    public IFPainterConfigurator getConfigurator(FOUserAgent userAgent) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-}
diff --git a/src/sandbox/org/apache/fop/render/svg/SVGPrintDocumentHandler.java b/src/sandbox/org/apache/fop/render/svg/SVGPrintDocumentHandler.java
new file mode 100644 (file)
index 0000000..ee69f95
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.svg;
+
+import java.awt.Dimension;
+
+import javax.xml.transform.Result;
+
+import org.xml.sax.SAXException;
+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;
+
+/**
+ * {@code IFDocumentHandler} implementation that writes SVG Print.
+ */
+public class SVGPrintDocumentHandler extends AbstractSVGDocumentHandler {
+
+    /**
+     * Default constructor.
+     */
+    public SVGPrintDocumentHandler() {
+        //nop
+    }
+
+    /**
+     * Creates a new SVGPrintPainter that sends the XML content it generates to the given
+     * SAX ContentHandler.
+     * @param result the JAXP Result object to receive the generated content
+     * @throws IFException if an error occurs setting up the output
+     */
+    public SVGPrintDocumentHandler(Result result) throws IFException {
+        setResult(result);
+    }
+
+    /** {@inheritDoc} */
+    public boolean supportsPagesOutOfOrder() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public String getMimeType() {
+        return MIME_SVG_PRINT;
+    }
+
+    /** {@inheritDoc} */
+    public void startDocument() throws IFException {
+        try {
+            handler.startDocument();
+            handler.startPrefixMapping("", NAMESPACE);
+            handler.startPrefixMapping(XLINK_PREFIX, XLINK_NAMESPACE);
+            handler.startPrefixMapping("if", IFConstants.NAMESPACE);
+            AttributesImpl atts = new AttributesImpl();
+            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);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void endDocument() throws IFException {
+        try {
+            handler.endElement("svg");
+            handler.endDocument();
+        } catch (SAXException e) {
+            throw new IFException("SAX error in endDocument()", e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void startPageSequence(String id) throws IFException {
+        try {
+            AttributesImpl atts = new AttributesImpl();
+            if (id != null) {
+                atts.addAttribute(XML_NAMESPACE, "id", "xml:id", CDATA, id);
+            }
+            handler.startElement("pageSet", atts);
+        } catch (SAXException e) {
+            throw new IFException("SAX error in startPageSequence()", e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void endPageSequence() throws IFException {
+        try {
+            handler.endElement("pageSet");
+        } catch (SAXException e) {
+            throw new IFException("SAX error in endPageSequence()", e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void startPage(int index, String name, Dimension size) throws IFException {
+        try {
+            AttributesImpl atts = new AttributesImpl();
+            /*
+            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",
+                    CDATA, Integer.toString(size.width));
+            atts.addAttribute(IFConstants.NAMESPACE, "height", "if:height",
+                    CDATA, Integer.toString(size.height));
+            atts.addAttribute(IFConstants.NAMESPACE, "viewBox", "if:viewBox", CDATA,
+                    "0 0 " + Integer.toString(size.width) + " " + Integer.toString(size.height));
+            handler.startElement("page", atts);
+        } catch (SAXException e) {
+            throw new IFException("SAX error in startPage()", e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void startPageHeader() throws IFException {
+    }
+
+    /** {@inheritDoc} */
+    public void endPageHeader() throws IFException {
+    }
+
+    /** {@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 startPageTrailer() throws IFException {
+    }
+
+    /** {@inheritDoc} */
+    public void endPageTrailer() throws IFException {
+    }
+
+    /** {@inheritDoc} */
+    public void endPage() throws IFException {
+        try {
+            handler.endElement("page");
+        } catch (SAXException e) {
+            throw new IFException("SAX error in endPage()", e);
+        }
+    }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/svg/SVGPrintDocumentHandlerMaker.java b/src/sandbox/org/apache/fop/render/svg/SVGPrintDocumentHandlerMaker.java
new file mode 100644 (file)
index 0000000..61993da
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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.apache.fop.apps.FOUserAgent;
+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 SVG Print output.
+ */
+public class SVGPrintDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker {
+
+    private static final String[] MIMES = new String[] {SVGConstants.MIME_SVG_PRINT};
+
+    /** {@inheritDoc} */
+    public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) {
+        SVGPrintDocumentHandler handler = new SVGPrintDocumentHandler();
+        handler.setUserAgent(ua);
+        return handler;
+    }
+
+    /** {@inheritDoc} */
+    public boolean needsOutputStream() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    public String[] getSupportedMimeTypes() {
+        return MIMES;
+    }
+
+    /** {@inheritDoc} */
+    public IFDocumentHandlerConfigurator getConfigurator(FOUserAgent userAgent) {
+        return null;
+    }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/svg/SVGPrintPainter.java b/src/sandbox/org/apache/fop/render/svg/SVGPrintPainter.java
deleted file mode 100644 (file)
index 7f5c84c..0000000
+++ /dev/null
@@ -1,177 +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.Dimension;
-
-import javax.xml.transform.Result;
-
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.AttributesImpl;
-
-import org.apache.fop.render.intermediate.IFConstants;
-import org.apache.fop.render.intermediate.IFException;
-
-/**
- * IFPainter implementation that writes SVG Print.
- */
-public class SVGPrintPainter extends AbstractSVGPainter {
-
-    /**
-     * Default constructor.
-     */
-    public SVGPrintPainter() {
-        //nop
-    }
-
-    /**
-     * Creates a new SVGPrintPainter that sends the XML content it generates to the given
-     * SAX ContentHandler.
-     * @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 {
-        setResult(result);
-    }
-
-    /** {@inheritDoc} */
-    public boolean supportsPagesOutOfOrder() {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    public String getMimeType() {
-        return MIME_SVG_PRINT;
-    }
-
-    /** {@inheritDoc} */
-    public void startDocument() throws IFException {
-        try {
-            handler.startDocument();
-            handler.startPrefixMapping("", NAMESPACE);
-            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);
-        } catch (SAXException e) {
-            throw new IFException("SAX error in startDocument()", e);
-        }
-    }
-
-    /** {@inheritDoc} */
-    public void endDocument() throws IFException {
-        try {
-            endElement("svg");
-            handler.endDocument();
-        } catch (SAXException e) {
-            throw new IFException("SAX error in endDocument()", e);
-        }
-    }
-
-    /** {@inheritDoc} */
-    public void startPageSequence(String id) throws IFException {
-        try {
-            AttributesImpl atts = new AttributesImpl();
-            if (id != null) {
-                atts.addAttribute(XML_NAMESPACE, "id", "xml:id", CDATA, id);
-            }
-            startElement("pageSet", atts);
-        } catch (SAXException e) {
-            throw new IFException("SAX error in startPageSequence()", e);
-        }
-    }
-
-    /** {@inheritDoc} */
-    public void endPageSequence() throws IFException {
-        try {
-            endElement("pageSet");
-        } catch (SAXException e) {
-            throw new IFException("SAX error in endPageSequence()", e);
-        }
-    }
-
-    /** {@inheritDoc} */
-    public void startPage(int index, String name, Dimension size) throws IFException {
-        try {
-            AttributesImpl atts = new AttributesImpl();
-            /*
-            atts.addAttribute("", "index", "index", CDATA, Integer.toString(index));
-            atts.addAttribute("", "name", "name", CDATA, name);
-            */
-            //NOTE: SVG Print doesn't support individual page sizes for each page
-            atts.addAttribute(IFConstants.NAMESPACE, "width", "if:width",
-                    CDATA, Integer.toString(size.width));
-            atts.addAttribute(IFConstants.NAMESPACE, "height", "if:height",
-                    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);
-        } catch (SAXException e) {
-            throw new IFException("SAX error in startPage()", e);
-        }
-    }
-
-    /** {@inheritDoc} */
-    public void startPageHeader() throws IFException {
-    }
-
-    /** {@inheritDoc} */
-    public void endPageHeader() throws IFException {
-    }
-
-    /** {@inheritDoc} */
-    public void startPageContent() throws IFException {
-        super.startPageContent();
-        try {
-            startElement("g");
-        } catch (SAXException e) {
-            throw new IFException("SAX error in startPageContent()", e);
-        }
-    }
-
-    /** {@inheritDoc} */
-    public void endPageContent() throws IFException {
-        try {
-            endElement("g");
-        } catch (SAXException e) {
-            throw new IFException("SAX error in endPageContent()", e);
-        }
-        super.endPageContent();
-    }
-
-    /** {@inheritDoc} */
-    public void startPageTrailer() throws IFException {
-    }
-
-    /** {@inheritDoc} */
-    public void endPageTrailer() throws IFException {
-    }
-
-    /** {@inheritDoc} */
-    public void endPage() throws IFException {
-        try {
-            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/SVGPrintPainterMaker.java
deleted file mode 100644 (file)
index 55a7bf7..0000000
+++ /dev/null
@@ -1,55 +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 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;
-
-/**
- * Painter factory for SVG Print output.
- */
-public class SVGPrintPainterMaker extends AbstractIFPainterMaker {
-
-    private static final String[] MIMES = new String[] {SVGConstants.MIME_SVG_PRINT};
-
-    /** {@inheritDoc} */
-    public IFPainter makePainter(FOUserAgent ua) {
-        return new SVGPrintPainter();
-    }
-
-    /** {@inheritDoc} */
-    public boolean needsOutputStream() {
-        return true;
-    }
-
-    /** {@inheritDoc} */
-    public String[] getSupportedMimeTypes() {
-        return MIMES;
-    }
-
-    /** {@inheritDoc} */
-    public IFPainterConfigurator getConfigurator(FOUserAgent userAgent) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-}
index 2803e26c58f4925e92dde7d3df87b54023b0e993..b61c252d7af5fb6d8fbed639468dfad66a1d27eb 100644 (file)
@@ -35,8 +35,8 @@ import org.w3c.dom.Document;
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.apps.Fop;
 import org.apache.fop.apps.MimeConstants;
-import org.apache.fop.render.Renderer;
-import org.apache.fop.render.intermediate.IFPainter;
+import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.render.intermediate.IFDocumentHandler;
 import org.apache.fop.render.intermediate.IFParser;
 import org.apache.fop.render.intermediate.IFRenderer;
 import org.apache.fop.render.intermediate.IFSerializer;
@@ -82,20 +82,20 @@ public class IFParserTestCase extends AbstractIntermediateTestCase {
         FOUserAgent userAgent = createUserAgent();
 
         //Create an instance of the target renderer so the XMLRenderer can use its font setup
-        Renderer targetRenderer = userAgent.getRendererFactory().createRenderer(
+        IFDocumentHandler targetHandler = userAgent.getRendererFactory().createDocumentHandler(
                 userAgent, getTargetMIME());
 
-        //Setup renderer
-        IFRenderer renderer = new IFRenderer();
-        renderer.setUserAgent(userAgent);
-        renderer.mimicRenderer(targetRenderer);
-
         //Setup painter
         IFSerializer serializer = new IFSerializer();
         serializer.setUserAgent(userAgent);
+        serializer.mimicDocumentHandler(targetHandler);
         serializer.setResult(domResult);
 
-        renderer.setPainter(serializer);
+        //Setup renderer
+        IFRenderer renderer = new IFRenderer();
+        renderer.setUserAgent(userAgent);
+
+        renderer.setDocumentHandler(serializer);
         userAgent.setRendererOverride(renderer);
 
         Fop fop = fopFactory.newFop(userAgent);
@@ -111,11 +111,11 @@ public class IFParserTestCase extends AbstractIntermediateTestCase {
 
         FOUserAgent userAgent = createUserAgent();
 
-        IFPainter painter = userAgent.getRendererFactory().createPainter(
+        IFDocumentHandler documentHandler = userAgent.getRendererFactory().createDocumentHandler(
                 userAgent, getTargetMIME());
-        painter.setResult(new StreamResult(out));
-        painter.setDefaultFontInfo();
-        parser.parse(src, painter, userAgent);
+        documentHandler.setResult(new StreamResult(out));
+        documentHandler.setDefaultFontInfo(new FontInfo());
+        parser.parse(src, documentHandler, userAgent);
     }
 
     /** {@inheritDoc} */
index ff5015aa5e64e78d645820bf7a3d127b006efa39..6ad2672e7a046b63572491eab1bf2b90c5a481b6 100644 (file)
@@ -115,7 +115,7 @@ public class IFTester {
             IFSerializer serializer = new IFSerializer();
             DOMResult result = new DOMResult();
             serializer.setResult(result);
-            ifRenderer.setPainter(serializer);
+            ifRenderer.setDocumentHandler(serializer);
 
             ua.setRendererOverride(ifRenderer);
             FontInfo fontInfo = new FontInfo();