]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Merge from Trunk revisions 719662 - 724689.
authorJeremias Maerki <jeremias@apache.org>
Tue, 9 Dec 2008 15:00:35 +0000 (15:00 +0000)
committerJeremias Maerki <jeremias@apache.org>
Tue, 9 Dec 2008 15:00:35 +0000 (15:00 +0000)
Conflict for ImageHandler interface resolved by renaming Trunk's ImageHandler to ImageHandlerBase and extending the other ImageHandler from that.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign@724729 13f79535-47bb-0310-9956-ffa450edef68

23 files changed:
1  2 
build.xml
src/java/org/apache/fop/apps/MimeConstants.java
src/java/org/apache/fop/events/EventFormatter.xml
src/java/org/apache/fop/render/AbstractImageHandlerRegistry.java
src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java
src/java/org/apache/fop/render/AbstractRenderer.java
src/java/org/apache/fop/render/ImageHandler.java
src/java/org/apache/fop/render/ImageHandlerBase.java
src/java/org/apache/fop/render/PrintRenderer.java
src/java/org/apache/fop/render/afp/AFPEventProducer.xml
src/java/org/apache/fop/render/afp/AFPImageHandler.java
src/java/org/apache/fop/render/java2d/Java2DRenderer.java
src/java/org/apache/fop/render/pcl/PCLRenderer.java
src/java/org/apache/fop/render/pdf/PDFContentGenerator.java
src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java
src/java/org/apache/fop/render/pdf/PDFImageHandler.java
src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java
src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java
src/java/org/apache/fop/render/pdf/PDFRenderer.java
src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java
src/java/org/apache/fop/render/pdf/PDFRendererContextConstants.java
src/java/org/apache/fop/render/pdf/PDFSVGHandler.java
src/java/org/apache/fop/svg/PDFGraphics2D.java

diff --cc build.xml
index cc000e4d88c316cc4c5ebebde0b0c8c38c48216e,2d92b2e110282822402266ba4c391cb85fdaa0ac..27dc3566fe854ef55d54f437333907b5cbbbbbbc
+++ b/build.xml
@@@ -612,8 -611,8 +612,9 @@@ list of possible build targets
        <include name="org/apache/fop/render/pdf/**"/>
        <exclude name="org/apache/fop/render/pdf/PDFRenderer.class"/>
        <exclude name="org/apache/fop/render/pdf/PDFXMLHandler*"/>
 +      <include name="org/apache/fop/render/intermediate/IFPainterConfigurator.class"/>
        <include name="org/apache/fop/render/*RendererConfigurator**"/>
+       <include name="org/apache/fop/util/AbstractPaintingState**"/>
        <include name="org/apache/fop/pdf/**"/>
      </patternset>
  <!-- PS transcoder -->
index b8a9637a848dfa3e465e035aa5707679be490e56,87048fa4dacc1a9c696d05abb13e8dffa228930f..851690db1c1976c6396401d76e071c1c9b54d902
@@@ -73,9 -30,5 +30,6 @@@ public interface MimeConstants extends 
      String MIME_FOP_PRINT       = "application/X-fop-print";
      /** Apache FOP's area tree XML */
      String MIME_FOP_AREA_TREE   = "application/X-fop-areatree";
 -
 +    /** Apache FOP's intermediate format XML */
 +    String MIME_FOP_IF          = "application/X-fop-intermediate-format";
-     /** Proposed but non-registered MIME type for XSL-FO */
-     String MIME_XSL_FO          = "text/xsl";
  }
index 0000000000000000000000000000000000000000,e8001f2fa0f1e42faa05d1bd7598222e4c4ebd04..4196a1b199ecb8dd435caa02edd8afe6212d69ad
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,208 +1,209 @@@
 -            ImageHandler h1 = (ImageHandler)o1;
 -            ImageHandler h2 = (ImageHandler)o2;
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one or more
+  * contributor license agreements.  See the NOTICE file distributed with
+  * this work for additional information regarding copyright ownership.
+  * The ASF licenses this file to You under the Apache License, Version 2.0
+  * (the "License"); you may not use this file except in compliance with
+  * the License.  You may obtain a copy of the License at
+  *
+  *      http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  */
+ /* $Id$ */
+ package org.apache.fop.render;
+ import java.util.Comparator;
+ import java.util.Iterator;
+ import java.util.List;
+ import java.util.ListIterator;
+ import java.util.Map;
+ import org.apache.commons.logging.Log;
+ import org.apache.commons.logging.LogFactory;
++
+ import org.apache.xmlgraphics.image.loader.Image;
+ import org.apache.xmlgraphics.image.loader.ImageFlavor;
+ import org.apache.xmlgraphics.util.Service;
+ /**
+  * This class holds references to various image handlers used by the renderers. It also
+  * supports automatic discovery of additional handlers available through
+  * the class path.
+  */
+ public abstract class AbstractImageHandlerRegistry {
+     /** the logger */
+     private static Log log = LogFactory.getLog(AbstractImageHandlerRegistry.class);
+     private static final Comparator HANDLER_COMPARATOR = new Comparator() {
+         public int compare(Object o1, Object o2) {
 -            ImageHandler handlerInstance
 -                = (ImageHandler)Class.forName(classname).newInstance();
++            ImageHandlerBase h1 = (ImageHandlerBase)o1;
++            ImageHandlerBase h2 = (ImageHandlerBase)o2;
+             return h1.getPriority() - h2.getPriority();
+         }
+     };
+     /** Map containing image handlers for various MIME types */
+     private final Map/*<Class, ImageHandler>*/ handlers
+         = new java.util.HashMap/*<Class, ImageHandler>*/();
+     /** List containing the same handlers as above but ordered by priority */
+     private final List/*<ImageHandler>*/ handlerList
+         = new java.util.LinkedList/*<ImageHandler>*/();
+     /** Sorted Set of registered handlers */
+     private ImageFlavor[] supportedFlavors = new ImageFlavor[0];
+     private int handlerRegistrations;
+     private int lastSync;
+     /**
+      * Default constructor.
+      */
+     public AbstractImageHandlerRegistry() {
+         discoverHandlers();
+     }
+     /**
+      * Add an ImageHandler. The handler itself is inspected to find out what it supports.
+      * @param classname the fully qualified class name
+      */
+     public void addHandler(String classname) {
+         try {
 -    public synchronized void addHandler(ImageHandler handler) {
++            ImageHandlerBase handlerInstance
++                = (ImageHandlerBase)Class.forName(classname).newInstance();
+             addHandler(handlerInstance);
+         } catch (ClassNotFoundException e) {
+             throw new IllegalArgumentException("Could not find "
+                                                + classname);
+         } catch (InstantiationException e) {
+             throw new IllegalArgumentException("Could not instantiate "
+                                                + classname);
+         } catch (IllegalAccessException e) {
+             throw new IllegalArgumentException("Could not access "
+                                                + classname);
+         } catch (ClassCastException e) {
+             throw new IllegalArgumentException(classname
+                                                + " is not an "
+                                                + getHandlerClass().getName());
+         }
+     }
+     /**
+      * Add an image handler. The handler itself is inspected to find out what it supports.
+      * @param handler the ImageHandler instance
+      */
 -            ImageHandler h = (ImageHandler)iter.next();
++    public synchronized void addHandler(ImageHandlerBase handler) {
+         this.handlers.put(handler.getSupportedImageClass(), handler);
+         //Sorted insert
+         ListIterator iter = this.handlerList.listIterator();
+         while (iter.hasNext()) {
 -    public ImageHandler getHandler(Image img) {
++            ImageHandlerBase h = (ImageHandlerBase)iter.next();
+             if (getHandlerComparator().compare(handler, h) < 0) {
+                 iter.previous();
+                 break;
+             }
+         }
+         iter.add(handler);
+         this.handlerRegistrations++;
+     }
+     /**
+      * Returns an ImageHandler which handles an specific image type given the MIME type
+      * of the image.
+      * @param img the Image to be handled
+      * @return the ImageHandler responsible for handling the image or null if none is available
+      */
 -    public synchronized ImageHandler getHandler(Class imageClass) {
 -        ImageHandler handler = null;
++    public ImageHandlerBase getHandler(Image img) {
+         return getHandler(img.getClass());
+     }
+     /**
+      * Returns an ImageHandler which handles an specific image type given the MIME type
+      * of the image.
+      * @param imageClass the Image subclass for which to get a handler
+      * @return the ImageHandler responsible for handling the image or null if none is available
+      */
 -            handler = (ImageHandler)handlers.get(cl);
++    public synchronized ImageHandlerBase getHandler(Class imageClass) {
++        ImageHandlerBase handler = null;
+         Class cl = imageClass;
+         while (cl != null) {
 -                ImageFlavor[] f = ((ImageHandler)iter.next()).getSupportedImageFlavors();
++            handler = (ImageHandlerBase)handlers.get(cl);
+             if (handler != null) {
+                 break;
+             }
+             cl = cl.getSuperclass();
+         }
+         return handler;
+     }
+     /**
+      * Returns the ordered array of supported image flavors.
+      * @return the array of image flavors
+      */
+     public synchronized ImageFlavor[] getSupportedFlavors() {
+         if (this.lastSync != this.handlerRegistrations) {
+             //Extract all ImageFlavors into a single array
+             List flavors = new java.util.ArrayList();
+             Iterator iter = this.handlerList.iterator();
+             while (iter.hasNext()) {
 -                ImageHandler handler = (ImageHandler)providers.next();
++                ImageFlavor[] f = ((ImageHandlerBase)iter.next()).getSupportedImageFlavors();
+                 for (int i = 0; i < f.length; i++) {
+                     flavors.add(f[i]);
+                 }
+             }
+             this.supportedFlavors = (ImageFlavor[])flavors.toArray(new ImageFlavor[flavors.size()]);
+             this.lastSync = this.handlerRegistrations;
+         }
+         return this.supportedFlavors;
+     }
+     /**
+      * Discovers ImageHandler implementations through the classpath and dynamically
+      * registers them.
+      */
+     private void discoverHandlers() {
+         // add mappings from available services
+         Class imageHandlerClass = getHandlerClass();
+         Iterator providers = Service.providers(imageHandlerClass);
+         if (providers != null) {
+             while (providers.hasNext()) {
++                ImageHandlerBase handler = (ImageHandlerBase)providers.next();
+                 try {
+                     if (log.isDebugEnabled()) {
+                         log.debug("Dynamically adding ImageHandler: "
+                                 + handler.getClass().getName());
+                     }
+                     addHandler(handler);
+                 } catch (IllegalArgumentException e) {
+                     log.error("Error while adding ImageHandler", e);
+                 }
+             }
+         }
+     }
+     /**
+      * Returns the ImageHandler comparator
+      *
+      * @return the ImageHandler comparator
+      */
+     public Comparator getHandlerComparator() {
+         return HANDLER_COMPARATOR;
+     }
+     /**
+      * Returns the ImageHandler implementing class
+      *
+      * @return the ImageHandler implementing class
+      */
+     public abstract Class getHandlerClass();
+ }
index c57a9d56690b04854ee054e10be475241a59c4a1,e74a8f31933b5b5902d7c13c1857e9e49390eabf..2e04f2d85f9f2fa44501ec5bbbf5b95c08d47d6b
@@@ -467,11 -470,9 +470,10 @@@ public abstract class AbstractPathOrien
                                  , width + bpwidth
                                  , height + bpheight);
          }
      }
  
 -    private static final QName FOX_TRANSFORM
 +    /** Constant for the fox:transform extension attribute */
 +    protected static final QName FOX_TRANSFORM
              = new QName(ExtensionElementMapping.URI, "fox:transform");
  
      /** {@inheritDoc} */
