]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
new file for the SVG rendering into PDF
authorKeiron Liddle <keiron@apache.org>
Fri, 10 Nov 2000 01:06:24 +0000 (01:06 +0000)
committerKeiron Liddle <keiron@apache.org>
Fri, 10 Nov 2000 01:06:24 +0000 (01:06 +0000)
also adds the pattern shading functionality

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

src/org/apache/fop/render/pdf/SVGRenderer.java [new file with mode: 0644]

diff --git a/src/org/apache/fop/render/pdf/SVGRenderer.java b/src/org/apache/fop/render/pdf/SVGRenderer.java
new file mode 100644 (file)
index 0000000..1c47b53
--- /dev/null
@@ -0,0 +1,2478 @@
+/*-- $Id$ --
+
+ ============================================================================
+                                  The Apache Software License, Version 1.1
+ ============================================================================
+
+       Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must  retain the above copyright  notice,
+       this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+       this list of conditions and the following disclaimer in the documentation
+       and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+       include  the following  acknowledgment:  "This product includes  software
+       developed  by the  Apache Software Foundation  (http://www.apache.org/)."
+       Alternately, this  acknowledgment may  appear in the software itself,  if
+       and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "FOP" and  "Apache Software Foundation"  must not be used to
+       endorse  or promote  products derived  from this  software without      prior
+       written permission. For written permission, please contact
+       apache@apache.org.
+
+ 5. Products  derived from this software may not  be called "Apache", nor may
+       "Apache" appear  in their name,  without prior written permission  of the
+       Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS  FOR A PARTICULAR     PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
+ APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY  THEORY OF LIABILITY,     WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
+ (INCLUDING  NEGLIGENCE OR     OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made  by many individuals
+ on  behalf of the Apache Software     Foundation and was      originally created by
+ James Tauber <jtauber@jtauber.com>. For more  information on the Apache
+ Software Foundation, please see <http://www.apache.org/>.
+
+ */
+
+package org.apache.fop.render.pdf;
+
+// FOP
+import org.apache.fop.messaging.MessageHandler;
+import org.apache.fop.image.ImageArea;
+import org.apache.fop.image.FopImage;
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.properties.*;
+import org.apache.fop.layout.*;
+import org.apache.fop.datatypes.*;
+import org.apache.fop.svg.PathPoint;
+import org.apache.fop.pdf.*;
+import org.apache.fop.layout.*;
+import org.apache.fop.image.*;
+
+import org.w3c.dom.*;
+import org.w3c.dom.svg.*;
+import org.w3c.dom.css.*;
+import org.w3c.dom.svg.SVGLength;
+
+import org.apache.fop.dom.svg.*;
+import org.apache.fop.dom.svg.SVGRectElementImpl;
+import org.apache.fop.dom.svg.SVGTextElementImpl;
+import org.apache.fop.dom.svg.SVGLineElementImpl;
+import org.apache.fop.dom.svg.SVGArea;
+
+// Java
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Enumeration;
+import java.awt.Rectangle;
+import java.util.Vector;
+import java.util.Hashtable;
+
+/**
+ * Renderer that renders SVG to PDF
+ */
+public class SVGRenderer {
+
+    /** the PDF Document being created */
+    protected PDFDocument pdfDoc;
+
+    protected FontState fontState;
+
+    /** the /Resources object of the PDF document being created */
+    // protected PDFResources pdfResources;
+
+    /** the current stream to add PDF commands to */
+    StringWriter currentStream = new StringWriter();
+
+    /** the current (internal) font name */
+    protected String currentFontName;
+
+    /** the current font size in millipoints */
+    protected int currentFontSize;
+
+    /** the current vertical position in millipoints from bottom */
+    protected int currentYPosition = 0;
+
+    /** the current horizontal position in millipoints from left */
+    protected int currentXPosition = 0;
+
+    /** the current colour for use in svg */
+    private PDFColor currentColour = new PDFColor(0, 0, 0);
+
+    /**
+     * create the SVG renderer
+     */
+    public SVGRenderer(FontState fs, PDFDocument doc, String font,
+                       int size, int xpos, int ypos) {
+        pdfDoc = doc;
+        currentFontName = font;
+        currentFontSize = size;
+        currentYPosition = ypos;
+        currentXPosition = xpos;
+        fontState = fs;
+    }
+
+    public String getString() {
+        return currentStream.toString();
+    }
+
+    /**
+     * Renders an SVG element in an SVG document.
+     * This renders each of the child elements.
+     */
+    protected void renderSVG(SVGSVGElement svg, int x, int y) {
+        NodeList nl = svg.getChildNodes();
+        for (int count = 0; count < nl.getLength(); count++) {
+            Node n = nl.item(count);
+            if (n instanceof SVGElement) {
+                renderElement((SVGElement) n, x, y);
+            }
+        }
+    }
+
+    public void renderGArea(SVGGElement area, int posx, int posy) {
+        NodeList nl = area.getChildNodes();
+        for (int count = 0; count < nl.getLength(); count++) {
+            Node n = nl.item(count);
+            if (n instanceof SVGElement) {
+                renderElement((SVGElement) n, posx, posy);
+            }
+        }
+    }
+
+    /**
+     * Handles the SVG switch element.
+     * The switch determines which of its child elements should be rendered
+     * according to the required extensions, required features and system language.
+     */
+    protected void handleSwitchElement(int posx, int posy,
+                                       SVGSwitchElement ael) {
+        SVGList relist = ael.getRequiredExtensions();
+        SVGList rflist = ael.getRequiredFeatures();
+        SVGList sllist = ael.getSystemLanguage();
+        NodeList nl = ael.getChildNodes();
+        choices:
+        for (int count = 0; count < nl.getLength(); count++) {
+            org.w3c.dom.Node n = nl.item(count);
+            // only render the first child that has a valid
+            // test data
+            if (n instanceof GraphicElement) {
+                GraphicElement graphic = (GraphicElement) n;
+                SVGList grelist = graphic.getRequiredExtensions();
+                // if null it evaluates to true
+                if (grelist != null) {
+                    if (grelist.getNumberOfItems() == 0) {
+                        if ((relist != null) &&
+                                relist.getNumberOfItems() != 0) {
+                            continue choices;
+                        }
+                    }
+                    for (int i = 0; i < grelist.getNumberOfItems(); i++) {
+                        String str = (String) grelist.getItem(i);
+                        if (relist == null) {
+                            // use default extension set
+                            // currently no extensions are supported
+                            //                                                 if(!(str.equals("http:// ??"))) {
+                            continue choices;
+                            //                                                 }
+                        } else {
+                        }
+                    }
+                }
+                SVGList grflist = graphic.getRequiredFeatures();
+                if (grflist != null) {
+                    if (grflist.getNumberOfItems() == 0) {
+                        if ((rflist != null) &&
+                                rflist.getNumberOfItems() != 0) {
+                            continue choices;
+                        }
+                    }
+                    for (int i = 0; i < grflist.getNumberOfItems(); i++) {
+                        String str = (String) grflist.getItem(i);
+                        if (rflist == null) {
+                            // use default feature set
+                            if (!(str.equals("org.w3c.svg.static") ||
+                                    str.equals("org.w3c.dom.svg.all"))) {
+                                continue choices;
+                            }
+                        } else {
+                            boolean found = false;
+                            for (int j = 0;
+                                    j < rflist.getNumberOfItems(); j++) {
+                                if (rflist.getItem(j).equals(str)) {
+                                    found = true;
+                                    break;
+                                }
+                            }
+                            if (!found)
+                                continue choices;
+                        }
+                    }
+                }
+                SVGList gsllist = graphic.getSystemLanguage();
+                if (gsllist != null) {
+                    if (gsllist.getNumberOfItems() == 0) {
+                        if ((sllist != null) &&
+                                sllist.getNumberOfItems() != 0) {
+                            continue choices;
+                        }
+                    }
+                    for (int i = 0; i < gsllist.getNumberOfItems(); i++) {
+                        String str = (String) gsllist.getItem(i);
+                        if (sllist == null) {
+                            // use default feature set
+                            if (!(str.equals("en"))) {
+                                continue choices;
+                            }
+                        } else {
+                            boolean found = false;
+                            for (int j = 0;
+                                    j < sllist.getNumberOfItems(); j++) {
+                                if (sllist.getItem(j).equals(str)) {
+                                    found = true;
+                                    break;
+                                }
+                            }
+                            if (!found)
+                                continue choices;
+                        }
+                    }
+                }
+                renderElement((SVGElement) n, posx, posy);
+                // only render the first valid one
+                break;
+            }
+        }
+    }
+
+    /**
+     * add a line to the current stream
+     *
+     * @param x1 the start x location in millipoints
+     * @param y1 the start y location in millipoints
+     * @param x2 the end x location in millipoints
+     * @param y2 the end y location in millipoints
+     * @param th the thickness in millipoints
+     * @param r the red component
+     * @param g the green component
+     * @param b the blue component
+     */
+    protected void addLine(float x1, float y1, float x2, float y2,
+                           DrawingInstruction di) {
+        String str;
+        str = "" + x1 + " " + y1 + " m " + x2 + " " + y2 + " l";
+        if (di != null && di.fill)
+            currentStream.write(str + " f\n"); // ??
+        currentStream.write(str + " S\n");
+    }
+
+    /**
+     * Add an SVG circle
+     * Uses bezier curves to approximate the shape of a circle.
+     */
+    protected void addCircle(float cx, float cy, float r,
+                             DrawingInstruction di) {
+        String str;
+        str = "" + cx + " " + (cy - r) + " m\n" + "" +
+              (cx + 21 * r / 40f) + " " + (cy - r) + " " +
+              (cx + r) + " " + (cy - 21 * r / 40f) + " " +
+              (cx + r) + " " + cy + " c\n" + "" + (cx + r) + " " +
+              (cy + 21 * r / 40f) + " " + (cx + 21 * r / 40f) +
+              " " + (cy + r) + " " + cx + " " + (cy + r) + " c\n" +
+              "" + (cx - 21 * r / 40f) + " " + (cy + r) + " " +
+              (cx - r) + " " + (cy + 21 * r / 40f) + " " +
+              (cx - r) + " " + cy + " c\n" + "" + (cx - r) + " " +
+              (cy - 21 * r / 40f) + " " + (cx - 21 * r / 40f) +
+              " " + (cy - r) + " " + cx + " " + (cy - r) + " c\n";
+
+        currentStream.write(str);
+        doDrawing(di);
+    }
+
+    /**
+     * Add an SVG ellips
+     * Uses bezier curves to approximate the shape of an ellipse.
+     */
+    protected void addEllipse(float cx, float cy, float rx, float ry,
+                              DrawingInstruction di) {
+        String str;
+        str = "" + cx + " " + (cy - ry) + " m\n" + "" +
+              (cx + 21 * rx / 40f) + " " + (cy - ry) + " " +
+              (cx + rx) + " " + (cy - 21 * ry / 40f) + " " +
+              (cx + rx) + " " + cy + " c\n" + "" + (cx + rx) + " " +
+              (cy + 21 * ry / 40f) + " " + (cx + 21 * rx / 40f) +
+              " " + (cy + ry) + " " + cx + " " + (cy + ry) +
+              " c\n" + "" + (cx - 21 * rx / 40f) + " " + (cy + ry) +
+              " " + (cx - rx) + " " + (cy + 21 * ry / 40f) + " " +
+              (cx - rx) + " " + cy + " c\n" + "" + (cx - rx) + " " +
+              (cy - 21 * ry / 40f) + " " + (cx - 21 * rx / 40f) +
+              " " + (cy - ry) + " " + cx + " " + (cy - ry) + " c\n";
+        currentStream.write(str);
+        doDrawing(di);
+    }
+
+    /**
+     * add an SVG rectangle to the current stream.
+     * If there are curved edges then these are rendered using bezier curves.
+     *
+     * @param x the x position of left edge
+     * @param y the y position of top edge
+     * @param w the width
+     * @param h the height
+     * @param rx the x radius curved edge
+     * @param ry the y radius curved edge
+     */
+    protected void addRect(float x, float y, float w, float h,
+                           float rx, float ry, DrawingInstruction di) {
+        String str = "";
+        if (rx == 0.0 && ry == 0.0) {
+            str = "" + x + " " + y + " " + w + " " + h + " re\n";
+        } else {
+            if (ry == 0.0)
+                ry = rx;
+            if (rx > w / 2.0f)
+                rx = w / 2.0f;
+            if (ry > h / 2.0f)
+                ry = h / 2.0f;
+            str = "" + (x + rx) + " " + y + " m\n";
+            str += "" + (x + w - rx) + " " + y + " l\n";
+            str += "" + (x + w - 19 * rx / 40) + " " + y + " " +
+                   (x + w) + " " + (y + 19 * ry / 40) + " " +
+                   (x + w) + " " + (y + ry) + " c\n";
+            str += "" + (x + w) + " " + (y + h - ry) + " l\n";
+            str += "" + (x + w) + " " + (y + h - 19 * ry / 40) + " " +
+                   (x + w - 19 * rx / 40) + " " + (y + h) + " " +
+                   (x + w - rx) + " " + (y + h) + " c\n";
+            str += "" + (x + rx) + " " + (y + h) + " l\n";
+            str += "" + (x + 19 * rx / 40) + " " + (y + h) + " " + x +
+                   " " + (y + h - 19 * ry / 40) + " " + x + " " +
+                   (y + h - ry) + " c\n";
+            str += "" + x + " " + (y + ry) + " l\n";
+            str += "" + x + " " + (y + 19 * ry / 40) + " " +
+                   (x + 19 * rx / 40) + " " + y + " " + (x + rx) +
+                   " " + y + " c\n";
+        }
+        currentStream.write(str);
+        doDrawing(di);
+    }
+
+    /**
+     * Adds an SVG path to the current streem.
+     * An SVG path is made up of a list of drawing instructions that are rendered
+     * out in order.
+     * Arcs don't work.
+     */
+    protected void addPath(Vector points, int posx, int posy,
+                           DrawingInstruction di) {
+        SVGPathSegImpl pathmoveto = null;
+        float lastx = 0;
+        float lasty = 0;
+        for (Enumeration e = points.elements(); e.hasMoreElements();) {
+            SVGPathSegImpl pc = (SVGPathSegImpl) e.nextElement();
+            float[] vals = pc.getValues();
+            float lastcx = 0;
+            float lastcy = 0;
+            switch (pc.getPathSegType()) {
+                case SVGPathSeg.PATHSEG_MOVETO_ABS:
+                    pathmoveto = pc;
+                    lastx = vals[0];
+                    lasty = vals[1];
+                    currentStream.write(lastx + " " + lasty + " m\n");
+                    break;
+                case SVGPathSeg.PATHSEG_MOVETO_REL:
+                    if (pathmoveto == null) {
+                        lastx = vals[0];
+                        lasty = vals[1];
+                        pathmoveto = pc;
+                        currentStream.write(lastx + " " + lasty + " m\n");
+                    } else {
+                        lastx += vals[0];
+                        lasty += vals[1];
+                        currentStream.write(lastx + " " + lasty + " l\n");
+                    }
+                    break;
+                case SVGPathSeg.PATHSEG_LINETO_ABS:
+                    lastx = vals[0];
+                    lasty = vals[1];
+                    currentStream.write(lastx + " " + lasty + " l\n");
+                    break;
+                case SVGPathSeg.PATHSEG_LINETO_REL:
+                    lastx += vals[0];
+                    lasty += vals[1];
+                    currentStream.write(lastx + " " + lasty + " l\n");
+                    break;
+                case SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS:
+                    lasty = vals[0];
+                    currentStream.write(lastx + " " + lasty + " l\n");
+                    break;
+                case SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL:
+                    lasty += vals[0];
+                    currentStream.write(lastx + " " + lasty + " l\n");
+                    break;
+                case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS:
+                    lastx = vals[0];
+                    currentStream.write(lastx + " " + lasty + " l\n");
+                    break;
+                case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL:
+                    lastx += vals[0];
+                    currentStream.write(lastx + " " + lasty + " l\n");
+                    break;
+                case SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS:
+                    lastx = vals[4];
+                    lasty = vals[5];
+                    lastcx = vals[2];
+                    lastcy = vals[3];
+                    currentStream.write((vals[0]) + " " + (vals[1]) +
+                                        " " + (vals[2]) + " " + (vals[3]) + " " +
+                                        lastx + " " + lasty + " c\n");
+                    break;
+                case SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL:
+                    currentStream.write((vals[0] + lastx) + " " +
+                                        (vals[1] + lasty) + " " +
+                                        (vals[2] + lastx) + " " +
+                                        (vals[3] + lasty) + " " +
+                                        (vals[4] + lastx) + " " +
+                                        (vals[5] + lasty) + " c\n");
+                    lastcx = vals[2] + lastx;
+                    lastcy = vals[3] + lasty;
+                    lastx += vals[4];
+                    lasty += vals[5];
+                    break;
+                case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
+                    if (lastcx == 0) {
+                        lastcx = lastx;
+                    }
+                    if (lastcy == 0) {
+                        lastcy = lasty;
+                    }
+                    lastx = vals[2];
+                    lasty = vals[3];
+                    currentStream.write(lastcx + " " + lastcy + " " +
+                                        (vals[0]) + " " + (vals[1]) + " " +
+                                        lastx + " " + lasty + " c\n");
+                    break;
+                case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
+                    if (lastcx == 0) {
+                        lastcx = lastx;
+                    }
+                    if (lastcy == 0) {
+                        lastcy = lasty;
+                    }
+                    currentStream.write(lastcx + " " + lastcy + " " +
+                                        (vals[0] + lastx) + " " +
+                                        (vals[1] + lasty) + " " +
+                                        (vals[2] + lastx) + " " +
+                                        (vals[3] + lasty) + " c\n");
+                    lastx += vals[2];
+                    lasty += vals[3];
+                    break;
+                case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS:
+                    if (lastcx == 0) {
+                        lastcx = lastx;
+                    }
+                    if (lastcy == 0) {
+                        lastcy = lasty;
+                    }
+                    lastx = vals[0];
+                    lasty = vals[1];
+                    lastcx = 0;
+                    lastcy = 0;
+                    currentStream.write(lastcx + " " + lastcy + " " +
+                                        lastx + " " + lasty + " y\n");
+                    break;
+                case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL:
+                    if (lastcx == 0) {
+                        lastcx = lastx;
+                    }
+                    if (lastcy == 0) {
+                        lastcy = lasty;
+                    }
+                    currentStream.write(lastcx + " " + lastcy + " " +
+                                        (vals[0] + lastx) + " " +
+                                        (vals[1] + lasty) + " y\n");
+                    lastcx = 0;
+                    lastcy = 0;
+                    lastx += vals[0];
+                    lasty += vals[1];
+                    break;
+                    // get angle between the two points
+                    // then get angle of points to centre (ie. both points are on the
+                    // apogee and perigee of the ellipse)
+                    // then work out the direction from flags
+                case SVGPathSeg.PATHSEG_ARC_ABS:
+                    {
+                        double rx = vals[0];
+                        double ry = vals[1];
+                        double theta = vals[2];
+                        boolean largearcflag = (vals[3] == 1.0);
+                        boolean sweepflag = (vals[4] == 1.0);
+
+                        double angle = Math.atan((vals[6] - lasty) /
+                                                 (vals[5] - lastx));
+                        double relangle = Math.acos(rx /
+                                                    Math.sqrt((vals[6] - lasty) *
+                                                              (vals[6] - lasty) +
+                                                              (vals[5] - lastx) * (vals[5] - lastx)));
+                        double absangle = angle + relangle;
+                        // change sign depending on flags
+                        double contrx1;
+                        double contry1;
+                        double contrx2;
+                        double contry2;
+                        if (largearcflag) {
+                            if (sweepflag) {
+                                contrx1 = lastx - rx * Math.cos(absangle);
+                                contry1 = lasty + rx * Math.sin(absangle);
+                                contrx2 = vals[5] + ry * Math.cos(absangle);
+                                contry2 = vals[6] + ry * Math.sin(absangle);
+                            } else {
+                                contrx1 = lastx - rx * Math.cos(absangle);
+                                contry1 = lasty - rx * Math.sin(absangle);
+                                contrx2 = vals[5] + ry * Math.cos(absangle);
+                                contry2 = vals[6] - ry * Math.sin(absangle);
+                            }
+                        } else {
+                            if (sweepflag) {
+                                contrx1 = lastx + rx * Math.cos(absangle);
+                                contry1 = lasty + rx * Math.sin(absangle);
+                                contrx2 = contrx1;
+                                contry2 = contry1;
+                            } else {
+                                contrx1 = lastx + ry * Math.cos(absangle);
+                                contry1 = lasty - ry * Math.sin(absangle);
+                                contrx2 = contrx1;
+                                contry2 = contry1;
+                            }
+                        }
+
+                        double cx = lastx;
+                        double cy = lasty;
+                        currentStream.write(contrx1 + " " + contry1 +
+                                            " " + contrx2 + " " + contry2 + " " +
+                                            vals[5] + " " + vals[6] + " c\n");
+                        lastcx = 0; //??
+                        lastcy = 0; //??
+                        lastx = vals[5];
+                        lasty = vals[6];
+                    }
+                    break;
+                case SVGPathSeg.PATHSEG_ARC_REL:
+                    {
+                        double rx = vals[0];
+                        double ry = vals[1];
+                        double theta = vals[2];
+                        boolean largearcflag = (vals[3] == 1.0);
+                        boolean sweepflag = (vals[4] == 1.0);
+
+                        double angle = Math.atan(vals[6] / vals[5]);
+                        double relangle = Math.atan(ry / rx);
+                        //                                     System.out.println((theta * Math.PI / 180f) + ":" + relangle + ":" + largearcflag + ":" + sweepflag);
+                        double absangle = (theta * Math.PI / 180f);//angle + relangle;
+                        // change sign depending on flags
+                        double contrx1;
+                        double contry1;
+                        double contrx2;
+                        double contry2;
+                        if (largearcflag) {
+                            // in a large arc we need to do at least 2 and a bit
+                            // segments or curves.
+                            if (sweepflag) {
+                                contrx1 = lastx + rx * Math.cos(absangle);
+                                contry1 = lasty + rx * Math.sin(absangle);
+                                contrx2 = lastx + vals[5] +
+                                          ry * Math.cos(absangle);
+                                contry2 = lasty + vals[6] -
+                                          ry * Math.sin(absangle);
+                            } else {
+                                contrx1 = lastx + rx * Math.sin(absangle);
+                                contry1 = lasty + rx * Math.cos(absangle);
+                                contrx2 = lastx + vals[5] +
+                                          ry * Math.cos(absangle);
+                                contry2 = lasty + vals[6] +
+                                          ry * Math.sin(absangle);
+                            }
+                        } else {
+                            // only need at most two segments
+                            if (sweepflag) {
+                                contrx1 = lastx + rx * Math.cos(absangle);
+                                contry1 = lasty - rx * Math.sin(absangle);
+                                contrx2 = contrx1;
+                                contry2 = contry1;
+                            } else {
+                                contrx1 = lastx - ry * Math.cos(absangle);
+                                contry1 = lasty + ry * Math.sin(absangle);
+                                contrx2 = contrx1;
+                                contry2 = contry1;
+                            }
+                        }
+                        //System.out.println(contrx1 + ":" + contry1 + ":" + contrx2 + ":" + contry2);
+
+                        double cx = lastx;
+                        double cy = lasty;
+                        currentStream.write(contrx1 + " " + contry1 +
+                                            " " + contrx2 + " " + contry2 + " " +
+                                            (vals[5] + lastx) + " " +
+                                            (vals[6] + lasty) + " c\n");
+
+                        lastcx = 0; //??
+                        lastcy = 0; //??
+                        lastx += vals[5];
+                        lasty += vals[6];
+                    }
+                    break;
+                case SVGPathSeg.PATHSEG_CLOSEPATH:
+                    currentStream.write("h\n");
+                    break;
+            }
+        }
+        doDrawing(di);
+    }
+
+    /**
+     * Adds an SVG polyline or polygon.
+     * A polygon is merely a closed polyline.
+     * This is made up from a set of points that straight lines are drawn between.
+     */
+    protected void addPolyline(Vector points, DrawingInstruction di,
+                               boolean close) {
+        PathPoint pc;
+        float lastx = 0;
+        float lasty = 0;
+        Enumeration e = points.elements();
+        if (e.hasMoreElements()) {
+            pc = (PathPoint) e.nextElement();
+            lastx = pc.x;
+            lasty = pc.y;
+            currentStream.write(lastx + " " + lasty + " m\n");
+        }
+        while (e.hasMoreElements()) {
+            pc = (PathPoint) e.nextElement();
+            lastx = pc.x;
+            lasty = pc.y;
+            currentStream.write(lastx + " " + lasty + " l\n");
+        }
+        if (close)
+            currentStream.write("h\n");
+        doDrawing(di);
+    }
+
+    /**
+     * Writes the drawing instruction out to the current stream
+     * depending on what type of drawing is required.
+     */
+    protected void doDrawing(DrawingInstruction di) {
+        if (di == null) {
+            currentStream.write("S\n");
+        } else {
+            if (di.fill) {
+                if (di.stroke) {
+                    if (!di.nonzero)
+                        currentStream.write("B*\n");
+                    else
+                        currentStream.write("B\n");
+                } else {
+                    if (!di.nonzero)
+                        currentStream.write("f*\n");
+                    else
+                        currentStream.write("f\n");
+                }
+            } else {
+                //                             if(di.stroke)
+                currentStream.write("S\n");
+            }
+        }
+    }
+
+    /**
+     * Renders an svg image to the current stream.
+     * This uses the FopImageFactory to load the image and then renders it.
+     */
+    public void renderImage(String href, float x, float y, float width,
+                            float height) {
+        try {
+            if (href.indexOf(":") == -1) {
+                href = "file:" + href;
+            }
+            FopImage img = FopImageFactory.Make(href);
+            if (img instanceof SVGImage) {
+                SVGSVGElement svg =
+                  ((SVGImage) img).getSVGDocument().getRootElement();
+                currentStream.write("q\n" + width /
+                                    svg.getWidth().getBaseVal().getValue() + " 0 0 " +
+                                    height /
+                                    svg.getHeight().getBaseVal().getValue() + " 0 0 cm\n");
+                renderSVG(svg, (int) x * 1000, (int) y * 1000);
+                currentStream.write("Q\n");
+                //                             renderSVG(svg);
+            } else if (img != null) {
+                int xObjectNum = this.pdfDoc.addImage(img);
+                currentStream.write("q\n1 0 0 -1 " + 0 + " " +
+                                    (2 * y + height) + " cm\n" + width + " 0 0 " +
+                                    height + " " + x + " " + y + " cm\n" + "/Im" +
+                                    xObjectNum + " Do\nQ\n");
+                //                             img.close();
+            }
+        } catch (Exception e) {
+            System.err.println("could not add image to SVG: " + href);
+        }
+    }
+
+    /**
+     * A symbol has a viewbox and preserve aspect ratio.
+     */
+    protected void renderSymbol(SVGSymbolElement symbol, int x, int y) {
+        NodeList nl = symbol.getChildNodes();
+        for (int count = 0; count < nl.getLength(); count++) {
+            Node n = nl.item(count);
+            if (n instanceof SVGElement) {
+                renderElement((SVGElement) n, x, y);
+            }
+        }
+    }
+
+    /**
+     * Handles the construction of an SVG gradient.
+     * This gets the gradient element and creates the pdf info
+     * in the pdf document.
+     * The type of gradient is determined by what class the gradient element is.
+     */
+    protected void handleGradient(String sp, DrawingInstruction di,
+                                  boolean fill, SVGElement area) {
+        // should be a url to a gradient
+        String url = (String) sp;
+        if (url.startsWith("url(")) {
+            String address;
+            int b1 = url.indexOf("(");
+            int b2 = url.indexOf(")");
+            address = url.substring(b1 + 1, b2);
+            SVGElement gi = null;
+            gi = locateDef(address, area);
+            if (gi instanceof SVGLinearGradientElement) {
+                SVGLinearGradientElement linear =
+                  (SVGLinearGradientElement) gi;
+                handleLinearGradient(linear, di, fill, area);
+            } else if (gi instanceof SVGRadialGradientElement) {
+                SVGRadialGradientElement radial =
+                  (SVGRadialGradientElement) gi;
+                handleRadialGradient(radial, di, fill, area);
+            } else if (gi instanceof SVGPatternElement) {
+                SVGPatternElement pattern = (SVGPatternElement) gi;
+                handlePattern(pattern, di, fill, area);
+            } else {
+                System.err.println("WARNING Invalid fill reference :" +
+                                   gi + ":" + address);
+            }
+        }
+    }
+
+    protected void handlePattern(SVGPatternElement pattern,
+                                 DrawingInstruction di, boolean fill, SVGElement area) {
+        SVGAnimatedLength x, y, width, height;
+        short pattUnits = SVGUnitTypes.SVG_UNIT_TYPE_UNKNOWN;
+        NodeList stops = null;
+        x = pattern.getX();
+        y = pattern.getY();
+        width = pattern.getWidth();
+        height = pattern.getHeight();
+        NodeList nl = pattern.getChildNodes();
+        SVGPatternElement ref = (SVGPatternElement) locateDef(
+                                  pattern.getHref().getBaseVal(), pattern);
+        while (ref != null) {
+            if (x == null) {
+                x = ref.getX();
+                pattUnits = ref.getPatternUnits().getBaseVal();
+            }
+            if (y == null) {
+                y = ref.getY();
+            }
+            if (width == null) {
+                width = ref.getWidth();
+            }
+            if (height == null) {
+                height = ref.getHeight();
+            }
+            if (nl.getLength() == 0) {
+                nl = ref.getChildNodes();
+            }
+            ref = (SVGPatternElement) locateDef(
+                    ref.getHref().getBaseVal(), ref);
+        }
+        if (x == null) {
+            SVGLength length = new SVGLengthImpl();
+            length.newValueSpecifiedUnits(
+              SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0);
+            x = new SVGAnimatedLengthImpl(length);
+        }
+        if (y == null) {
+            SVGLength length = new SVGLengthImpl();
+            length.newValueSpecifiedUnits(
+              SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0);
+            y = new SVGAnimatedLengthImpl(length);
+        }
+        if (width == null) {
+            SVGLength length = new SVGLengthImpl();
+            length.newValueSpecifiedUnits(
+              SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 1);
+            width = new SVGAnimatedLengthImpl(length);
+        }
+        if (height == null) {
+            SVGLength length = new SVGLengthImpl();
+            length.newValueSpecifiedUnits(
+              SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 1);
+            height = new SVGAnimatedLengthImpl(length);
+        }
+
+        StringWriter realStream = currentStream;
+        currentStream = new StringWriter();
+
+        currentStream.write("q\n");
+        // this makes the pattern the right way up, since it is outside the original
+        // transform around the whole svg document
+        currentStream.write("1 0 0 -1 0 " +
+                            height.getBaseVal().getValue() + " cm\n");
+        for (int count = 0; count < nl.getLength(); count++) {
+            Node n = nl.item(count);
+            if (n instanceof SVGElement) {
+                renderElement((SVGElement) n, 0, 0);
+            }
+        }
+        currentStream.write("Q\n");
+
+        double xval = x.getBaseVal().getValue() + currentXPosition / 1000f;
+        double yval = -y.getBaseVal().getValue() + currentYPosition / 1000f;
+        if (area instanceof GraphicElement) {
+            SVGRect bbox = ((GraphicElement) area).getBBox();
+            if (bbox != null) {
+                //                     xval += bbox.getX();
+                //                     yval -= bbox.getY();
+            }
+        }
+        double widthval = width.getBaseVal().getValue();
+        double heightval = height.getBaseVal().getValue();
+        Vector bbox = new Vector();
+        bbox.addElement(new Double(0));
+        bbox.addElement(new Double(0));
+        bbox.addElement(new Double(widthval));
+        bbox.addElement(new Double(heightval));
+        Vector translate = new Vector();
+        // combine with pattern transform
+        translate.addElement(new Double(1));
+        translate.addElement(new Double(0));
+        translate.addElement(new Double(0));
+        translate.addElement(new Double(1));
+        translate.addElement(new Double(xval));
+        translate.addElement(new Double(yval));
+        // need to handle PDFResources
+        PDFPattern myPat =
+          this.pdfDoc.makePattern(1, null, 1, 1, bbox, widthval,
+                                  heightval, translate, null, currentStream.getBuffer());
+
+        currentStream = realStream;
+        currentStream.write(myPat.getColorSpaceOut(fill));
+        if (fill)
+            di.fill = true;
+        else
+            di.stroke = true;
+    }
+
+    protected void handleLinearGradient(
+      SVGLinearGradientElement linear, DrawingInstruction di,
+      boolean fill, SVGElement area) {
+        // first get all the gradient values
+        // if values not present follow the href
+        // the gradient units will be where the vals are specified
+        // the spread method will be where there are stop elements
+        SVGAnimatedLength ax1, ax2, ay1, ay2;
+        short spread = SVGGradientElement.SVG_SPREADMETHOD_UNKNOWN;
+        short gradUnits = SVGUnitTypes.SVG_UNIT_TYPE_UNKNOWN;
+        NodeList stops = null;
+        ax1 = linear.getX1();
+        ax2 = linear.getX2();
+        ay1 = linear.getY1();
+        ay2 = linear.getY2();
+        stops = linear.getChildNodes();
+        SVGLinearGradientElement ref = (SVGLinearGradientElement) locateDef(
+                                         linear.getHref().getBaseVal(), linear);
+        while (ref != null) {
+            if (ax1 == null) {
+                ax1 = ref.getX1();
+                gradUnits = ref.getGradientUnits().getBaseVal();
+            }
+            if (ax2 == null) {
+                ax2 = ref.getX2();
+            }
+            if (ay1 == null) {
+                ay1 = ref.getY1();
+            }
+            if (ay2 == null) {
+                ay2 = ref.getY2();
+            }
+            if (stops.getLength() == 0) {
+                stops = ref.getChildNodes();
+            }
+            ref = (SVGLinearGradientElement) locateDef(
+                    ref.getHref().getBaseVal(), ref);
+        }
+        if (ax1 == null) {
+            SVGLength length = new SVGLengthImpl();
+            length.newValueSpecifiedUnits(
+              SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0);
+            ax1 = new SVGAnimatedLengthImpl(length);
+        }
+        if (ax2 == null) {
+            // if x2 is not specified then it should be 100%
+            SVGLength length = new SVGLengthImpl();
+            length.newValueSpecifiedUnits(
+              SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 1);
+            ax2 = new SVGAnimatedLengthImpl(length);
+        }
+        if (ay1 == null) {
+            SVGLength length = new SVGLengthImpl();
+            length.newValueSpecifiedUnits(
+              SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0);
+            ay1 = new SVGAnimatedLengthImpl(length);
+        }
+        if (ay2 == null) {
+            SVGLength length = new SVGLengthImpl();
+            length.newValueSpecifiedUnits(
+              SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0);
+            ay2 = new SVGAnimatedLengthImpl(length);
+        }
+        Vector theCoords = null;
+        if (gradUnits == SVGUnitTypes.SVG_UNIT_TYPE_UNKNOWN)
+            gradUnits = linear.getGradientUnits().getBaseVal();
+        // spread: pad (normal), reflect, repeat
+        spread = linear.getSpreadMethod().getBaseVal();
+        if (gradUnits == SVGUnitTypes.SVG_UNIT_TYPE_USERSPACEONUSE) {
+            if (area instanceof SVGTransformable) {
+                SVGTransformable tf = (SVGTransformable) area;
+                double x1, y1, x2, y2;
+                x1 = ax1.getBaseVal().getValue();
+                y1 = -ay1.getBaseVal().getValue();
+                x2 = ax2.getBaseVal().getValue();
+                y2 = -ay2.getBaseVal().getValue();
+                SVGMatrix matrix = tf.getScreenCTM();
+                double oldx = x1;
+                x1 = matrix.getA() * x1 + matrix.getB() * y1 +
+                     matrix.getE();
+                y1 = matrix.getC() * oldx + matrix.getD() * y1 +
+                     matrix.getF();
+                oldx = x2;
+                x2 = matrix.getA() * x2 + matrix.getB() * y2 +
+                     matrix.getE();
+                y2 = matrix.getC() * oldx + matrix.getD() * y2 +
+                     matrix.getF();
+                theCoords = new Vector();
+                if (spread == SVGGradientElement.SVG_SPREADMETHOD_REFLECT) {
+                } else if (spread ==
+                    SVGGradientElement.SVG_SPREADMETHOD_REFLECT) {
+                } else {
+                    theCoords.addElement(
+                      new Double(currentXPosition / 1000f + x1));
+                    theCoords.addElement(
+                      new Double(currentYPosition / 1000f - y1));
+                    theCoords.addElement(
+                      new Double(currentXPosition / 1000f + x2));
+                    theCoords.addElement(
+                      new Double(currentYPosition / 1000f - y2));
+                }
+            }
+        } else if (area instanceof GraphicElement) {
+            SVGRect rect = ((GraphicElement) area).getBBox();
+            if (rect != null) {
+                theCoords = new Vector();
+                SVGLength val;
+                val = ax1.getBaseVal();
+                if (val.getUnitType() ==
+                        SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits ==
+                        SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+                    theCoords.addElement(
+                      new Double(currentXPosition / 1000f +
+                                 rect.getX() +
+                                 val.getValue() * rect.getWidth()));
+                } else {
+                    theCoords.addElement(
+                      new Double(currentXPosition / 1000f +
+                                 val.getValue()));
+                }
+                val = ay1.getBaseVal();
+                if (val.getUnitType() ==
+                        SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits ==
+                        SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+                    theCoords.addElement(
+                      new Double(currentYPosition / 1000f -
+                                 rect.getY() -
+                                 val.getValue() * rect.getHeight()));
+                } else {
+                    theCoords.addElement(
+                      new Double(currentYPosition / 1000f -
+                                 val.getValue()));
+                }
+                val = ax2.getBaseVal();
+                if (val.getUnitType() ==
+                        SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits ==
+                        SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+                    theCoords.addElement(
+                      new Double(currentXPosition / 1000f +
+                                 rect.getX() +
+                                 val.getValue() * rect.getWidth()));
+                } else {
+                    theCoords.addElement(
+                      new Double(currentXPosition / 1000f +
+                                 val.getValue()));
+                }
+                val = ay2.getBaseVal();
+                if (val.getUnitType() ==
+                        SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits ==
+                        SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+                    theCoords.addElement(
+                      new Double(currentYPosition / 1000f -
+                                 rect.getY() -
+                                 val.getValue() * rect.getHeight()));
+                } else {
+                    theCoords.addElement(
+                      new Double(currentYPosition / 1000f -
+                                 val.getValue()));
+                }
+            }
+        }
+        if (theCoords == null) {
+            theCoords = new Vector();
+            theCoords.addElement( new Double(currentXPosition / 1000f +
+                                             ax1.getBaseVal().getValue()));
+            theCoords.addElement( new Double(currentYPosition / 1000f -
+                                             ay1.getBaseVal().getValue()));
+            theCoords.addElement( new Double(currentXPosition / 1000f +
+                                             ax2.getBaseVal().getValue()));
+            theCoords.addElement( new Double(currentYPosition / 1000f -
+                                             ay2.getBaseVal().getValue()));
+        }
+
+        Vector theExtend = new Vector();
+        theExtend.addElement(new Boolean(true));
+        theExtend.addElement(new Boolean(true));
+
+        Vector theDomain = new Vector();
+        theDomain.addElement(new Double(0));
+        theDomain.addElement(new Double(1));
+
+        Vector theEncode = new Vector();
+        theEncode.addElement(new Double(0));
+        theEncode.addElement(new Double(1));
+        theEncode.addElement(new Double(0));
+        theEncode.addElement(new Double(1));
+
+        Vector theBounds = new Vector();
+        theBounds.addElement(new Double(0));
+        theBounds.addElement(new Double(1));
+
+        Vector theFunctions = new Vector();
+
+        NodeList nl = stops;
+        Vector someColors = new Vector();
+        float lastoffset = 0;
+        Vector lastVector = null;
+        SVGStopElementImpl stop;
+        if (nl.getLength() == 0) {
+            // the color should be "none"
+            if (fill)
+                di.fill = false;
+            else
+                di.stroke = false;
+            return;
+        } else if (nl.getLength() == 1) {
+            stop = (SVGStopElementImpl) nl.item(0);
+            CSSValue cv = stop.getPresentationAttribute("stop-color");
+            if (cv == null) {
+                // maybe using color
+                cv = stop.getPresentationAttribute("color");
+            }
+            if (cv == null) {
+                // problems
+                System.err.println("no stop-color or color in stop element");
+                return;
+            }
+            PDFColor color = new PDFColor(0, 0, 0);
+            if (cv != null &&
+                    cv.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
+                if (((CSSPrimitiveValue) cv).getPrimitiveType() ==
+                        CSSPrimitiveValue.CSS_RGBCOLOR) {
+                    RGBColor col =
+                      ((CSSPrimitiveValue) cv).getRGBColorValue();
+                    CSSPrimitiveValue val;
+                    val = col.getRed();
+                    float red = val.getFloatValue(
+                                  CSSPrimitiveValue.CSS_NUMBER);
+                    val = col.getGreen();
+                    float green = val.getFloatValue(
+                                    CSSPrimitiveValue.CSS_NUMBER);
+                    val = col.getBlue();
+                    float blue = val.getFloatValue(
+                                   CSSPrimitiveValue.CSS_NUMBER);
+                    color = new PDFColor(red, green, blue);
+                }
+            }
+            currentStream.write(color.getColorSpaceOut(fill));
+            if (fill)
+                di.fill = true;
+            else
+                di.stroke = true;
+            return;
+        }
+        for (int count = 0; count < nl.getLength(); count++) {
+            stop = (SVGStopElementImpl) nl.item(count);
+            CSSValue cv = stop.getPresentationAttribute("stop-color");
+            if (cv == null) {
+                // maybe using color
+                cv = stop.getPresentationAttribute("color");
+            }
+            if (cv == null) {
+                // problems
+                System.err.println("no stop-color or color in stop element");
+                continue;
+            }
+            PDFColor color = new PDFColor(0, 0, 0);
+            if (cv != null &&
+                    cv.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
+                if (((CSSPrimitiveValue) cv).getPrimitiveType() ==
+                        CSSPrimitiveValue.CSS_RGBCOLOR) {
+                    RGBColor col =
+                      ((CSSPrimitiveValue) cv).getRGBColorValue();
+                    CSSPrimitiveValue val;
+                    val = col.getRed();
+                    float red = val.getFloatValue(
+                                  CSSPrimitiveValue.CSS_NUMBER);
+                    val = col.getGreen();
+                    float green = val.getFloatValue(
+                                    CSSPrimitiveValue.CSS_NUMBER);
+                    val = col.getBlue();
+                    float blue = val.getFloatValue(
+                                   CSSPrimitiveValue.CSS_NUMBER);
+                    color = new PDFColor(red, green, blue);
+                    currentColour = color;
+                }
+            }
+            float offset = stop.getOffset().getBaseVal();
+            Vector colVector = color.getVector();
+            // create bounds from last to offset
+            if (lastVector != null) {
+                Vector theCzero = lastVector;
+                Vector theCone = colVector;
+                PDFFunction myfunc =
+                  this.pdfDoc.makeFunction(2, theDomain, null,
+                                           theCzero, theCone, 1.0);
+                theFunctions.addElement(myfunc);
+            }
+            lastoffset = offset;
+            lastVector = colVector;
+            someColors.addElement(color);
+        }
+        ColorSpace aColorSpace = new ColorSpace(ColorSpace.DEVICE_RGB);
+        /*                             PDFFunction myfunky = this.pdfDoc.makeFunction(3,
+                               theDomain, null,
+                               theFunctions, null,
+                               theEncode);
+                       PDFShading myShad = null;
+                       myShad = this.pdfDoc.makeShading(
+                               2, aColorSpace,
+                               null, null, false,
+                               theCoords, null, myfunky,theExtend);
+                       PDFPattern myPat = this.pdfDoc.makePattern(2, myShad, null, null, null);*/
+        PDFPattern myPat = this.pdfDoc.createGradient(false, aColorSpace,
+                           someColors, null, theCoords);
+        currentStream.write(myPat.getColorSpaceOut(fill));
+        if (fill)
+            di.fill = true;
+        else
+            di.stroke = true;
+    }
+
+    protected void handleRadialGradient(
+      SVGRadialGradientElement radial, DrawingInstruction di,
+      boolean fill, SVGElement area) {
+        // first get all the gradient values
+        // if values not present follow the href
+        // the gradient units will be where the vals are specified
+        SVGAnimatedLength acx, acy, ar, afx, afy;
+        short gradUnits = radial.getGradientUnits().getBaseVal();
+        NodeList stops = null;
+        acx = radial.getCx();
+        acy = radial.getCy();
+        ar = radial.getR();
+        afx = radial.getFx();
+        afy = radial.getFy();
+        stops = radial.getChildNodes();
+        SVGRadialGradientElement ref = (SVGRadialGradientElement) locateDef(
+                                         radial.getHref().getBaseVal(), radial);
+        while (ref != null) {
+            if (acx == null) {
+                acx = ref.getCx();
+                gradUnits = ref.getGradientUnits().getBaseVal();
+            }
+            if (acy == null) {
+                acy = ref.getCy();
+            }
+            if (ar == null) {
+                ar = ref.getR();
+            }
+            if (afx == null) {
+                afx = ref.getFx();
+            }
+            if (afy == null) {
+                afy = ref.getFy();
+            }
+            if (stops.getLength() == 0) {
+                stops = ref.getChildNodes();
+            }
+            ref = (SVGRadialGradientElement) locateDef(
+                    ref.getHref().getBaseVal(), ref);
+        }
+        if (acx == null) {
+            SVGLength length = new SVGLengthImpl();
+            length.newValueSpecifiedUnits(
+              SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0.5f);
+            acx = new SVGAnimatedLengthImpl(length);
+        }
+        if (acy == null) {
+            SVGLength length = new SVGLengthImpl();
+            length.newValueSpecifiedUnits(
+              SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0.5f);
+            acy = new SVGAnimatedLengthImpl(length);
+        }
+        if (ar == null) {
+            SVGLength length = new SVGLengthImpl();
+            length.newValueSpecifiedUnits(
+              SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 1);
+            ar = new SVGAnimatedLengthImpl(length);
+        }
+        if (afx == null) {
+            SVGLength length = new SVGLengthImpl();
+            length.newValueSpecifiedUnits(
+              SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0.5f);
+            afx = new SVGAnimatedLengthImpl(length);
+        }
+        if (afy == null) {
+            SVGLength length = new SVGLengthImpl();
+            length.newValueSpecifiedUnits(
+              SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0.5f);
+            afy = new SVGAnimatedLengthImpl(length);
+        }
+        ColorSpace aColorSpace = new ColorSpace(ColorSpace.DEVICE_RGB);
+        org.w3c.dom.NodeList nl = stops;
+        SVGStopElementImpl stop;
+        if (nl.getLength() == 0) {
+            // the color should be "none"
+            if (fill)
+                di.fill = false;
+            else
+                di.stroke = false;
+            return;
+        } else if (nl.getLength() == 1) {
+            stop = (SVGStopElementImpl) nl.item(0);
+            CSSValue cv = stop.getPresentationAttribute("stop-color");
+            if (cv == null) {
+                // maybe using color
+                cv = stop.getPresentationAttribute("color");
+            }
+            if (cv == null) {
+                // problems
+                System.err.println("no stop-color or color in stop element");
+                return;
+            }
+            PDFColor color = new PDFColor(0, 0, 0);
+            if (cv != null &&
+                    cv.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
+                if (((CSSPrimitiveValue) cv).getPrimitiveType() ==
+                        CSSPrimitiveValue.CSS_RGBCOLOR) {
+                    RGBColor col =
+                      ((CSSPrimitiveValue) cv).getRGBColorValue();
+                    CSSPrimitiveValue val;
+                    val = col.getRed();
+                    float red = val.getFloatValue(
+                                  CSSPrimitiveValue.CSS_NUMBER);
+                    val = col.getGreen();
+                    float green = val.getFloatValue(
+                                    CSSPrimitiveValue.CSS_NUMBER);
+                    val = col.getBlue();
+                    float blue = val.getFloatValue(
+                                   CSSPrimitiveValue.CSS_NUMBER);
+                    color = new PDFColor(red, green, blue);
+                }
+            }
+            currentStream.write(color.getColorSpaceOut(fill));
+            if (fill)
+                di.fill = true;
+            else
+                di.stroke = true;
+            return;
+        }
+        Hashtable table = null;
+        Vector someColors = new Vector();
+        Vector theCoords = null;
+        Vector theBounds = new Vector();
+        // the coords should be relative to the current object
+        // check value types, eg. %
+        if (gradUnits == SVGUnitTypes.SVG_UNIT_TYPE_USERSPACEONUSE) {
+            if (area instanceof SVGTransformable) {
+                SVGTransformable tf = (SVGTransformable) area;
+                double x1, y1, x2, y2;
+                x1 = acx.getBaseVal().getValue();
+                y1 = -acy.getBaseVal().getValue();
+                x2 = afx.getBaseVal().getValue();
+                y2 = -afy.getBaseVal().getValue();
+                SVGMatrix matrix = tf.getScreenCTM();
+                double oldx = x1;
+                x1 = matrix.getA() * x1 + matrix.getB() * y1 +
+                     matrix.getE();
+                y1 = matrix.getC() * oldx + matrix.getD() * y1 +
+                     matrix.getF();
+                oldx = x2;
+                x2 = matrix.getA() * x2 + matrix.getB() * y2 +
+                     matrix.getE();
+                y2 = matrix.getC() * oldx + matrix.getD() * y2 +
+                     matrix.getF();
+                theCoords = new Vector();
+                //                             if(spread == SVGGradientElement.SVG_SPREADMETHOD_REFLECT) {
+                //                             } else if(spread== SVGGradientElement.SVG_SPREADMETHOD_REFLECT) {
+                //                             } else {
+                theCoords.addElement(
+                  new Double(currentXPosition / 1000f + x1));
+                // the y val needs to be adjust by 2 * R * rotation
+                // depending on if this value is from an x or y coord
+                // before transformation
+                theCoords.addElement(
+                  new Double(currentYPosition / 1000f - y1 +
+                             (matrix.getC() - matrix.getD()) * 2 *
+                             ar.getBaseVal().getValue()));
+                theCoords.addElement(new Double(0));
+                theCoords.addElement(
+                  new Double(currentXPosition / 1000f + x2));
+                theCoords.addElement(
+                  new Double(currentYPosition / 1000f - y2 +
+                             (matrix.getC() - matrix.getD()) * 2 *
+                             ar.getBaseVal().getValue()));
+                theCoords.addElement(
+                  new Double(ar.getBaseVal().getValue()));
+                //                             }
+            }
+        } else if (gradUnits ==
+            SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX &&
+            area instanceof GraphicElement) {
+            SVGRect rect = ((GraphicElement) area).getBBox();
+            if (rect != null) {
+                theCoords = new Vector();
+                SVGLength val;
+                val = acx.getBaseVal();
+                if (val.getUnitType() ==
+                        SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits ==
+                        SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+                    theCoords.addElement(
+                      new Double(currentXPosition / 1000f +
+                                 rect.getX() +
+                                 val.getValue() * rect.getWidth()));
+                } else {
+                    theCoords.addElement(
+                      new Double(currentXPosition / 1000f +
+                                 val.getValue()));
+                }
+                val = acy.getBaseVal();
+                if (val.getUnitType() ==
+                        SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits ==
+                        SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+                    theCoords.addElement(
+                      new Double(currentYPosition / 1000f -
+                                 rect.getY() -
+                                 val.getValue() * rect.getHeight()));
+                } else {
+                    theCoords.addElement(
+                      new Double(currentYPosition / 1000f -
+                                 val.getValue()));
+                }
+                theCoords.addElement(new Double(0));
+                val = afx.getBaseVal();
+                if (val.getUnitType() ==
+                        SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits ==
+                        SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+                    theCoords.addElement(
+                      new Double(currentXPosition / 1000f +
+                                 rect.getX() +
+                                 val.getValue() * rect.getWidth()));
+                } else {
+                    theCoords.addElement(
+                      new Double(currentXPosition / 1000f +
+                                 val.getValue()));
+                }
+                val = afy.getBaseVal();
+                if (val.getUnitType() ==
+                        SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits ==
+                        SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+                    theCoords.addElement(
+                      new Double(currentYPosition / 1000f -
+                                 rect.getY() -
+                                 val.getValue() * rect.getHeight()));
+                } else {
+                    theCoords.addElement(
+                      new Double(currentYPosition / 1000f -
+                                 val.getValue()));
+                }
+                val = ar.getBaseVal();
+                if (val.getUnitType() ==
+                        SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits ==
+                        SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+                    theCoords.addElement(
+                      new Double(val.getValue() * rect.getHeight()));
+                } else {
+                    theCoords.addElement(new Double(val.getValue()));
+                }
+            }
+        }
+        if (theCoords == null) {
+            // percentage values are expressed according to the viewport.
+            SVGElement vp =
+              ((GraphicElement) area).getNearestViewportElement();
+            if (area instanceof GraphicElement) {
+                SVGRect rect = ((GraphicElement) area).getBBox();
+                if (rect != null) {
+                    theCoords = new Vector();
+                    SVGLength val = acx.getBaseVal();
+                    if (val.getUnitType() ==
+                            SVGLength.SVG_LENGTHTYPE_PERCENTAGE ||
+                            gradUnits ==
+                            SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+                        theCoords.addElement(
+                          new Double(currentXPosition / 1000f +
+                                     rect.getX() +
+                                     val.getValue() * rect.getWidth()));
+                    } else {
+                        theCoords.addElement(
+                          new Double(currentXPosition / 1000f +
+                                     val.getValue()));
+                    }
+                    val = acy.getBaseVal();
+                    if (val.getUnitType() ==
+                            SVGLength.SVG_LENGTHTYPE_PERCENTAGE ||
+                            gradUnits ==
+                            SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+                        theCoords.addElement(
+                          new Double(currentYPosition / 1000f -
+                                     rect.getY() -
+                                     val.getValue() * rect.getHeight()));
+                    } else {
+                        theCoords.addElement(
+                          new Double(currentYPosition / 1000f -
+                                     val.getValue()));
+                    }
+                    theCoords.addElement(new Double(0));
+                    val = afx.getBaseVal();
+                    if (val.getUnitType() ==
+                            SVGLength.SVG_LENGTHTYPE_PERCENTAGE ||
+                            gradUnits ==
+                            SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+                        theCoords.addElement(
+                          new Double(currentXPosition / 1000f +
+                                     rect.getX() +
+                                     val.getValue() * rect.getWidth()));
+                    } else {
+                        theCoords.addElement(
+                          new Double(currentXPosition / 1000f +
+                                     val.getValue()));
+                    }
+                    val = afy.getBaseVal();
+                    if (val.getUnitType() ==
+                            SVGLength.SVG_LENGTHTYPE_PERCENTAGE ||
+                            gradUnits ==
+                            SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+                        theCoords.addElement(
+                          new Double(currentYPosition / 1000f -
+                                     rect.getY() -
+                                     val.getValue() * rect.getHeight()));
+                    } else {
+                        theCoords.addElement(
+                          new Double(currentYPosition / 1000f -
+                                     val.getValue()));
+                    }
+                    val = ar.getBaseVal();
+                    if (val.getUnitType() ==
+                            SVGLength.SVG_LENGTHTYPE_PERCENTAGE ||
+                            gradUnits ==
+                            SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+                        theCoords.addElement( new Double(val.getValue() *
+                                                         rect.getHeight()));
+                    } else {
+                        theCoords.addElement(new Double(val.getValue()));
+                    }
+                }
+            }
+        }
+        if (theCoords == null) {
+            theCoords = new Vector();
+            theCoords.addElement( new Double(currentXPosition / 1000f +
+                                             acx.getBaseVal().getValue()));
+            theCoords.addElement( new Double(currentYPosition / 1000f -
+                                             acy.getBaseVal().getValue()));
+            theCoords.addElement(new Double(0));
+            theCoords.addElement( new Double(currentXPosition / 1000f +
+                                             afx.getBaseVal().getValue())); // Fx
+            theCoords.addElement(
+              new Double(currentYPosition / 1000f -
+                         afy.getBaseVal().getValue())); // Fy
+            theCoords.addElement(
+              new Double(ar.getBaseVal().getValue()));
+        }
+        float lastoffset = 0;
+        for (int count = 0; count < nl.getLength(); count++) {
+            stop = (SVGStopElementImpl) nl.item(count);
+            CSSValue cv = stop.getPresentationAttribute("stop-color");
+            if (cv == null) {
+                // maybe using color
+                cv = stop.getPresentationAttribute("color");
+            }
+            if (cv == null) {
+                // problems
+                System.err.println("no stop-color or color in stop element");
+                continue;
+            }
+            PDFColor color = new PDFColor(0, 0, 0);
+            if (cv != null &&
+                    cv.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
+                if (((CSSPrimitiveValue) cv).getPrimitiveType() ==
+                        CSSPrimitiveValue.CSS_RGBCOLOR) {
+                    RGBColor col =
+                      ((CSSPrimitiveValue) cv).getRGBColorValue();
+                    CSSPrimitiveValue val;
+                    val = col.getRed();
+                    float red = val.getFloatValue(
+                                  CSSPrimitiveValue.CSS_NUMBER);
+                    val = col.getGreen();
+                    float green = val.getFloatValue(
+                                    CSSPrimitiveValue.CSS_NUMBER);
+                    val = col.getBlue();
+                    float blue = val.getFloatValue(
+                                   CSSPrimitiveValue.CSS_NUMBER);
+                    color = new PDFColor(red, green, blue);
+                }
+            }
+            float offset = stop.getOffset().getBaseVal();
+            // create bounds from last to offset
+            lastoffset = offset;
+            someColors.addElement(color);
+        }
+        PDFPattern myPat = this.pdfDoc.createGradient(true, aColorSpace,
+                           someColors, theBounds, theCoords);
+
+        currentStream.write(myPat.getColorSpaceOut(fill));
+        if (fill)
+            di.fill = true;
+        else
+            di.stroke = true;
+    }
+
+    /*
+     * This sets up the style for drawing objects.
+     * Should only set style for elements that have changes.
+     *
+     */
+    // need mask drawing
+    class DrawingInstruction {
+        boolean stroke = false;
+        boolean nonzero = false; // non-zero fill rule "f*", "B*" operator
+        boolean fill = false;
+        int linecap = 0; // butt
+        int linejoin = 0; // miter
+        int miterwidth = 8;
+    }
+    protected DrawingInstruction applyStyle(SVGElement area,
+                                            SVGStylable style) {
+        DrawingInstruction di = new DrawingInstruction();
+        CSSValue sp;
+        sp = style.getPresentationAttribute("fill");
+        if (sp != null) {
+            if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
+                if (((CSSPrimitiveValue) sp).getPrimitiveType() ==
+                        CSSPrimitiveValue.CSS_RGBCOLOR) {
+                    RGBColor col =
+                      ((CSSPrimitiveValue) sp).getRGBColorValue();
+                    CSSPrimitiveValue val;
+                    val = col.getRed();
+                    float red = val.getFloatValue(
+                                  CSSPrimitiveValue.CSS_NUMBER);
+                    val = col.getGreen();
+                    float green = val.getFloatValue(
+                                    CSSPrimitiveValue.CSS_NUMBER);
+                    val = col.getBlue();
+                    float blue = val.getFloatValue(
+                                   CSSPrimitiveValue.CSS_NUMBER);
+                    PDFColor fillColour = new PDFColor(red, green, blue);
+                    currentColour = fillColour;
+                    currentStream.write(fillColour.getColorSpaceOut(true));
+                    di.fill = true;
+                } else if ( ((CSSPrimitiveValue) sp).getPrimitiveType() ==
+                    CSSPrimitiveValue.CSS_URI) {
+                    // gradient
+                    String str = ((CSSPrimitiveValue) sp).getCssText();
+                    handleGradient(str, di, true, area);
+                } else if ( ((CSSPrimitiveValue) sp).getPrimitiveType() ==
+                    CSSPrimitiveValue.CSS_STRING) {
+                    String str = ((CSSPrimitiveValue) sp).getCssText();
+                    if (str.equals("none")) {
+                        di.fill = false;
+                    } else if (str.equals("currentColor")) {
+                        currentStream.write(
+                          currentColour.getColorSpaceOut(true));
+                        di.fill = true;
+                        //                             } else {
+                        //                                     handleGradient(str, true, area);
+                    }
+                }
+            }
+        } else {
+            PDFColor fillColour = new PDFColor(0, 0, 0);
+            currentStream.write(fillColour.getColorSpaceOut(true));
+        }
+        sp = style.getPresentationAttribute("fill-rule");
+        if (sp != null) {
+            if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
+                if (((CSSPrimitiveValue) sp).getPrimitiveType() ==
+                        CSSPrimitiveValue.CSS_STRING) {
+                    if (sp.getCssText().equals("nonzero")) {
+                        di.nonzero = true;
+                    }
+                }
+            }
+        } else {
+        }
+        sp = style.getPresentationAttribute("stroke");
+        if (sp != null) {
+            if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
+                if (((CSSPrimitiveValue) sp).getPrimitiveType() ==
+                        CSSPrimitiveValue.CSS_RGBCOLOR) {
+                    RGBColor col =
+                      ((CSSPrimitiveValue) sp).getRGBColorValue();
+                    CSSPrimitiveValue val;
+                    val = col.getRed();
+                    float red = val.getFloatValue(
+                                  CSSPrimitiveValue.CSS_NUMBER);
+                    val = col.getGreen();
+                    float green = val.getFloatValue(
+                                    CSSPrimitiveValue.CSS_NUMBER);
+                    val = col.getBlue();
+                    float blue = val.getFloatValue(
+                                   CSSPrimitiveValue.CSS_NUMBER);
+                    PDFColor fillColour = new PDFColor(red, green, blue);
+                    currentStream.write(
+                      fillColour.getColorSpaceOut(false));
+                    di.stroke = true;
+                } else if ( ((CSSPrimitiveValue) sp).getPrimitiveType() ==
+                    CSSPrimitiveValue.CSS_URI) {
+                    // gradient
+                    String str = ((CSSPrimitiveValue) sp).getCssText();
+                    handleGradient(str, di, false, area);
+                } else if ( ((CSSPrimitiveValue) sp).getPrimitiveType() ==
+                    CSSPrimitiveValue.CSS_STRING) {
+                    String str = ((CSSPrimitiveValue) sp).getCssText();
+                    if (str.equals("none")) {
+                        di.stroke = false;
+                        //                             } else {
+                        //                                     handleGradient(str, false, area);
+                    }
+                }
+            }
+        } else {
+            PDFColor fillColour = new PDFColor(0, 0, 0);
+            currentStream.write(fillColour.getColorSpaceOut(false));
+        }
+        sp = style.getPresentationAttribute("stroke-linecap");
+        if (sp != null) {
+            if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
+                if (((CSSPrimitiveValue) sp).getPrimitiveType() ==
+                        CSSPrimitiveValue.CSS_STRING) {
+                    String str = sp.getCssText();
+                    // butt, round ,square
+                    if (str.equals("butt")) {
+                        currentStream.write(0 + " J\n");
+                    } else if (str.equals("round")) {
+                        currentStream.write(1 + " J\n");
+                    } else if (str.equals("square")) {
+                        currentStream.write(2 + " J\n");
+                    }
+                }
+            }
+        } else {
+        }
+        sp = style.getPresentationAttribute("stroke-linejoin");
+        if (sp != null) {
+            if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
+                if (((CSSPrimitiveValue) sp).getPrimitiveType() ==
+                        CSSPrimitiveValue.CSS_STRING) {
+                    String str = sp.getCssText();
+                    if (str.equals("miter")) {
+                        currentStream.write(0 + " j\n");
+                    } else if (str.equals("round")) {
+                        currentStream.write(1 + " j\n");
+                    } else if (str.equals("bevel")) {
+                        currentStream.write(2 + " j\n");
+                    }
+                }
+            }
+        } else {
+        }
+        sp = style.getPresentationAttribute("stroke-miterlimit");
+        if (sp != null) {
+            if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
+                float width;
+                width = ((CSSPrimitiveValue) sp).getFloatValue(
+                          CSSPrimitiveValue.CSS_PT);
+                PDFNumber pdfNumber = new PDFNumber();
+                currentStream.write(pdfNumber.doubleOut(width) + " M\n");
+            }
+        } else {
+        }
+        sp = style.getPresentationAttribute("stroke-width");
+        if (sp != null) {
+            if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
+                float width;
+                width = ((CSSPrimitiveValue) sp).getFloatValue(
+                          CSSPrimitiveValue.CSS_PT);
+                PDFNumber pdfNumber = new PDFNumber();
+                currentStream.write(pdfNumber.doubleOut(width) + " w\n");
+            }
+        }
+        sp = style.getPresentationAttribute("stroke-dasharray");
+        if (sp != null) {
+            if (sp.getValueType() == CSSValue.CSS_VALUE_LIST) {
+                currentStream.write("[ ");
+                CSSValueList list = (CSSValueList) sp;
+                for (int count = 0; count < list.getLength(); count++) {
+                    CSSValue val = list.item(count);
+                    if (val.getValueType() ==
+                            CSSValue.CSS_PRIMITIVE_VALUE) {
+                        currentStream.write(
+                          ((CSSPrimitiveValue) val).getFloatValue(
+                            CSSPrimitiveValue.CSS_NUMBER) + " ");
+                    }
+                }
+                currentStream.write("] ");
+                sp = style.getPresentationAttribute("stroke-offset");
+                if (sp != null && sp.getValueType() ==
+                        CSSValue.CSS_PRIMITIVE_VALUE) {
+                    currentStream.write(
+                      ((CSSPrimitiveValue) sp).getFloatValue(
+                        CSSPrimitiveValue.CSS_NUMBER) + " d\n");
+                } else {
+                    currentStream.write("0 d\n");
+                }
+            }
+            /*                 Vector list;
+                               list = (Vector)sp;
+                               currentStream.add("[ ");
+                               for(Enumeration e = list.elements(); e.hasMoreElements(); ) {
+                                       Integer val = (Integer)e.nextElement();
+                                       currentStream.add(val.intValue() + " ");
+                               }
+                               sp = style.getPropertyCSSValue("stroke-offset");
+                               if(sp != null) {
+                                       float width;
+                                       width = ((SVGLengthImpl)sp).getValue();
+                                       PDFNumber pdfNumber = new PDFNumber();
+                                       currentStream.add("] " + pdfNumber.doubleOut(width) + " d\n");
+                               } else {
+                                       currentStream.add("] 0 d\n");
+                               }*/
+
+        }
+        sp = style.getPresentationAttribute("mask");
+        if (sp != null) {
+            String maskurl;
+            if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
+                if (((CSSPrimitiveValue) sp).getPrimitiveType() ==
+                        CSSPrimitiveValue.CSS_STRING) {
+                    maskurl = ((CSSPrimitiveValue) sp).getCssText();
+                    //                                 System.out.println("mask: " + maskurl);
+                    // get def of mask and set mask
+                    SVGElement graph = null;
+                    graph = locateDef(maskurl, area);
+                    if (graph != null) {
+                        System.out.println("mask: " + graph);
+                        //                                             SVGElement parent = graph.getGraphicParent();
+                        //                                             graph.setParent(area);
+                        //                                             renderElement(svgarea, graph, posx, posy);
+                        //                                             graph.setParent(parent);
+                    }
+                }
+            }
+        }
+        return di;
+    }
+
+    protected void applyTransform(SVGAnimatedTransformList trans) {
+        PDFNumber pdfNumber = new PDFNumber();
+        SVGTransformList list = trans.getBaseVal();
+        for (int count = 0; count < list.getNumberOfItems(); count++) {
+            SVGMatrix matrix =
+              ((SVGTransform) list.getItem(count)).getMatrix();
+            currentStream.write(pdfNumber.doubleOut(matrix.getA()) +
+                                " " + pdfNumber.doubleOut(matrix.getB()) + " " +
+                                pdfNumber.doubleOut(matrix.getC()) + " " +
+                                pdfNumber.doubleOut(matrix.getD()) + " " +
+                                pdfNumber.doubleOut(matrix.getE()) + " " +
+                                pdfNumber.doubleOut(matrix.getF()) + " cm\n");
+        }
+    }
+
+    public void renderElement(SVGElement area, int posx, int posy) {
+        int x = posx;
+        int y = posy;
+        //             CSSStyleDeclaration style = null;
+        //             if(area instanceof SVGStylable)
+        //                     style = ((SVGStylable)area).getStyle();
+        DrawingInstruction di = null;
+
+        currentStream.write("q\n");
+        if (area instanceof SVGTransformable) {
+            SVGTransformable tf = (SVGTransformable) area;
+            SVGAnimatedTransformList trans = tf.getTransform();
+            if (trans != null) {
+                applyTransform(trans);
+            }
+        }
+
+        if (area instanceof SVGStylable) {
+            di = applyStyle(area, (SVGStylable) area);
+        }
+
+        if (area instanceof SVGRectElement) {
+            SVGRectElement rg = (SVGRectElement) area;
+            float rectx = rg.getX().getBaseVal().getValue();
+            float recty = rg.getY().getBaseVal().getValue();
+            float rx = rg.getRx().getBaseVal().getValue();
+            float ry = rg.getRy().getBaseVal().getValue();
+            float rw = rg.getWidth().getBaseVal().getValue();
+            float rh = rg.getHeight().getBaseVal().getValue();
+            addRect(rectx, recty, rw, rh, rx, ry, di);
+        } else if (area instanceof SVGLineElement) {
+            SVGLineElement lg = (SVGLineElement) area;
+            float x1 = lg.getX1().getBaseVal().getValue();
+            float y1 = lg.getY1().getBaseVal().getValue();
+            float x2 = lg.getX2().getBaseVal().getValue();
+            float y2 = lg.getY2().getBaseVal().getValue();
+            addLine(x1, y1, x2, y2, di);
+        } else if (area instanceof SVGTextElementImpl) {
+            //                 currentStream.add("q\n");
+            //                 currentStream.add(1 + " " + 0 + " " + 0 + " " + 1 + " " + 0 + " " + 0 + " cm\n");
+            currentStream.write("BT\n");
+            renderText((SVGTextElementImpl) area, 0, 0, di);
+            currentStream.write("ET\n");
+            //                 currentStream.add("Q\n");
+        } else if (area instanceof SVGCircleElement) {
+            SVGCircleElement cg = (SVGCircleElement) area;
+            float cx = cg.getCx().getBaseVal().getValue();
+            float cy = cg.getCy().getBaseVal().getValue();
+            float r = cg.getR().getBaseVal().getValue();
+            addCircle(cx, cy, r, di);
+        } else if (area instanceof SVGEllipseElement) {
+            SVGEllipseElement cg = (SVGEllipseElement) area;
+            float cx = cg.getCx().getBaseVal().getValue();
+            float cy = cg.getCy().getBaseVal().getValue();
+            float rx = cg.getRx().getBaseVal().getValue();
+            float ry = cg.getRy().getBaseVal().getValue();
+            addEllipse(cx, cy, rx, ry, di);
+        } else if (area instanceof SVGPathElementImpl) {
+            addPath(((SVGPathElementImpl) area).pathElements, posx,
+                    posy, di);
+        } else if (area instanceof SVGPolylineElementImpl) {
+            addPolyline(((SVGPolylineElementImpl) area).points, di, false);
+        } else if (area instanceof SVGPolygonElementImpl) {
+            addPolyline(((SVGPolygonElementImpl) area).points, di, true);
+        } else if (area instanceof SVGGElementImpl) {
+            renderGArea((SVGGElementImpl) area, x, y);
+        } else if (area instanceof SVGUseElementImpl) {
+            SVGUseElementImpl ug = (SVGUseElementImpl) area;
+            String ref = ug.link;
+            //                 ref = ref.substring(1, ref.length());
+            SVGElement graph = null;
+            graph = locateDef(ref, ug);
+            if (graph != null) {
+                // probably not the best way to do this, should be able
+                // to render without the style being set.
+                //                             SVGElement parent = graph.getGraphicParent();
+                //                             graph.setParent(area);
+                // need to clip (if necessary) to the use area
+                // the style of the linked element is as if it was
+                // a direct descendant of the use element.
+
+                // scale to the viewBox
+
+                if (graph instanceof SVGSymbolElement) {
+                    currentStream.write("q\n");
+                    SVGSymbolElement symbol = (SVGSymbolElement) graph;
+                    SVGRect view = symbol.getViewBox().getBaseVal();
+                    float usex = ug.getX().getBaseVal().getValue();
+                    float usey = ug.getY().getBaseVal().getValue();
+                    float usewidth = ug.getWidth().getBaseVal().getValue();
+                    float useheight =
+                      ug.getHeight().getBaseVal().getValue();
+                    float scaleX;
+                    float scaleY;
+                    scaleX = usewidth / view.getWidth();
+                    scaleY = useheight / view.getHeight();
+                    currentStream.write(usex + " " + usey + " m\n");
+                    currentStream.write((usex + usewidth) + " " +
+                                        usey + " l\n");
+                    currentStream.write((usex + usewidth) + " " +
+                                        (usey + useheight) + " l\n");
+                    currentStream.write(usex + " " +
+                                        (usey + useheight) + " l\n");
+                    currentStream.write("h\n");
+                    currentStream.write("W\n");
+                    currentStream.write("n\n");
+                    currentStream.write(scaleX + " 0 0 " + scaleY +
+                                        " " + usex + " " + usey + " cm\n");
+                    renderSymbol(symbol, posx, posy);
+                    currentStream.write("Q\n");
+                } else {
+                    renderElement(graph, posx, posy);
+                }
+                //                             graph.setParent(parent);
+            }
+            else {
+                MessageHandler.logln("Use Element: " + ref + " not found");
+            }
+        } else if (area instanceof SVGImageElementImpl) {
+            SVGImageElementImpl ig = (SVGImageElementImpl) area;
+            renderImage(ig.link, ig.x, ig.y, ig.width, ig.height);
+        } else if (area instanceof SVGSVGElement) {
+            currentStream.write("q\n");
+            SVGSVGElement svgel = (SVGSVGElement) area;
+            float svgx = 0;
+            if (svgel.getX() != null)
+                svgx = svgel.getX().getBaseVal().getValue();
+            float svgy = 0;
+            if (svgel.getY() != null)
+                svgy = svgel.getY().getBaseVal().getValue();
+            currentStream.write(1 + " 0 0 " + 1 + " " + svgx + " " +
+                                svgy + " cm\n");
+            renderSVG(svgel, (int)(x + 1000 * svgx),
+                      (int)(y + 1000 * svgy));
+            currentStream.write("Q\n");
+            //         } else if (area instanceof SVGSymbolElement) {
+            // 'symbol' element is not rendered (except by 'use')
+        } else if (area instanceof SVGAElement) {
+            SVGAElement ael = (SVGAElement) area;
+            org.w3c.dom.NodeList nl = ael.getChildNodes();
+            for (int count = 0; count < nl.getLength(); count++) {
+                org.w3c.dom.Node n = nl.item(count);
+                if (n instanceof SVGElement) {
+                    if (n instanceof GraphicElement) {
+                        SVGRect rect = ((GraphicElement) n).getBBox();
+                        if (rect != null) {
+                            /*                                                 currentAnnotList = this.pdfDoc.makeAnnotList();
+                                                                               currentPage.setAnnotList(currentAnnotList);
+                                                                               String dest = linkSet.getDest();
+                                                                               int linkType = linkSet.getLinkType();
+                                                                               currentAnnotList.addLink(
+                                                                                       this.pdfDoc.makeLink(lrect.getRectangle(), dest, linkType));
+                                                                               currentAnnotList = null;
+                             */ }
+                    }
+                    renderElement((SVGElement) n, posx, posy);
+                }
+            }
+        } else if (area instanceof SVGSwitchElement) {
+            handleSwitchElement(posx, posy, (SVGSwitchElement) area);
+        }
+        // should be done with some cleanup code, so only
+        // required values are reset.
+        currentStream.write("Q\n");
+    }
+
+    /**
+     * Todo: underline, linethrough, textpath, tref
+     */
+    public void renderText(SVGTextElementImpl tg, float x, float y,
+                           DrawingInstruction di) {
+        SVGTextRenderer str = new SVGTextRenderer(fontState, tg, x, y);
+        if (di.fill) {
+            if (di.stroke) {
+                currentStream.write("2 Tr\n");
+            } else {
+                currentStream.write("0 Tr\n");
+            }
+        } else if (di.stroke) {
+            currentStream.write("1 Tr\n");
+        }
+        str.renderText(tg);
+    }
+
+    /**
+     * Adds an svg string to the output.
+     * This handles the escaping of special pdf chars and deals with
+     * whitespace.
+     */
+    protected float addSVGStr(FontState fs, float currentX, String str,
+                              boolean spacing) {
+        boolean inbetween = false;
+        boolean addedspace = false;
+        StringBuffer pdf = new StringBuffer();
+        for (int i = 0; i < str.length(); i++) {
+            char ch = str.charAt(i);
+            if (ch > 127) {
+                pdf = pdf.append("\\");
+                pdf = pdf.append(Integer.toOctalString((int) ch));
+                currentX += fs.width(ch) / 1000f;
+                inbetween = true;
+                addedspace = false;
+            } else {
+                switch (ch) {
+                    case '(' :
+                        pdf = pdf.append("\\(");
+                        currentX += fs.width(ch) / 1000f;
+                        inbetween = true;
+                        addedspace = false;
+                        break;
+                    case ')' :
+                        pdf = pdf.append("\\)");
+                        currentX += fs.width(ch) / 1000f;
+                        inbetween = true;
+                        addedspace = false;
+                        break;
+                    case '\\' :
+                        pdf = pdf.append("\\\\");
+                        currentX += fs.width(ch) / 1000f;
+                        inbetween = true;
+                        addedspace = false;
+                        break;
+                    case '     ':
+                    case ' ':
+                        if (spacing) {
+                            pdf = pdf.append(' ');
+                            currentX += fs.width(' ') / 1000f;
+                        } else {
+                            if (inbetween && !addedspace) {
+                                addedspace = true;
+                                pdf = pdf.append(' ');
+                                currentX += fs.width(' ') / 1000f;
+                            }
+                        }
+                        break;
+                    case '\n':
+                    case '\r':
+                        if (spacing) {
+                            pdf = pdf.append(' ');
+                            currentX += fs.width(' ') / 1000f;
+                        }
+                        break;
+                    default:
+                        addedspace = false;
+                        pdf = pdf.append(ch);
+                        currentX += fs.width(ch) / 1000f;
+                        inbetween = true;
+                        break;
+                }
+            }
+        }
+        currentStream.write(pdf.toString());
+        return currentX;
+    }
+
+    /**
+     * Locates a defined element in an svg document.
+     * Either gets the element defined by its "id" in the current
+     * SVGDocument, or if the uri reference is to an external
+     * document it loads the document and returns the element.
+     */
+    protected SVGElement locateDef(String ref, SVGElement currentElement) {
+        int pos;
+        ref = ref.trim();
+        pos = ref.indexOf("#");
+        if (pos == 0) {
+            // local doc
+            Document doc = currentElement.getOwnerDocument();
+            Element ele =
+              doc.getElementById(ref.substring(1, ref.length()));
+            if (ele instanceof SVGElement) {
+                return (SVGElement) ele;
+            }
+        } else if (pos != -1) {
+            String href = ref.substring(0, pos);
+            if (href.indexOf(":") == -1) {
+                href = "file:" + href;
+            }
+            try {
+                // this is really only to get a cached svg image
+                FopImage img = FopImageFactory.Make(href);
+                if (img instanceof SVGImage) {
+                    SVGDocument doc = ((SVGImage) img).getSVGDocument();
+                    Element ele = doc.getElementById(
+                                    ref.substring(pos + 1, ref.length()));
+                    if (ele instanceof SVGElement) {
+                        return (SVGElement) ele;
+                    }
+                }
+            } catch (Exception e) {
+                System.out.println(e);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * This class is used to handle the rendering of svg text.
+     * This is so that it can deal with the recursive rendering
+     * of text markup, while keeping track of the state and position.
+     */
+    class SVGTextRenderer {
+        FontState fs;
+        String transstr;
+        float currentX;
+        float currentY;
+        float baseX;
+        float baseY;
+        SVGMatrix matrix;
+        float x;
+        float y;
+
+        SVGTextRenderer(FontState fontState, SVGTextElementImpl tg,
+                        float x, float y) {
+            fs = fontState;
+
+            PDFNumber pdfNumber = new PDFNumber();
+            SVGTransformList trans = tg.getTransform().getBaseVal();
+            matrix = trans.consolidate().getMatrix();
+            transstr = (pdfNumber.doubleOut(matrix.getA()) + " " +
+                        pdfNumber.doubleOut(matrix.getB()) + " " +
+                        pdfNumber.doubleOut(matrix.getC()) + " " +
+                        pdfNumber.doubleOut(-matrix.getD()) + " ");
+            this.x = x;
+            this.y = y;
+        }
+
+        void renderText(SVGTextElementImpl te) {
+            DrawingInstruction di = applyStyle(te, te);
+            if (di.fill) {
+                if (di.stroke) {
+                    currentStream.write("2 Tr\n");
+                } else {
+                    currentStream.write("0 Tr\n");
+                }
+            } else if (di.stroke) {
+                currentStream.write("1 Tr\n");
+            }
+            updateFont(te, fs);
+
+            float tx = te.x;
+            float ty = te.y;
+            currentX = x + tx;
+            currentY = y + ty;
+            baseX = currentX;
+            baseY = currentY;
+            NodeList nodel = te.getChildNodes();
+            //         Vector list = te.textList;
+            for (int count = 0; count < nodel.getLength(); count++) {
+                Object o = nodel.item(count);
+                applyStyle(te, te);
+                if (o instanceof CharacterData) {
+                    String str = ((CharacterData) o).getData();
+                    currentStream.write(transstr +
+                                        (currentX + matrix.getE()) + " " +
+                                        (baseY + matrix.getF()) + " Tm " + "(");
+                    boolean spacing = "preserve".equals(te.getXMLspace());
+                    currentX = addSVGStr(fs, currentX, str, spacing);
+                    currentStream.write(") Tj\n");
+                } else if (o instanceof SVGTextPathElementImpl) {
+                    SVGTextPathElementImpl tpg = (SVGTextPathElementImpl) o;
+                    String ref = tpg.str;
+                    SVGElement graph = null;
+                    graph = locateDef(ref, tpg);
+                    if (graph instanceof SVGPathElementImpl) {
+                        // probably not the best way to do this, should be able
+                        // to render without the style being set.
+                        //                                     GraphicImpl parent = graph.getGraphicParent();
+                        //                                     graph.setParent(tpg);
+                        // set text path??
+                        // how should this work
+                        //                                     graph.setParent(parent);
+                    }
+                } else if (o instanceof SVGTRefElementImpl) {
+                    SVGTRefElementImpl trg = (SVGTRefElementImpl) o;
+                    String ref = trg.ref;
+                    SVGElement element = locateDef(ref, trg);
+                    if (element instanceof SVGTextElementImpl) {
+                        //                                     GraphicImpl parent = graph.getGraphicParent();
+                        //                                     graph.setParent(trg);
+                        SVGTextElementImpl tele =
+                          (SVGTextElementImpl) element;
+                        // the style should be from tele, but it needs to be placed as a child
+                        // of trg to work
+                        di = applyStyle(trg, trg);
+                        if (di.fill) {
+                            if (di.stroke) {
+                                currentStream.write("2 Tr\n");
+                            } else {
+                                currentStream.write("0 Tr\n");
+                            }
+                        } else if (di.stroke) {
+                            currentStream.write("1 Tr\n");
+                        }
+                        boolean changed = false;
+                        FontState oldfs = fs;
+                        changed = updateFont(te, fs);
+                        NodeList nl = tele.getChildNodes();
+                        boolean spacing =
+                          "preserve".equals(trg.getXMLspace());
+                        renderTextNodes(spacing, nl,
+                                        trg.getX().getBaseVal(),
+                                        trg.getY().getBaseVal(),
+                                        trg.getDx().getBaseVal(),
+                                        trg.getDy().getBaseVal());
+
+                        if (changed) {
+                            fs = oldfs;
+                            currentStream.write("/" +
+                                                fs.getFontName() + " " +
+                                                fs.getFontSize() / 1000f + " Tf\n");
+                        }
+                        //                                     graph.setParent(parent);
+                    }
+                } else if (o instanceof SVGTSpanElementImpl) {
+                    SVGTSpanElementImpl tsg = (SVGTSpanElementImpl) o;
+                    applyStyle(tsg, tsg);
+                    boolean changed = false;
+                    FontState oldfs = fs;
+                    changed = updateFont(tsg, fs);
+                    boolean spacing = "preserve".equals(tsg.getXMLspace());
+                    renderTextNodes(spacing, tsg.getChildNodes(),
+                                    tsg.getX().getBaseVal(),
+                                    tsg.getY().getBaseVal(),
+                                    tsg.getDx().getBaseVal(),
+                                    tsg.getDy().getBaseVal());
+
+                    //                         currentX += fs.width(' ') / 1000f;
+                    if (changed) {
+                        fs = oldfs;
+                        currentStream.write("/" + fs.getFontName() +
+                                            " " + fs.getFontSize() / 1000f + " Tf\n");
+                    }
+                } else {
+                    System.err.println("Error: unknown text element " + o);
+                }
+            }
+        }
+
+        void renderTextNodes(boolean spacing, NodeList nl,
+                             SVGLengthList xlist, SVGLengthList ylist,
+                             SVGLengthList dxlist, SVGLengthList dylist) {
+            boolean inbetween = false;
+            boolean addedspace = false;
+            int charPos = 0;
+            float xpos = currentX;
+            float ypos = currentY;
+
+            for (int count = 0; count < nl.getLength(); count++) {
+                Node n = nl.item(count);
+                if (n instanceof CharacterData) {
+                    StringBuffer pdf = new StringBuffer();
+                    String str = ((CharacterData) n).getData();
+                    for (int i = 0; i < str.length(); i++) {
+                        char ch = str.charAt(i);
+                        xpos = currentX;
+                        ypos = currentY;
+                        if (ylist.getNumberOfItems() > charPos) {
+                            ypos = baseY + ((Float) ylist.getItem(charPos)).
+                                   floatValue();
+                        }
+                        if (dylist.getNumberOfItems() > charPos) {
+                            ypos = ypos + ((Float) dylist.getItem(charPos)).
+                                   floatValue();
+                        }
+                        if (xlist.getNumberOfItems() > charPos) {
+                            xpos = baseX + ((Float) xlist.getItem(charPos)).
+                                   floatValue();
+                        }
+                        if (dxlist.getNumberOfItems() > charPos) {
+                            xpos = xpos + ((Float) dxlist.getItem(charPos)).
+                                   floatValue();
+                        }
+                        if (ch > 127) {
+                            pdf = pdf.append(transstr +
+                                             (xpos + matrix.getE()) + " " +
+                                             (ypos + matrix.getF()) + " Tm " +
+                                             "(" + "\\" +
+                                             Integer.toOctalString((int) ch) +
+                                             ") Tj\n");
+                            currentX = xpos + fs.width(ch) / 1000f;
+                            currentY = ypos;
+                            charPos++;
+                            inbetween = true;
+                            addedspace = false;
+                        } else {
+                            switch (ch) {
+                                case '(' :
+                                    pdf = pdf.append(transstr +
+                                                     (xpos + matrix.getE()) +
+                                                     " " + (ypos +
+                                                            matrix.getF()) + " Tm " +
+                                                     "(" + "\\(" + ") Tj\n");
+                                    currentX = xpos + fs.width(ch) / 1000f;
+                                    currentY = ypos;
+                                    charPos++;
+                                    inbetween = true;
+                                    addedspace = false;
+                                    break;
+                                case ')' :
+                                    pdf = pdf.append(transstr +
+                                                     (xpos + matrix.getE()) +
+                                                     " " + (ypos +
+                                                            matrix.getF()) + " Tm " +
+                                                     "(" + "\\)" + ") Tj\n");
+                                    currentX = xpos + fs.width(ch) / 1000f;
+                                    currentY = ypos;
+                                    charPos++;
+                                    inbetween = true;
+                                    addedspace = false;
+                                    break;
+                                case '\\' :
+                                    pdf = pdf.append(transstr +
+                                                     (xpos + matrix.getE()) +
+                                                     " " + (ypos +
+                                                            matrix.getF()) + " Tm " +
+                                                     "(" + "\\\\" + ") Tj\n");
+                                    currentX = xpos + fs.width(ch) / 1000f;
+                                    currentY = ypos;
+                                    charPos++;
+                                    inbetween = true;
+                                    addedspace = false;
+                                    break;
+                                case ' ':
+                                case ' ':
+                                    if (spacing) {
+                                        currentX = xpos + fs.width(' ') /
+                                                   1000f;
+                                        currentY = ypos;
+                                        charPos++;
+                                    } else {
+                                        if (inbetween && !addedspace) {
+                                            addedspace = true;
+                                            currentX = xpos + fs.width(' ')
+                                                       / 1000f;
+                                            currentY = ypos;
+                                            charPos++;
+                                        }
+                                    }
+                                    break;
+                                case '\n':
+                                case '\r':
+                                    if (spacing) {
+                                        currentX = xpos + fs.width(' ') /
+                                                   1000f;
+                                        currentY = ypos;
+                                        charPos++;
+                                    }
+                                    break;
+                                default:
+                                    addedspace = false;
+                                    pdf = pdf.append(transstr +
+                                                     (xpos + matrix.getE()) +
+                                                     " " + (ypos +
+                                                            matrix.getF()) + " Tm " +
+                                                     "(" + ch + ") Tj\n");
+                                    currentX = xpos + fs.width(ch) / 1000f;
+                                    currentY = ypos;
+                                    charPos++;
+                                    inbetween = true;
+                                    break;
+                            }
+                        }
+                        currentStream.write(pdf.toString());
+                    }
+                }
+            }
+        }
+
+        protected boolean updateFont(SVGStylable style, FontState fs) {
+            boolean changed = false;
+            String fontFamily = fs.getFontFamily();
+            CSSValue sp = style.getPresentationAttribute("font-family");
+            if (sp != null &&
+                    sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
+                if (((CSSPrimitiveValue) sp).getPrimitiveType() ==
+                        CSSPrimitiveValue.CSS_STRING) {
+                    fontFamily = sp.getCssText();
+                }
+            }
+            if (!fontFamily.equals(fs.getFontFamily())) {
+                changed = true;
+            }
+            String fontStyle = fs.getFontStyle();
+            sp = style.getPresentationAttribute("font-style");
+            if (sp != null &&
+                    sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
+                if (((CSSPrimitiveValue) sp).getPrimitiveType() ==
+                        CSSPrimitiveValue.CSS_STRING) {
+                    fontStyle = sp.getCssText();
+                }
+            }
+            if (!fontStyle.equals(fs.getFontStyle())) {
+                changed = true;
+            }
+            String fontWeight = fs.getFontWeight();
+            sp = style.getPresentationAttribute("font-weight");
+            if (sp != null &&
+                    sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
+                if (((CSSPrimitiveValue) sp).getPrimitiveType() ==
+                        CSSPrimitiveValue.CSS_STRING) {
+                    fontWeight = sp.getCssText();
+                }
+            }
+            if (!fontWeight.equals(fs.getFontWeight())) {
+                changed = true;
+            }
+            float newSize = fs.getFontSize() / 1000f;
+            sp = style.getPresentationAttribute("font-size");
+            if (sp != null &&
+                    sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
+                //                 if(((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_NUMBER) {
+                newSize = ((CSSPrimitiveValue) sp).getFloatValue(
+                            CSSPrimitiveValue.CSS_PT);
+                //                 }
+            }
+            if (fs.getFontSize() / 1000f != newSize) {
+                changed = true;
+            }
+            if (changed) {
+                try {
+                    fs = new FontState(fs.getFontInfo(), fontFamily,
+                                       fontStyle, fontWeight, (int)(newSize * 1000));
+                } catch (Exception fope) {
+                }
+                this.fs = fs;
+
+                currentStream.write("/" + fs.getFontName() + " " +
+                                    newSize + " Tf\n");
+            } else {
+                if (!currentFontName.equals(fs.getFontName()) ||
+                        currentFontSize != fs.getFontSize()) {
+                    //                         currentFontName = fs.getFontName();
+                    //                         currentFontSize = fs.getFontSize();
+                    currentStream.write("/" + fs.getFontName() + " " +
+                                        (fs.getFontSize() / 1000) + " Tf\n");
+                }
+            }
+            return changed;
+        }
+    }
+}