index 42ae5fd492de09b28f44384b080094a78841b0ae,6a44c01a9a33e44f87ed2d80122c03fd71870189..ec5f576aa9df7d3fe78130aaff7396767f771cb0
  
  package org.apache.fop.render;
  
 -import org.apache.xmlgraphics.image.loader.ImageFlavor;
 +import java.awt.Rectangle;
 +import java.io.IOException;
  
 -public interface ImageHandler {
 +import org.apache.xmlgraphics.image.loader.Image;
- import org.apache.xmlgraphics.image.loader.ImageFlavor;
  
 -    /**
 -     * Returns the priority for this image handler. A lower value means higher priority. This
 -     * information is used to build the ordered/prioritized list of supported ImageFlavors.
 -     * The built-in handlers use priorities between 100 and 999.
 -     * @return a positive integer (>0) indicating the priority
 -     */
 -    int getPriority();
 +/**
-  * This interface is used for handling all sorts of image types for PDF output.
++ * This interface is a service provider interface for image handlers.
 + */
- public interface ImageHandler {
-     /**
-      * Returns the priority for this image handler. A lower value means higher priority. This
-      * information is used to build the ordered/prioritized list of supported ImageFlavors.
-      * The built-in handlers use priorities between 100 and 999.
-      * @return a positive integer (>0) indicating the priority
-      */
-     int getPriority();
-     /**
-      * Returns the {@link ImageFlavor}s supported by this instance
-      * @return the supported image flavors
-      */
-     ImageFlavor[] getSupportedImageFlavors();
++public interface ImageHandler extends ImageHandlerBase {
  
      /**
 -     * Returns the {@link ImageFlavor}s supported by this instance
 -     * @return the supported image flavors
 +     * Indicates whether the image handler is compatible with the indicated target represented
 +     * by the rendering context object and with the image to be processed. The image is also
 +     * passed as a parameter because a handler might not support every subtype of image that is
 +     * presented. For example: in the case of {@code ImageXMLDOM}, the image might carry an SVG
 +     * or some other XML format. One handler might only handle SVG but no other XML format.
 +     * @param targetContext the target rendering context
 +     * @param image the image to be processed (or null if only to check based on the rendering
 +     *              context)
 +     * @return true if this handler is compatible with the target rendering context
       */
 -    ImageFlavor[] getSupportedImageFlavors();
 +    boolean isCompatible(RenderingContext targetContext, Image image);
  
-     /**
-      * Returns the {@link Image} subclass supported by this instance.
-      * @return the Image type
-      */
-     Class getSupportedImageClass();
      /**
 -     * Returns the {@link Class} subclass supported by this instance.
 -     * @return the image Class type
 +     * Handles the given {@link Image} instance painting it at the indicated position in the
 +     * output format being generated.
 +     * @param context the rendering context
 +     * @param image the image to be handled
 +     * @param pos the position and scaling of the image relative to the origin point of the
 +     *          current viewport (in millipoints)
 +     * @throws IOException if an I/O error occurs
       */
 -    Class getSupportedImageClass();
 +    void handleImage(RenderingContext context, Image image,
 +            Rectangle pos) throws IOException;
 +
  }
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f07c8967136d716fdd6d04c7ac58ecfe2dcb6833
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,50 @@@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one or more
++ * contributor license agreements.  See the NOTICE file distributed with
++ * this work for additional information regarding copyright ownership.
++ * The ASF licenses this file to You under the Apache License, Version 2.0
++ * (the "License"); you may not use this file except in compliance with
++ * the License.  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++/* $Id$ */
++
++package org.apache.fop.render;
++
++import org.apache.xmlgraphics.image.loader.ImageFlavor;
++
++/**
++ * This interface is a service provider base interface for image handlers. It only contains
++ * methods necessary for registration and is extended by sub-interfaces with the actual
++ * image handling contract.
++ */
++public interface ImageHandlerBase {
++
++    /**
++     * Returns the priority for this image handler. A lower value means higher priority. This
++     * information is used to build the ordered/prioritized list of supported ImageFlavors.
++     * The built-in handlers use priorities between 100 and 999.
++     * @return a positive integer (>0) indicating the priority
++     */
++    int getPriority();
++
++    /**
++     * Returns the {@link ImageFlavor}s supported by this instance
++     * @return the supported image flavors
++     */
++    ImageFlavor[] getSupportedImageFlavors();
++
++    /**
++     * Returns the {@link Class} subclass supported by this instance.
++     * @return the image Class type
++     */
++    Class getSupportedImageClass();
++}
index 818e31568777984d59fa255ea4b319d9ea4ecf28,e4ec41e0b1ccf15dc3bd6341a5f7de180bf2af41..76f727e8402441abf44e635bbca7a2144b6a7948
@@@ -24,9 -24,6 +24,7 @@@ import java.awt.geom.Rectangle2D
  import java.util.List;
  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;
index b0eeeb202fd49a4ef6b8326dd885578caea2cd2a,0000000000000000000000000000000000000000..23bd9a182ef1c7e49c4d9eb2c4b48bde9fd8965b
mode 100644,000000..100644
--- /dev/null
@@@ -1,3 -1,0 +1,1 @@@
- <?xml version="1.0" encoding="UTF-8"?><catalogue xml:lang="en">
-   <message key="org.apache.fop.render.afp.AFPEventProducer.warnDefaultFontSetup">No AFP fonts configured. Using default setup.</message>
- </catalogue>
++<?xml version="1.0" encoding="UTF-8"?><catalogue xml:lang="en"/>
index 0000000000000000000000000000000000000000,3ec3ea0b11153942a6afd72ba2a513179a546fd6..a6d2d613d26a5c8a8059d9026c7f1bff69fd8170
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,104 +1,104 @@@
 -import org.apache.fop.render.ImageHandler;
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one or more
+  * contributor license agreements.  See the NOTICE file distributed with
+  * this work for additional information regarding copyright ownership.
+  * The ASF licenses this file to You under the Apache License, Version 2.0
+  * (the "License"); you may not use this file except in compliance with
+  * the License.  You may obtain a copy of the License at
+  *
+  *      http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  */
+ /* $Id$ */
+ package org.apache.fop.render.afp;
+ import java.awt.Point;
+ import java.awt.geom.Rectangle2D;
+ import java.io.IOException;
+ import java.util.Map;
+ import org.apache.fop.afp.AFPDataObjectInfo;
+ import org.apache.fop.afp.AFPObjectAreaInfo;
+ import org.apache.fop.afp.AFPPaintingState;
+ import org.apache.fop.afp.AFPResourceInfo;
+ import org.apache.fop.afp.AFPUnitConverter;
 -public abstract class AFPImageHandler implements ImageHandler {
++import org.apache.fop.render.ImageHandlerBase;
+ /**
+  * A base abstract AFP image handler
+  */
++public abstract class AFPImageHandler implements ImageHandlerBase {
+     private static final int X = 0;
+     private static final int Y = 1;
+     /** foreign attribute reader */
+     private final AFPForeignAttributeReader foreignAttributeReader
+         = new AFPForeignAttributeReader();
+     /**
+      * Generates an intermediate AFPDataObjectInfo that is later used to construct
+      * the appropriate data object in the AFP DataStream.
+      *
+      * @param rendererImageInfo the renderer image info
+      * @return a data object info object
+      * @throws IOException thrown if an I/O exception of some sort has occurred.
+      */
+     public AFPDataObjectInfo generateDataObjectInfo(
+             AFPRendererImageInfo rendererImageInfo) throws IOException {
+         AFPDataObjectInfo dataObjectInfo = createDataObjectInfo();
+         // set resource information
+         Map foreignAttributes = rendererImageInfo.getForeignAttributes();
+         AFPResourceInfo resourceInfo
+             = foreignAttributeReader.getResourceInfo(foreignAttributes);
+         resourceInfo.setUri(rendererImageInfo.getURI());
+         dataObjectInfo.setResourceInfo(resourceInfo);
+         // set object area
+         AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo();
+         Point origin = rendererImageInfo.getOrigin();
+         Rectangle2D position = rendererImageInfo.getPosition();
+         float srcX = origin.x + (float)position.getX();
+         float srcY = origin.y + (float)position.getY();
+         AFPRendererContext rendererContext
+             = (AFPRendererContext)rendererImageInfo.getRendererContext();
+         AFPInfo afpInfo = rendererContext.getInfo();
+         AFPPaintingState paintingState = afpInfo.getPaintingState();
+         AFPUnitConverter unitConv = paintingState.getUnitConverter();
+         int[] coords = unitConv.mpts2units(new float[] {srcX, srcY});
+         objectAreaInfo.setX(coords[X]);
+         objectAreaInfo.setY(coords[Y]);
+         int width = Math.round(unitConv.mpt2units((float)position.getWidth()));
+         objectAreaInfo.setWidth(width);
+         int height = Math.round(unitConv.mpt2units((float)position.getHeight()));
+         objectAreaInfo.setHeight(height);
+         int resolution = paintingState.getResolution();
+         objectAreaInfo.setHeightRes(resolution);
+         objectAreaInfo.setWidthRes(resolution);
+         objectAreaInfo.setRotation(paintingState.getRotation());
+         dataObjectInfo.setObjectAreaInfo(objectAreaInfo);
+         return dataObjectInfo;
+     }
+     /**
+      * Creates the data object information object
+      *
+      * @return the data object information object
+      */
+     protected abstract AFPDataObjectInfo createDataObjectInfo();
+ }
index 70e0f7eb5a2540f501da502e46f72339777930a9,0000000000000000000000000000000000000000..4b0f35bec24186e467b1bbc3737bc28401536748
mode 100644,000000..100644
--- /dev/null
@@@ -1,331 -1,0 +1,331 @@@
- import org.apache.fop.pdf.PDFState;
 +/*
 + * 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.Color;
 +import java.awt.Rectangle;
 +import java.awt.geom.AffineTransform;
 +import java.io.IOException;
 +import java.io.OutputStream;
 +
 +import org.apache.fop.pdf.PDFColor;
 +import org.apache.fop.pdf.PDFDocument;
 +import org.apache.fop.pdf.PDFFilterList;
 +import org.apache.fop.pdf.PDFNumber;
++import org.apache.fop.pdf.PDFPaintingState;
 +import org.apache.fop.pdf.PDFResourceContext;
-     protected PDFState currentState = null;
 +import org.apache.fop.pdf.PDFStream;
 +import org.apache.fop.pdf.PDFTextUtil;
 +import org.apache.fop.pdf.PDFXObject;
 +
 +/**
 + * Generator class encapsulating all object references and state necessary to generate a
 + * PDF content stream.
 + */
 +public class PDFContentGenerator {
 +
 +    /** Controls whether comments are written to the PDF stream. */
 +    protected static final boolean WRITE_COMMENTS = true;
 +
 +    private PDFDocument document;
 +    private OutputStream outputStream;
 +    private PDFResourceContext resourceContext;
 +
 +    /** the current stream to add PDF commands to */
 +    private PDFStream currentStream;
 +
 +    /** drawing state */
-         this.currentState = new PDFState();
++    protected PDFPaintingState currentState = null;
 +    /** Text generation utility holding the current font status */
 +    protected PDFTextUtil textutil;
 +
 +
 +    /**
 +     * Main constructor. Creates a new PDF stream and additional helper classes for text painting
 +     * and state management.
 +     * @param document the PDF document
 +     * @param out the output stream the PDF document is generated to
 +     * @param resourceContext the resource context
 +     */
 +    public PDFContentGenerator(PDFDocument document, OutputStream out,
 +            PDFResourceContext resourceContext) {
 +        this.document = document;
 +        this.outputStream = out;
 +        this.resourceContext = resourceContext;
 +        this.currentStream = document.getFactory()
 +                .makeStream(PDFFilterList.CONTENT_FILTER, false);
 +        this.textutil = new PDFTextUtil() {
 +            protected void write(String code) {
 +                currentStream.add(code);
 +            }
 +        };
 +
-     public PDFState getState() {
++        this.currentState = new PDFPaintingState();
 +    }
 +
 +    /**
 +     * Returns the applicable resource context for the generator.
 +     * @return the resource context
 +     */
 +    public PDFDocument getDocument() {
 +        return this.document;
 +    }
 +
 +    /**
 +     * Returns the output stream the PDF document is written to.
 +     * @return the output stream
 +     */
 +    public OutputStream getOutputStream() {
 +        return this.outputStream;
 +    }
 +
 +    /**
 +     * Returns the applicable resource context for the generator.
 +     * @return the resource context
 +     */
 +    public PDFResourceContext getResourceContext() {
 +        return this.resourceContext;
 +    }
 +
 +    /**
 +     * Returns the {@code PDFStream} associated with this instance.
 +     * @return the PDF stream
 +     */
 +    public PDFStream getStream() {
 +        return this.currentStream;
 +    }
 +
 +    /**
 +     * Returns the {@code PDFState} associated with this instance.
 +     * @return the PDF state
 +     */
-         currentState.push();
++    public PDFPaintingState getState() {
 +        return this.currentState;
 +    }
 +
 +    /**
 +     * Returns the {@code PDFTextUtil} associated with this instance.
 +     * @return the text utility
 +     */
 +    public PDFTextUtil getTextUtil() {
 +        return this.textutil;
 +    }
 +
 +    /**
 +     * Flushes all queued PDF objects ready to be written to the output stream.
 +     * @throws IOException if an error occurs while flushing the PDF objects
 +     */
 +    public void flushPDFDoc() throws IOException {
 +        this.document.output(this.outputStream);
 +    }
 +
 +    /**
 +     * Writes out a comment.
 +     * @param text text for the comment
 +     */
 +    protected void comment(String text) {
 +        if (WRITE_COMMENTS) {
 +            currentStream.add("% " + text + "\n");
 +        }
 +    }
 +
 +    /** {@inheritDoc} */
 +    protected void saveGraphicsState() {
 +        endTextObject();
-             currentState.pop();
++        currentState.save();
 +        currentStream.add("q\n");
 +    }
 +
 +    /**
 +     * Restored the graphics state valid before the previous {@code #saveGraphicsState()}.
 +     * @param popState true if the state should also be popped, false if only the PDF command
 +     *           should be issued
 +     */
 +    protected void restoreGraphicsState(boolean popState) {
 +        endTextObject();
 +        currentStream.add("Q\n");
 +        if (popState) {
++            currentState.restore();
 +        }
 +    }
 +
 +    /** {@inheritDoc} */
 +    protected void restoreGraphicsState() {
 +        restoreGraphicsState(true);
 +    }
 +
 +    /** Indicates the beginning of a text object. */
 +    protected void beginTextObject() {
 +        if (!textutil.isInTextObject()) {
 +            textutil.beginTextObject();
 +        }
 +    }
 +
 +    /** Indicates the end of a text object. */
 +    protected void endTextObject() {
 +        if (textutil.isInTextObject()) {
 +            textutil.endTextObject();
 +        }
 +    }
 +
 +    /**
 +     * Concatenates the given transformation matrix with the current one.
 +     * @param transform the transformation matrix (in points)
 +     */
 +    public void concatenate(AffineTransform transform) {
 +        if (!transform.isIdentity()) {
 +            currentState.concatenate(transform);
 +            currentStream.add(CTMHelper.toPDFString(transform, false) + " cm\n");
 +        }
 +    }
 +
 +    /**
 +     * Intersects the current clip region with the given rectangle.
 +     * @param rect the clip rectangle
 +     */
 +    public void clipRect(Rectangle rect) {
 +        StringBuffer sb = new StringBuffer();
 +        sb.append(format(rect.x / 1000f)).append(' ');
 +        sb.append(format(rect.y / 1000f)).append(' ');
 +        sb.append(format(rect.width / 1000f)).append(' ');
 +        sb.append(format(rect.height / 1000f)).append(" re W n\n");
 +        add(sb.toString());
 +    }
 +
 +    /**
 +     * Adds content to the stream.
 +     * @param content the PDF content
 +     */
 +    public void add(String content) {
 +        currentStream.add(content);
 +    }
 +
 +    /**
 +     * Formats a float value (normally coordinates in points) as Strings.
 +     * @param value the value
 +     * @return the formatted value
 +     */
 +    public static final String format(float value) {
 +        return PDFNumber.doubleOut(value);
 +    }
 +
 +    /**
 +     * Sets the current line width in points.
 +     * @param width line width in points
 +     */
 +    public void updateLineWidth(float width) {
 +        if (currentState.setLineWidth(width)) {
 +            //Only write if value has changed WRT the current line width
 +            currentStream.add(format(width) + " w\n");
 +        }
 +    }
 +
 +    /**
 +     * Establishes a new foreground or fill color. In contrast to updateColor
 +     * this method does not check the PDFState for optimization possibilities.
 +     * @param col the color to apply
 +     * @param fill true to set the fill color, false for the foreground color
 +     * @param pdf StringBuffer to write the PDF code to
 +     *//*
 +    public void setColor(Color col, boolean fill, StringBuffer pdf) {
 +        assert pdf != null;
 +    }*/
 +
 +    /**
 +     * Establishes a new foreground or fill color.
 +     * @param col the color to apply
 +     * @param fill true to set the fill color, false for the foreground color
 +     * @param stream the PDFStream to write the PDF code to
 +     */
 +    public void setColor(Color col, boolean fill, PDFStream stream) {
 +        assert stream != null;
 +        PDFColor color = new PDFColor(this.document, col);
 +        stream.add(color.getColorSpaceOut(fill));
 +    }
 +
 +    /**
 +     * Establishes a new foreground or fill color.
 +     * @param col the color to apply
 +     * @param fill true to set the fill color, false for the foreground color
 +     */
 +    public void setColor(Color col, boolean fill) {
 +        setColor(col, fill, getStream());
 +    }
 +
 +    /**
 +     * Establishes a new foreground or fill color. In contrast to updateColor
 +     * this method does not check the PDFState for optimization possibilities.
 +     * @param col the color to apply
 +     * @param fill true to set the fill color, false for the foreground color
 +     * @param pdf StringBuffer to write the PDF code to, if null, the code is
 +     *     written to the current stream.
 +     */
 +    protected void setColor(Color col, boolean fill, StringBuffer pdf) {
 +        if (pdf != null) {
 +            PDFColor color = new PDFColor(this.document, col);
 +            pdf.append(color.getColorSpaceOut(fill));
 +        } else {
 +            setColor(col, fill, this.currentStream);
 +        }
 +    }
 +
 +    /**
 +     * Establishes a new foreground or fill color.
 +     * @param col the color to apply (null skips this operation)
 +     * @param fill true to set the fill color, false for the foreground color
 +     * @param pdf StringBuffer to write the PDF code to, if null, the code is
 +     *     written to the current stream.
 +     */
 +    public void updateColor(Color col, boolean fill, StringBuffer pdf) {
 +        if (col == null) {
 +            return;
 +        }
 +        boolean update = false;
 +        if (fill) {
 +            update = getState().setBackColor(col);
 +        } else {
 +            update = getState().setColor(col);
 +        }
 +
 +        if (update) {
 +            setColor(col, fill, pdf);
 +        }
 +    }
 +
 +    /**
 +     * Places a previously registered image at a certain place on the page.
 +     * @param x X coordinate
 +     * @param y Y coordinate
 +     * @param w width for image
 +     * @param h height for image
 +     * @param xobj the image XObject
 +     */
 +    public void placeImage(float x, float y, float w, float h, PDFXObject xobj) {
 +        saveGraphicsState();
 +        add(format(w) + " 0 0 "
 +                          + format(-h) + " "
 +                          + format(x) + " "
 +                          + format(y + h)
 +                          + " cm\n" + xobj.getName() + " Do\n");
 +        restoreGraphicsState();
 +    }
 +
 +
 +}
index 4da7f13cbecbbcb7600731a8250f8ae3d0989cf8,01d863e6a3bd9fb96ca351abe53a9a1e1f6f5fde..102c1ab45974595bdcf3e4b36c05c8f2d8418e3a
@@@ -97,8 -95,8 +97,8 @@@ public class PDFGraphics2DAdapter exten
  
          AffineTransform transform = new AffineTransform();
          transform.translate(fx, fy);
 -        pdfInfo.pdfPaintingState.concatenate(transform);
 -        graphics.setPaintingState(pdfInfo.pdfPaintingState);
 +        generator.getState().concatenate(transform);
-         graphics.setPDFState(generator.getState());
++        graphics.setPaintingState(generator.getState());
          graphics.setOutputStream(pdfInfo.outputStream);
  
          if (pdfInfo.paintAsBitmap) {
index f93ee5a9732f8888410cf750db01a6c40ad2ede5,6343d0c50321f85084bdb4e376e2abadf329a4a0..934d306b9ff9d5b01355e4c4c5b8508125b96e6f
@@@ -23,36 -23,15 +23,16 @@@ import java.awt.Point
  import java.awt.Rectangle;
  import java.io.IOException;
  
- import org.apache.xmlgraphics.image.loader.ImageFlavor;
 +import org.apache.xmlgraphics.image.loader.Image;
 +
  import org.apache.fop.pdf.PDFXObject;
 -import org.apache.fop.render.ImageHandler;
++import org.apache.fop.render.ImageHandlerBase;
  import org.apache.fop.render.RendererContext;
 -import org.apache.xmlgraphics.image.loader.Image;
  
  /**
   * This interface is used for handling all sorts of image type for PDF output.
   */
- public interface PDFImageHandler {
-     /**
-      * Returns the priority for this image handler. A lower value means higher priority. This
-      * information is used to build the ordered/prioritized list of supported ImageFlavors for
-      * the PDF renderer. The built-in handlers use priorities between 100 and 999.
-      * @return a positive integer (>0) indicating the priority
-      */
-     int getPriority();
-     /**
-      * Returns the {@link ImageFlavor}s supported by this instance
-      * @return the supported image flavors
-      */
-     ImageFlavor[] getSupportedImageFlavors();
-     /**
-      * Returns the {@link Image} subclass supported by this instance.
-      * @return the Image type
-      */
-     Class getSupportedImageClass();
 -public interface PDFImageHandler extends ImageHandler {
++public interface PDFImageHandler extends ImageHandlerBase {
  
      /**
       * Generates the PDF objects for the given {@link Image} instance. If the handler generates
index 610fa274fe13cad27f80822455326aed0092c285,3e4a9b3541c766bde1dd51043cc6f8355f86b855..18717809d352bb3fa6c1432033295fca847ac78f
@@@ -67,58 -49,6 +67,58 @@@ public class PDFImageHandlerGraphics2D 
          return null;
      }
  
-         graphics.setPDFState(generator.getState());
 +    /** {@inheritDoc} */
 +    public void handleImage(RenderingContext context, Image image, Rectangle pos)
 +                throws IOException {
 +        PDFRenderingContext pdfContext = (PDFRenderingContext)context;
 +        PDFContentGenerator generator = pdfContext.getGenerator();
 +        ImageGraphics2D imageG2D = (ImageGraphics2D)image;
 +        float fwidth = pos.width / 1000f;
 +        float fheight = pos.height / 1000f;
 +        float fx = pos.x / 1000f;
 +        float fy = pos.y / 1000f;
 +
 +        // get the 'width' and 'height' attributes of the SVG document
 +        Dimension dim = image.getInfo().getSize().getDimensionMpt();
 +        float imw = (float)dim.getWidth() / 1000f;
 +        float imh = (float)dim.getHeight() / 1000f;
 +
 +        float sx = fwidth / (float)imw;
 +        float sy = fheight / (float)imh;
 +
 +        generator.comment("G2D start");
 +        generator.saveGraphicsState();
 +        generator.updateColor(Color.black, false, null);
 +        generator.updateColor(Color.black, true, null);
 +
 +        //TODO Clip to the image area.
 +
 +        // transform so that the coordinates (0,0) is from the top left
 +        // and positive is down and to the right. (0,0) is where the
 +        // viewBox puts it.
 +        generator.add(sx + " 0 0 " + sy + " " + fx + " " + fy + " cm\n");
 +
 +        final boolean textAsShapes = false;
 +        PDFGraphics2D graphics = new PDFGraphics2D(textAsShapes,
 +                pdfContext.getFontInfo(), generator.getDocument(),
 +                generator.getResourceContext(), pdfContext.getPage().referencePDF(),
 +                "", 0.0f);
 +        graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
 +
 +        AffineTransform transform = new AffineTransform();
 +        transform.translate(fx, fy);
 +        generator.getState().concatenate(transform);
++        graphics.setPaintingState(generator.getState());
 +        graphics.setOutputStream(generator.getOutputStream());
 +
 +        Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh);
 +        imageG2D.getGraphics2DImagePainter().paint(graphics, area);
 +
 +        generator.add(graphics.getString());
 +        generator.restoreGraphicsState();
 +        generator.comment("G2D end");
 +    }
 +
      /** {@inheritDoc} */
      public int getPriority() {
          return 200;
index 3764486b78ad3169ab865f2c937ed2dc773eaa35,0000000000000000000000000000000000000000..d1b7aa9867d202bebadcf407256c774a953fd505
mode 100644,000000..100644
--- /dev/null
@@@ -1,200 -1,0 +1,200 @@@
-         generator.getState().push();
 +/*
 + * 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.Color;
 +import java.awt.Rectangle;
 +import java.awt.geom.AffineTransform;
 +import java.io.IOException;
 +
 +import org.apache.batik.bridge.BridgeContext;
 +import org.apache.batik.bridge.GVTBuilder;
 +import org.apache.batik.dom.svg.SVGDOMImplementation;
 +import org.apache.batik.gvt.GraphicsNode;
 +import org.apache.batik.util.SVGConstants;
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +import org.apache.xmlgraphics.image.loader.Image;
 +import org.apache.xmlgraphics.image.loader.ImageFlavor;
 +import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
 +
 +import org.apache.fop.apps.FOUserAgent;
 +import org.apache.fop.image.loader.batik.BatikImageFlavors;
 +import org.apache.fop.render.ImageHandler;
 +import org.apache.fop.render.RenderingContext;
 +import org.apache.fop.svg.PDFAElementBridge;
 +import org.apache.fop.svg.PDFBridgeContext;
 +import org.apache.fop.svg.PDFGraphics2D;
 +import org.apache.fop.svg.SVGEventProducer;
 +import org.apache.fop.svg.SVGUserAgent;
 +
 +/**
 + * Image Handler implementation which handles SVG images.
 + */
 +public class PDFImageHandlerSVG implements ImageHandler {
 +
 +    /** logging instance */
 +    private static Log log = LogFactory.getLog(PDFImageHandlerSVG.class);
 +
 +    /** {@inheritDoc} */
 +    public void handleImage(RenderingContext context, Image image, Rectangle pos)
 +                throws IOException {
 +        PDFRenderingContext pdfContext = (PDFRenderingContext)context;
 +        PDFContentGenerator generator = pdfContext.getGenerator();
 +        ImageXMLDOM imageSVG = (ImageXMLDOM)image;
 +
 +        FOUserAgent userAgent = context.getUserAgent();
 +        final float deviceResolution = userAgent.getTargetResolution();
 +        if (log.isDebugEnabled()) {
 +            log.debug("Generating SVG at " + deviceResolution + "dpi.");
 +        }
 +
 +        final float uaResolution = userAgent.getSourceResolution();
 +        SVGUserAgent ua = new SVGUserAgent(userAgent, new AffineTransform());
 +
 +        //Scale for higher resolution on-the-fly images from Batik
 +        double s = uaResolution / deviceResolution;
 +        AffineTransform resolutionScaling = new AffineTransform();
 +        resolutionScaling.scale(s, s);
 +
 +        GVTBuilder builder = new GVTBuilder();
 +
 +        //Controls whether text painted by Batik is generated using text or path operations
 +        boolean strokeText = false;
 +        //TODO connect with configuration elsewhere.
 +
 +        BridgeContext ctx = new PDFBridgeContext(ua,
 +                (strokeText ? null : pdfContext.getFontInfo()),
 +                userAgent.getFactory().getImageManager(),
 +                userAgent.getImageSessionContext(),
 +                new AffineTransform());
 +
 +        GraphicsNode root;
 +        try {
 +            root = builder.build(ctx, imageSVG.getDocument());
 +            builder = null;
 +        } catch (Exception e) {
 +            SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
 +                    context.getUserAgent().getEventBroadcaster());
 +            eventProducer.svgNotBuilt(this, e, image.getInfo().getOriginalURI());
 +            return;
 +        }
 +        // get the 'width' and 'height' attributes of the SVG document
 +        float w = (float)ctx.getDocumentSize().getWidth() * 1000f;
 +        float h = (float)ctx.getDocumentSize().getHeight() * 1000f;
 +
 +        float sx = pos.width / (float)w;
 +        float sy = pos.height / (float)h;
 +
 +        //Scaling and translation for the bounding box of the image
 +        AffineTransform scaling = new AffineTransform(
 +                sx, 0, 0, sy, pos.x / 1000f, pos.y / 1000f);
 +
 +        //Transformation matrix that establishes the local coordinate system for the SVG graphic
 +        //in relation to the current coordinate system
 +        AffineTransform imageTransform = new AffineTransform();
 +        imageTransform.concatenate(scaling);
 +        imageTransform.concatenate(resolutionScaling);
 +
 +        /*
 +         * Clip to the svg area.
 +         * Note: To have the svg overlay (under) a text area then use
 +         * an fo:block-container
 +         */
 +        generator.comment("SVG setup");
 +        generator.saveGraphicsState();
 +        generator.setColor(Color.black, false);
 +        generator.setColor(Color.black, true);
 +
 +        if (!scaling.isIdentity()) {
 +            generator.comment("viewbox");
 +            generator.add(CTMHelper.toPDFString(scaling, false) + " cm\n");
 +        }
 +
 +        //SVGSVGElement svg = ((SVGDocument)doc).getRootElement();
 +
 +        PDFGraphics2D graphics = new PDFGraphics2D(true, pdfContext.getFontInfo(),
 +                generator.getDocument(),
 +                generator.getResourceContext(), pdfContext.getPage().referencePDF(),
 +                "", 0);
 +        graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
 +
 +        if (!resolutionScaling.isIdentity()) {
 +            generator.comment("resolution scaling for " + uaResolution
 +                        + " -> " + deviceResolution + "\n");
 +            generator.add(
 +                    CTMHelper.toPDFString(resolutionScaling, false) + " cm\n");
 +            graphics.scale(1 / s, 1 / s);
 +        }
 +
 +        generator.comment("SVG start");
 +
 +        //Save state and update coordinate system for the SVG image
-         graphics.setPDFState(generator.getState());
++        generator.getState().save();
 +        generator.getState().concatenate(imageTransform);
 +
 +        //Now that we have the complete transformation matrix for the image, we can update the
 +        //transformation matrix for the AElementBridge.
 +        PDFAElementBridge aBridge = (PDFAElementBridge)ctx.getBridge(
 +                SVGDOMImplementation.SVG_NAMESPACE_URI, SVGConstants.SVG_A_TAG);
 +        aBridge.getCurrentTransform().setTransform(generator.getState().getTransform());
 +
-         generator.getState().pop();
++        graphics.setPaintingState(generator.getState());
 +        graphics.setOutputStream(generator.getOutputStream());
 +        try {
 +            root.paint(graphics);
 +            generator.add(graphics.getString());
 +        } catch (Exception e) {
 +            SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
 +                    context.getUserAgent().getEventBroadcaster());
 +            eventProducer.svgRenderingError(this, e, image.getInfo().getOriginalURI());
 +        }
++        generator.getState().restore();
 +        generator.restoreGraphicsState();
 +        generator.comment("SVG end");
 +    }
 +
 +    /** {@inheritDoc} */
 +    public int getPriority() {
 +        return 400;
 +    }
 +
 +    /** {@inheritDoc} */
 +    public Class getSupportedImageClass() {
 +        return ImageXMLDOM.class;
 +    }
 +
 +    /** {@inheritDoc} */
 +    public ImageFlavor[] getSupportedImageFlavors() {
 +        return new ImageFlavor[] {
 +                BatikImageFlavors.SVG_DOM
 +            };
 +    }
 +
 +    /** {@inheritDoc} */
 +    public boolean isCompatible(RenderingContext targetContext, Image image) {
 +        return (image == null
 +                || (image instanceof ImageXMLDOM
 +                        && image.getFlavor().isCompatible(BatikImageFlavors.SVG_DOM)))
 +                && targetContext instanceof PDFRenderingContext;
 +    }
 +
 +}
index 730acb5404fe856d33fada30486fd8b201291fd9,e31f1eaeae82965575a5d156c6fb06f5fdd52c8e..e0e1bab6927d34a7ac29e0f89eef9cef1d43ffc8
@@@ -73,27 -74,49 +73,28 @@@ import org.apache.fop.fonts.Typeface
  import org.apache.fop.pdf.PDFAMode;
  import org.apache.fop.pdf.PDFAction;
  import org.apache.fop.pdf.PDFAnnotList;
 -import org.apache.fop.pdf.PDFColor;
 -import org.apache.fop.pdf.PDFConformanceException;
 -import org.apache.fop.pdf.PDFDictionary;
  import org.apache.fop.pdf.PDFDocument;
 -import org.apache.fop.pdf.PDFEncryptionManager;
  import org.apache.fop.pdf.PDFEncryptionParams;
  import org.apache.fop.pdf.PDFFactory;
 -import org.apache.fop.pdf.PDFFilterList;
  import org.apache.fop.pdf.PDFGoTo;
 -import org.apache.fop.pdf.PDFICCBasedColorSpace;
 -import org.apache.fop.pdf.PDFICCStream;
  import org.apache.fop.pdf.PDFInfo;
  import org.apache.fop.pdf.PDFLink;
 -import org.apache.fop.pdf.PDFMetadata;
  import org.apache.fop.pdf.PDFNumber;
 -import org.apache.fop.pdf.PDFNumsArray;
  import org.apache.fop.pdf.PDFOutline;
 -import org.apache.fop.pdf.PDFOutputIntent;
  import org.apache.fop.pdf.PDFPage;
 -import org.apache.fop.pdf.PDFPageLabels;
+ import org.apache.fop.pdf.PDFPaintingState;
  import org.apache.fop.pdf.PDFResourceContext;
  import org.apache.fop.pdf.PDFResources;
- import org.apache.fop.pdf.PDFState;
 -import org.apache.fop.pdf.PDFStream;
  import org.apache.fop.pdf.PDFTextUtil;
  import org.apache.fop.pdf.PDFXMode;
  import org.apache.fop.pdf.PDFXObject;
  import org.apache.fop.render.AbstractPathOrientedRenderer;
  import org.apache.fop.render.Graphics2DAdapter;
  import org.apache.fop.render.RendererContext;
 +import org.apache.fop.traits.RuleStyle;
+ import org.apache.fop.util.AbstractPaintingState;
  import org.apache.fop.util.CharUtilities;
 -import org.apache.fop.util.ColorProfileUtil;
--import org.apache.fop.util.ColorUtil;
+ import org.apache.fop.util.AbstractPaintingState.AbstractData;
 -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.image.loader.util.ImageUtil;
 -import org.apache.xmlgraphics.xmp.Metadata;
 -import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter;
 -import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;
  
  /**
   * Renderer that renders areas to PDF.
@@@ -189,41 -240,243 +190,41 @@@ public class PDFRenderer extends Abstra
      /** page height */
      protected int pageHeight;
  
 -    /** Registry of PDF filters */
 -    protected Map filterMap;
 -
      /** Image handler registry */
-     private PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry();
+     private final PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry();
  
 +
      /**
       * create the PDF renderer
       */
      public PDFRenderer() {
      }
  
 -    private boolean booleanValueOf(Object obj) {
 -        if (obj instanceof Boolean) {
 -            return ((Boolean)obj).booleanValue();
 -        } else if (obj instanceof String) {
 -            return Boolean.valueOf((String)obj).booleanValue();
 -        } else {
 -            throw new IllegalArgumentException("Boolean or \"true\" or \"false\" expected.");
 -        }
 -    }
 -
 -    /**
 -     * {@inheritDoc}
 -     */
 +    /** {@inheritDoc} */
      public void setUserAgent(FOUserAgent agent) {
          super.setUserAgent(agent);
 -        PDFEncryptionParams params
 -                = (PDFEncryptionParams)agent.getRendererOptions().get(ENCRYPTION_PARAMS);
 -        if (params != null) {
 -            this.encryptionParams = params; //overwrite if available
 -        }
 -        String pwd;
 -        pwd = (String)agent.getRendererOptions().get(USER_PASSWORD);
 -        if (pwd != null) {
 -            if (encryptionParams == null) {
 -                this.encryptionParams = new PDFEncryptionParams();
 -            }
 -            this.encryptionParams.setUserPassword(pwd);
 -        }
 -        pwd = (String)agent.getRendererOptions().get(OWNER_PASSWORD);
 -        if (pwd != null) {
 -            if (encryptionParams == null) {
 -                this.encryptionParams = new PDFEncryptionParams();
 -            }
 -            this.encryptionParams.setOwnerPassword(pwd);
 -        }
 -        Object setting;
 -        setting = agent.getRendererOptions().get(NO_PRINT);
 -        if (setting != null) {
 -            if (encryptionParams == null) {
 -                this.encryptionParams = new PDFEncryptionParams();
 -            }
 -            this.encryptionParams.setAllowPrint(!booleanValueOf(setting));
 -        }
 -        setting = agent.getRendererOptions().get(NO_COPY_CONTENT);
 -        if (setting != null) {
 -            if (encryptionParams == null) {
 -                this.encryptionParams = new PDFEncryptionParams();
 -            }
 -            this.encryptionParams.setAllowCopyContent(!booleanValueOf(setting));
 -        }
 -        setting = agent.getRendererOptions().get(NO_EDIT_CONTENT);
 -        if (setting != null) {
 -            if (encryptionParams == null) {
 -                this.encryptionParams = new PDFEncryptionParams();
 -            }
 -            this.encryptionParams.setAllowEditContent(!booleanValueOf(setting));
 -        }
 -        setting = agent.getRendererOptions().get(NO_ANNOTATIONS);
 -        if (setting != null) {
 -            if (encryptionParams == null) {
 -                this.encryptionParams = new PDFEncryptionParams();
 -            }
 -            this.encryptionParams.setAllowEditAnnotations(!booleanValueOf(setting));
 -        }
 -        String s = (String)agent.getRendererOptions().get(PDF_A_MODE);
 -        if (s != null) {
 -            this.pdfAMode = PDFAMode.valueOf(s);
 -        }
 -        s = (String)agent.getRendererOptions().get(PDF_X_MODE);
 -        if (s != null) {
 -            this.pdfXMode = PDFXMode.valueOf(s);
 -        }
 -        s = (String)agent.getRendererOptions().get(KEY_OUTPUT_PROFILE);
 -        if (s != null) {
 -            this.outputProfileURI = s;
 -        }
 -        setting = agent.getRendererOptions().get(KEY_DISABLE_SRGB_COLORSPACE);
 -        if (setting != null) {
 -            this.disableSRGBColorSpace = booleanValueOf(setting);
 -        }
 +        this.pdfUtil = new PDFRenderingUtil(getUserAgent());
      }
  
 -    /**
 -     * {@inheritDoc}
 -     */
 -    public void startRenderer(OutputStream stream) throws IOException {
 -        if (userAgent == null) {
 -            throw new IllegalStateException("UserAgent must be set before starting the renderer");
 -        }
 -        ostream = stream;
 -        this.pdfDoc = new PDFDocument(
 -                userAgent.getProducer() != null ? userAgent.getProducer() : "");
 -        this.pdfDoc.getProfile().setPDFAMode(this.pdfAMode);
 -        this.pdfDoc.getProfile().setPDFXMode(this.pdfXMode);
 -        this.pdfDoc.getInfo().setCreator(userAgent.getCreator());
 -        this.pdfDoc.getInfo().setCreationDate(userAgent.getCreationDate());
 -        this.pdfDoc.getInfo().setAuthor(userAgent.getAuthor());
 -        this.pdfDoc.getInfo().setTitle(userAgent.getTitle());
 -        this.pdfDoc.getInfo().setKeywords(userAgent.getKeywords());
 -        this.pdfDoc.setFilterMap(filterMap);
 -        this.pdfDoc.outputHeader(ostream);
 -
 -        //Setup encryption if necessary
 -        PDFEncryptionManager.setupPDFEncryption(encryptionParams, this.pdfDoc);
 -
 -        addsRGBColorSpace();
 -        if (this.outputProfileURI != null) {
 -            addDefaultOutputProfile();
 -        }
 -        if (pdfXMode != PDFXMode.DISABLED) {
 -            log.debug(pdfXMode + " is active.");
 -            log.warn("Note: " + pdfXMode
 -                    + " support is work-in-progress and not fully implemented, yet!");
 -            addPDFXOutputIntent();
 -        }
 -        if (pdfAMode.isPDFA1LevelB()) {
 -            log.debug("PDF/A is active. Conformance Level: " + pdfAMode);
 -            addPDFA1OutputIntent();
 -        }
 -
 +    PDFRenderingUtil getPDFUtil() {
 +        return this.pdfUtil;
      }
  
 -    private void addsRGBColorSpace() throws IOException {
 -        if (disableSRGBColorSpace) {
 -            if (this.pdfAMode != PDFAMode.DISABLED
 -                    || this.pdfXMode != PDFXMode.DISABLED
 -                    || this.outputProfileURI != null) {
 -                throw new IllegalStateException("It is not possible to disable the sRGB color"
 -                        + " space if PDF/A or PDF/X functionality is enabled or an"
 -                        + " output profile is set!");
 -            }
 -        } else {
 -            if (this.sRGBColorSpace != null) {
 -                return;
 -            }
 -            //Map sRGB as default RGB profile for DeviceRGB
 -            this.sRGBColorSpace = PDFICCBasedColorSpace.setupsRGBAsDefaultRGBColorSpace(pdfDoc);
 -        }
 +    PDFContentGenerator getGenerator() {
 +        return this.generator;
      }
  
-     PDFState getState() {
 -    private void addDefaultOutputProfile() throws IOException {
 -        if (this.outputProfile != null) {
 -            return;
 -        }
 -        ICC_Profile profile;
 -        InputStream in = null;
 -        if (this.outputProfileURI != null) {
 -            this.outputProfile = pdfDoc.getFactory().makePDFICCStream();
 -            Source src = userAgent.resolveURI(this.outputProfileURI);
 -            if (src == null) {
 -                throw new IOException("Output profile not found: " + this.outputProfileURI);
 -            }
 -            if (src instanceof StreamSource) {
 -                in = ((StreamSource)src).getInputStream();
 -            } else {
 -                in = new URL(src.getSystemId()).openStream();
 -            }
 -            try {
 -                profile = ICC_Profile.getInstance(in);
 -            } finally {
 -                IOUtils.closeQuietly(in);
 -            }
 -            this.outputProfile.setColorSpace(profile, null);
 -        } else {
 -            //Fall back to sRGB profile
 -            outputProfile = sRGBColorSpace.getICCStream();
 -        }
++    PDFPaintingState getState() {
 +        return getGenerator().getState();
      }
  
 -    /**
 -     * Adds an OutputIntent to the PDF as mandated by PDF/A-1 when uncalibrated color spaces
 -     * are used (which is true if we use DeviceRGB to represent sRGB colors).
 -     * @throws IOException in case of an I/O problem
 -     */
 -    private void addPDFA1OutputIntent() throws IOException {
 -        addDefaultOutputProfile();
 -
 -        String desc = ColorProfileUtil.getICCProfileDescription(this.outputProfile.getICCProfile());
 -        PDFOutputIntent outputIntent = pdfDoc.getFactory().makeOutputIntent();
 -        outputIntent.setSubtype(PDFOutputIntent.GTS_PDFA1);
 -        outputIntent.setDestOutputProfile(this.outputProfile);
 -        outputIntent.setOutputConditionIdentifier(desc);
 -        outputIntent.setInfo(outputIntent.getOutputConditionIdentifier());
 -        pdfDoc.getRoot().addOutputIntent(outputIntent);
 -    }
 -
 -    /**
 -     * Adds an OutputIntent to the PDF as mandated by PDF/X when uncalibrated color spaces
 -     * are used (which is true if we use DeviceRGB to represent sRGB colors).
 -     * @throws IOException in case of an I/O problem
 -     */
 -    private void addPDFXOutputIntent() throws IOException {
 -        addDefaultOutputProfile();
 -
 -        String desc = ColorProfileUtil.getICCProfileDescription(this.outputProfile.getICCProfile());
 -        int deviceClass = this.outputProfile.getICCProfile().getProfileClass();
 -        if (deviceClass != ICC_Profile.CLASS_OUTPUT) {
 -            throw new PDFConformanceException(pdfDoc.getProfile().getPDFXMode() + " requires that"
 -                    + " the DestOutputProfile be an Output Device Profile. "
 -                    + desc + " does not match that requirement.");
 +    /** {@inheritDoc} */
 +    public void startRenderer(OutputStream stream) throws IOException {
 +        if (userAgent == null) {
 +            throw new IllegalStateException("UserAgent must be set before starting the renderer");
          }
 -        PDFOutputIntent outputIntent = pdfDoc.getFactory().makeOutputIntent();
 -        outputIntent.setSubtype(PDFOutputIntent.GTS_PDFX);
 -        outputIntent.setDestOutputProfile(this.outputProfile);
 -        outputIntent.setOutputConditionIdentifier(desc);
 -        outputIntent.setInfo(outputIntent.getOutputConditionIdentifier());
 -        pdfDoc.getRoot().addOutputIntent(outputIntent);
 +        ostream = stream;
 +        this.pdfDoc = pdfUtil.setupPDFDocument(stream);
      }
  
      /**
          pages = null;
  
          pageReferences.clear();
 -        pvReferences.clear();
 +        //pvReferences.clear();
          pdfResources = null;
 -        currentStream = null;
 +        this.generator = null;
-         //currentStream = null;
          currentContext = null;
          currentPage = null;
-         //currentState = null;
-         //this.textutil = null;
 -        paintingState = null;
 -        this.textutil = null;
  
          idPositions.clear();
          idGoTos.clear();
                      (float)clippingRect.getHeight() / 1000f);
          }
          // multiply with current CTM
 -        currentStream.add(CTMHelper.toPDFString(ctm) + " cm\n");
 +        generator.concatenate(new AffineTransform(CTMHelper.toPDFArray(ctm)));
-         //currentStream.add(CTMHelper.toPDFString(ctm) + " cm\n");
      }
  
      /** {@inheritDoc} */
  
      /** {@inheritDoc} */
      protected void concatenateTransformationMatrix(AffineTransform at) {
 -        if (!at.isIdentity()) {
 -            paintingState.concatenate(at);
 -            currentStream.add(CTMHelper.toPDFString(at, false) + " cm\n");
 -        }
 +        generator.concatenate(at);
-         /*
-         if (!at.isIdentity()) {
-             currentState.concatenate(at);
-             currentStream.add(CTMHelper.toPDFString(at, false) + " cm\n");
-         }*/
      }
  
      /**
      /**
       * {@inheritDoc}
       */
-     protected void fillRect(float x, float y, float w, float h) {
-         if (w != 0 && h != 0) {
+     protected void fillRect(float x, float y, float width, float height) {
+         if (width > 0 && height > 0) {
 -            currentStream.add(format(x) + " " + format(y) + " "
 +            generator.add(format(x) + " " + format(y) + " "
-                     + format(w) + " " + format(h) + " re f\n");
+                     + format(width) + " " + format(height) + " re f\n");
          }
      }
  
       * @return the saved state stack to recreate later
       */
      protected List breakOutOfStateStack() {
 -//        return currentState.popAll();
++        PDFPaintingState paintingState = getState();
          List breakOutList = new java.util.ArrayList();
-         PDFState.Data data;
+         AbstractPaintingState.AbstractData data;
          while (true) {
-             data = getState().getData();
-             if (getState().pop() == null) {
+             data = paintingState.getData();
+             if (paintingState.restore() == null) {
                  break;
              }
              if (breakOutList.size() == 0) {
       * @param breakOutList the state stack to restore.
       */
      protected void restoreStateStackAfterBreakOut(List breakOutList) {
 -        comment("------ restoring context after break-out...");
 +        generator.comment("------ restoring context after break-out...");
-         PDFState.Data data;
+ //        currentState.pushAll(breakOutList);
+         AbstractData data;
          Iterator i = breakOutList.iterator();
          while (i.hasNext()) {
-             data = (PDFState.Data)i.next();
+             data = (AbstractData)i.next();
              saveGraphicsState();
              AffineTransform at = data.getTransform();
              concatenateTransformationMatrix(at);
              info = manager.getImageInfo(uri, sessionContext);
  
              Map hints = ImageUtil.getDefaultHints(sessionContext);
 +            ImageFlavor[] supportedFlavors = imageHandlerRegistry.getSupportedFlavors();
              org.apache.xmlgraphics.image.loader.Image img = manager.getImage(
 -                        info, imageHandlerRegistry.getSupportedFlavors(), hints, sessionContext);
 +                        info, supportedFlavors, hints, sessionContext);
  
              //First check for a dynamically registered handler
-             PDFImageHandler handler = imageHandlerRegistry.getHandler(img.getClass());
+             PDFImageHandler handler
+                 = (PDFImageHandler)imageHandlerRegistry.getHandler(img.getClass());
              if (handler != null) {
                  if (log.isDebugEnabled()) {
                      log.debug("Using PDFImageHandler: " + handler.getClass().getName());
  
          // output new data
          try {
 -            this.pdfDoc.output(ostream);
 +            this.generator.flushPDFDoc();
          } catch (IOException ioe) {
              // ioexception will be caught later
+             log.error(ioe.getMessage());
          }
      }
  
                  x, y, width, height, foreignAttributes);
          context.setProperty(PDFRendererContextConstants.PDF_DOCUMENT, pdfDoc);
          context.setProperty(PDFRendererContextConstants.OUTPUT_STREAM, ostream);
-         context.setProperty(PDFRendererContextConstants.PDF_STATE, getState());
 -        context.setProperty(PDFRendererContextConstants.PDF_PAINTING_STATE, paintingState);
          context.setProperty(PDFRendererContextConstants.PDF_PAGE, currentPage);
          context.setProperty(PDFRendererContextConstants.PDF_CONTEXT,
                      currentContext == null ? currentPage : currentContext);
index d416f11472cb62b2d3c223655af9a9ec6394049a,8d1042f7fc64eb112c6e1479d20bc0952f09e6fb..fccba1c257c79f5126d3e8b146987d0153360d30
@@@ -71,82 -61,78 +73,83 @@@ public class PDFRendererConfigurator ex
          Configuration cfg = super.getRendererConfig(renderer);
          if (cfg != null) {
              PDFRenderer pdfRenderer = (PDFRenderer)renderer;
 -            //PDF filters
 -            try {
 -                Map filterMap = buildFilterMapFromConfiguration(cfg);
 -                if (filterMap != null) {
 -                    pdfRenderer.setFilterMap(filterMap);
 -                }
 -            } catch (ConfigurationException e) {
 -                LogUtil.handleException(log, e, false);
 -            }
 -
              super.configure(renderer);
  
 -            String s = cfg.getChild(PDFRenderer.PDF_A_MODE, true).getValue(null);
 -            if (s != null) {
 -                pdfRenderer.setAMode(PDFAMode.valueOf(s));
 -            }
 -            s = cfg.getChild(PDFRenderer.PDF_X_MODE, true).getValue(null);
 -            if (s != null) {
 -                pdfRenderer.setXMode(PDFXMode.valueOf(s));
 +            PDFRenderingUtil pdfUtil = pdfRenderer.getPDFUtil();
 +            configure(cfg, pdfUtil);
 +        }
 +    }
 +
 +    private void configure(Configuration cfg, PDFRenderingUtil pdfUtil) throws FOPException {
 +        //PDF filters
 +        try {
 +            Map filterMap = buildFilterMapFromConfiguration(cfg);
 +            if (filterMap != null) {
 +                pdfUtil.setFilterMap(filterMap);
              }
-         Configuration encryptionParamsConfig = cfg.getChild(PDFRenderer.ENCRYPTION_PARAMS, false);
 +        } catch (ConfigurationException e) {
 +            LogUtil.handleException(log, e, false);
 +        }
 +
 +        String s = cfg.getChild(PDFRenderer.PDF_A_MODE, true).getValue(null);
 +        if (s != null) {
 +            pdfUtil.setAMode(PDFAMode.valueOf(s));
 +        }
 +        s = cfg.getChild(PDFRenderer.PDF_X_MODE, true).getValue(null);
 +        if (s != null) {
 +            pdfUtil.setXMode(PDFXMode.valueOf(s));
 +        }
 -            if (encryptionParamsConfig != null) {
 -                PDFEncryptionParams encryptionParams = new PDFEncryptionParams();
 -                Configuration ownerPasswordConfig = encryptionParamsConfig.getChild(
 -                        PDFRenderer.OWNER_PASSWORD, false);
 -                if (ownerPasswordConfig != null) {
 -                    String ownerPassword = ownerPasswordConfig.getValue(null);
 -                    if (ownerPassword != null) {
 -                        encryptionParams.setOwnerPassword(ownerPassword);
 -                    }
 -                }
 -                Configuration userPasswordConfig = encryptionParamsConfig.getChild(
 -                        PDFRenderer.USER_PASSWORD, false);
 -                if (userPasswordConfig != null) {
 -                    String userPassword = userPasswordConfig.getValue(null);
 -                    if (userPassword != null) {
 -                        encryptionParams.setUserPassword(userPassword);
 -                    }
+             Configuration encryptionParamsConfig
+                 = cfg.getChild(PDFRenderer.ENCRYPTION_PARAMS, false);
 +        if (encryptionParamsConfig != null) {
 +            PDFEncryptionParams encryptionParams = new PDFEncryptionParams();
 +            Configuration ownerPasswordConfig = encryptionParamsConfig.getChild(
 +                    PDFRenderer.OWNER_PASSWORD, false);
 +            if (ownerPasswordConfig != null) {
 +                String ownerPassword = ownerPasswordConfig.getValue(null);
 +                if (ownerPassword != null) {
 +                    encryptionParams.setOwnerPassword(ownerPassword);
                  }
 -                Configuration noPrintConfig = encryptionParamsConfig.getChild(
 -                        PDFRenderer.NO_PRINT, false);
 -                if (noPrintConfig != null) {
 -                    encryptionParams.setAllowPrint(false);
 -                }
 -                Configuration noCopyContentConfig = encryptionParamsConfig.getChild(
 -                        PDFRenderer.NO_COPY_CONTENT, false);
 -                if (noCopyContentConfig != null) {
 -                    encryptionParams.setAllowCopyContent(false);
 -                }
 -                Configuration noEditContentConfig = encryptionParamsConfig.getChild(
 -                        PDFRenderer.NO_EDIT_CONTENT, false);
 -                if (noEditContentConfig != null) {
 -                    encryptionParams.setAllowEditContent(false);
 -                }
 -                Configuration noAnnotationsConfig = encryptionParamsConfig.getChild(
 -                        PDFRenderer.NO_ANNOTATIONS, false);
 -                if (noAnnotationsConfig != null) {
 -                    encryptionParams.setAllowEditAnnotations(false);
 +            }
 +            Configuration userPasswordConfig = encryptionParamsConfig.getChild(
 +                    PDFRenderer.USER_PASSWORD, false);
 +            if (userPasswordConfig != null) {
 +                String userPassword = userPasswordConfig.getValue(null);
 +                if (userPassword != null) {
 +                    encryptionParams.setUserPassword(userPassword);
                  }
 -                pdfRenderer.setEncryptionParams(encryptionParams);
              }
 -            s = cfg.getChild(PDFRenderer.KEY_OUTPUT_PROFILE, true).getValue(null);
 -            if (s != null) {
 -                pdfRenderer.setOutputProfileURI(s);
 +            Configuration noPrintConfig = encryptionParamsConfig.getChild(
 +                    PDFRenderer.NO_PRINT, false);
 +            if (noPrintConfig != null) {
 +                encryptionParams.setAllowPrint(false);
              }
-         Configuration disableColorSpaceConfig
-             = cfg.getChild(PDFRenderer.KEY_DISABLE_SRGB_COLORSPACE, false);
 +            Configuration noCopyContentConfig = encryptionParamsConfig.getChild(
 +                    PDFRenderer.NO_COPY_CONTENT, false);
 +            if (noCopyContentConfig != null) {
 +                encryptionParams.setAllowCopyContent(false);
 +            }
 +            Configuration noEditContentConfig = encryptionParamsConfig.getChild(
 +                    PDFRenderer.NO_EDIT_CONTENT, false);
 +            if (noEditContentConfig != null) {
 +                encryptionParams.setAllowEditContent(false);
 +            }
 +            Configuration noAnnotationsConfig = encryptionParamsConfig.getChild(
 +                    PDFRenderer.NO_ANNOTATIONS, false);
 +            if (noAnnotationsConfig != null) {
 +                encryptionParams.setAllowEditAnnotations(false);
 +            }
 +            pdfUtil.setEncryptionParams(encryptionParams);
 +        }
 +        s = cfg.getChild(PDFRenderer.KEY_OUTPUT_PROFILE, true).getValue(null);
 +        if (s != null) {
 +            pdfUtil.setOutputProfileURI(s);
 +        }
 -            if (disableColorSpaceConfig != null) {
 -                pdfRenderer.disableSRGBColorSpace
 -                    = disableColorSpaceConfig.getValueAsBoolean(false);
 -            }
+             Configuration disableColorSpaceConfig = cfg.getChild(
+                     PDFRenderer.KEY_DISABLE_SRGB_COLORSPACE, false);
 +        if (disableColorSpaceConfig != null) {
 +            pdfUtil.setDisableSRGBColorSpace(
 +                    disableColorSpaceConfig.getValueAsBoolean(false));
          }
      }
  
index de51aabc70f193d353131c529a1d97d9898b34f8,33888d44228e1e65833842f332790ac78160966d..11380bf595d83f98ea17ea1e1306b5528c775f42
@@@ -29,9 -29,9 +29,6 @@@ public interface PDFRendererContextCons
      /** The PDF document that this image is being drawn into. */
      String PDF_DOCUMENT = "pdfDoc";
  
-     /** The current pdf state. */
-     String PDF_STATE = "pdfState";
 -    /** The current PDF painting state. */
 -    String PDF_PAINTING_STATE = "pdfPaintingState";
--
      /** The current PDF page for page renference and as a resource context. */
      String PDF_PAGE = "pdfPage";
  
index 11d9b1c3f8ee32e28e1cc19178c90bc634b06051,41f48df55c13a48772e0ff823b604620b3f1d8c6..8f7aad3001aa5a5963246e950db63f9393ecf928
@@@ -36,14 -36,14 +36,12 @@@ import org.apache.batik.util.SVGConstan
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  
- import org.apache.xmlgraphics.util.QName;
  import org.apache.fop.apps.FOUserAgent;
- import org.apache.fop.fo.extensions.ExtensionElementMapping;
  import org.apache.fop.fonts.FontInfo;
+ import org.apache.fop.image.loader.batik.BatikUtil;
  import org.apache.fop.pdf.PDFDocument;
  import org.apache.fop.pdf.PDFPage;
 -import org.apache.fop.pdf.PDFPaintingState;
  import org.apache.fop.pdf.PDFResourceContext;
 -import org.apache.fop.pdf.PDFStream;
  import org.apache.fop.render.AbstractGenericSVGHandler;
  import org.apache.fop.render.Renderer;
  import org.apache.fop.render.RendererContext;
@@@ -105,8 -105,8 +103,6 @@@ public class PDFSVGHandler extends Abst
          public PDFDocument pdfDoc;
          /** see OUTPUT_STREAM */
          public OutputStream outputStream;
--        /** see PDF_STATE */
-         //public PDFState pdfState;
 -        public PDFPaintingState pdfPaintingState;
          /** see PDF_PAGE */
          public PDFPage pdfPage;
          /** see PDF_CONTEXT */
              graphics.scale(1 / s, 1 / s);
          }
  
 -        pdfInfo.currentStream.add("%SVG start\n");
 +        generator.comment("SVG start");
  
          //Save state and update coordinate system for the SVG image
-         generator.getState().push();
 -        pdfInfo.pdfPaintingState.save();
 -        pdfInfo.pdfPaintingState.concatenate(imageTransform);
++        generator.getState().save();
 +        generator.getState().concatenate(imageTransform);
  
          //Now that we have the complete transformation matrix for the image, we can update the
          //transformation matrix for the AElementBridge.
          PDFAElementBridge aBridge = (PDFAElementBridge)ctx.getBridge(
                  SVGDOMImplementation.SVG_NAMESPACE_URI, SVGConstants.SVG_A_TAG);
 -        aBridge.getCurrentTransform().setTransform(pdfInfo.pdfPaintingState.getTransform());
 +        aBridge.getCurrentTransform().setTransform(generator.getState().getTransform());
  
-         graphics.setPDFState(generator.getState());
 -        graphics.setPaintingState(pdfInfo.pdfPaintingState);
++        graphics.setPaintingState(generator.getState());
          graphics.setOutputStream(pdfInfo.outputStream);
          try {
              root.paint(graphics);
                      context.getUserAgent().getEventBroadcaster());
              eventProducer.svgRenderingError(this, e, getDocumentURI(doc));
          }
-         generator.getState().pop();
 -        pdfInfo.pdfPaintingState.restore();
 -        renderer.restoreGraphicsState();
 -        pdfInfo.currentStream.add("%SVG end\n");
++        generator.getState().restore();
 +        generator.restoreGraphicsState();
 +        generator.comment("SVG end");
      }
  
      /** {@inheritDoc} */