aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop/svg
diff options
context:
space:
mode:
authorJeremias Maerki <jeremias@apache.org>2003-03-11 13:05:43 +0000
committerJeremias Maerki <jeremias@apache.org>2003-03-11 13:05:43 +0000
commit1e5d512c216d329effa693b91ef64652945def6a (patch)
tree5bd3521ee8121eade7bf1909ceaf29cfc0263fd1 /src/java/org/apache/fop/svg
parent73c824d39411bf11ad0c2f4e1c57cd9c484665f9 (diff)
downloadxmlgraphics-fop-1e5d512c216d329effa693b91ef64652945def6a.tar.gz
xmlgraphics-fop-1e5d512c216d329effa693b91ef64652945def6a.zip
Moved sources from src/org/** to src/java/org/**
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@196061 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop/svg')
-rw-r--r--src/java/org/apache/fop/svg/PDFAElementBridge.java124
-rw-r--r--src/java/org/apache/fop/svg/PDFANode.java156
-rw-r--r--src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java279
-rw-r--r--src/java/org/apache/fop/svg/PDFGraphics2D.java1660
-rw-r--r--src/java/org/apache/fop/svg/PDFGraphicsConfiguration.javat178
-rw-r--r--src/java/org/apache/fop/svg/PDFGraphicsDevice.java127
-rw-r--r--src/java/org/apache/fop/svg/PDFImageElementBridge.java181
-rw-r--r--src/java/org/apache/fop/svg/PDFTextElementBridge.java154
-rw-r--r--src/java/org/apache/fop/svg/PDFTextPainter.java434
-rw-r--r--src/java/org/apache/fop/svg/PDFTranscoder.java439
-rw-r--r--src/java/org/apache/fop/svg/SVGElement.java314
-rw-r--r--src/java/org/apache/fop/svg/SVGElementMapping.java115
-rw-r--r--src/java/org/apache/fop/svg/SVGObj.java79
-rw-r--r--src/java/org/apache/fop/svg/SVGUserAgent.java184
-rw-r--r--src/java/org/apache/fop/svg/SVGUtilities.java301
-rw-r--r--src/java/org/apache/fop/svg/package.html31
16 files changed, 4756 insertions, 0 deletions
diff --git a/src/java/org/apache/fop/svg/PDFAElementBridge.java b/src/java/org/apache/fop/svg/PDFAElementBridge.java
new file mode 100644
index 000000000..2969501f3
--- /dev/null
+++ b/src/java/org/apache/fop/svg/PDFAElementBridge.java
@@ -0,0 +1,124 @@
+/*
+ * $Id: PDFAElementBridge.java,v 1.6 2003/03/07 09:51:25 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 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.svg;
+
+import java.awt.geom.AffineTransform;
+
+import org.apache.batik.bridge.AbstractGraphicsNodeBridge;
+import org.apache.batik.bridge.BridgeContext;
+
+import org.apache.batik.gvt.GraphicsNode;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.svg.SVGAElement;
+
+/**
+ * Bridge class for the &lt;a> element.
+ *
+ * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+ */
+public class PDFAElementBridge extends AbstractGraphicsNodeBridge {
+ private AffineTransform transform;
+
+ /**
+ * Constructs a new bridge for the &lt;a> element.
+ */
+ public PDFAElementBridge() {
+ }
+
+ /**
+ * Set the current transform of this element.
+ * @param tf the transform
+ */
+ public void setCurrentTransform(AffineTransform tf) {
+ transform = tf;
+ }
+
+ /**
+ * Returns 'a'.
+ * @return the name of this node
+ */
+ public String getLocalName() {
+ return SVG_A_TAG;
+ }
+
+ /**
+ * Creates a <tt>CompositeGraphicsNode</tt>.
+ * @return a new PDFANode
+ */
+ protected GraphicsNode instantiateGraphicsNode() {
+ return new PDFANode();
+ }
+
+ /**
+ * Builds using the specified BridgeContext and element, the
+ * specified graphics node.
+ *
+ * @param ctx the bridge context to use
+ * @param e the element that describes the graphics node to build
+ * @return node the new graphics node
+ */
+ public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) {
+ PDFANode aNode = (PDFANode)super.createGraphicsNode(ctx, e);
+ aNode.setDestination(((SVGAElement)e).getHref().getBaseVal());
+ aNode.setTransform(transform);
+ return aNode;
+ }
+
+ /**
+ * Returns true as the &lt;a> element is a container.
+ * @return true if the a element is a container
+ */
+ public boolean isComposite() {
+ return true;
+ }
+
+}
diff --git a/src/java/org/apache/fop/svg/PDFANode.java b/src/java/org/apache/fop/svg/PDFANode.java
new file mode 100644
index 000000000..a200da27d
--- /dev/null
+++ b/src/java/org/apache/fop/svg/PDFANode.java
@@ -0,0 +1,156 @@
+/*
+ * $Id: PDFANode.java,v 1.11 2003/03/07 09:51:25 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 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.svg;
+
+import org.apache.batik.gvt.CompositeGraphicsNode;
+
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.AffineTransform;
+
+import java.util.StringTokenizer;
+
+/**
+ * A graphics node that represents an image described as a graphics node.
+ *
+ * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+ */
+public class PDFANode extends CompositeGraphicsNode {
+ private String destination;
+ private AffineTransform transform;
+
+ /**
+ * Constructs a new empty <tt>PDFANode</tt>.
+ */
+ public PDFANode() {
+ }
+
+ /**
+ * Set the destination String.
+ * @param dest the target destination
+ */
+ public void setDestination(String dest) {
+ destination = dest;
+ }
+
+ /**
+ * Set the current transform of this node.
+ * @param tf the transform
+ */
+ public void setTransform(AffineTransform tf) {
+ transform = tf;
+ }
+
+ /**
+ * Paints this node if visible.
+ *
+ * @param g2d the Graphics2D to use
+ */
+ public void paint(Graphics2D g2d) {
+ if (isVisible) {
+ super.paint(g2d);
+ if (g2d instanceof PDFGraphics2D) {
+ PDFGraphics2D pdfg = (PDFGraphics2D)g2d;
+ int type = org.apache.fop.pdf.PDFLink.EXTERNAL;
+ Shape outline = getOutline();
+ if (destination.startsWith("#svgView(viewBox(")) {
+ type = org.apache.fop.pdf.PDFLink.INTERNAL;
+ String nums = destination.substring(17, destination.length() - 2);
+ float x = 0;
+ float y = 0;
+ float width = 0;
+ float height = 0;
+ int count = 0;
+ try {
+ StringTokenizer st = new StringTokenizer(nums, ",");
+ while (st.hasMoreTokens()) {
+ String tok = st.nextToken();
+ count++;
+ switch(count) {
+ case 1:
+ x = Float.parseFloat(tok);
+ break;
+ case 2:
+ y = Float.parseFloat(tok);
+ break;
+ case 3:
+ width = Float.parseFloat(tok);
+ break;
+ case 4:
+ height = Float.parseFloat(tok);
+ break;
+ default:
+ break;
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ Rectangle2D destRect = new Rectangle2D.Float(x, y, width, height);
+ destRect = transform.createTransformedShape(destRect).getBounds();
+ // these numbers need conversion to current
+ // svg position and scaled for the page
+ x = (float)destRect.getX();
+ y = (float)destRect.getY();
+ width = (float)destRect.getWidth();
+ height = (float)destRect.getHeight();
+
+ destination = "" + x + " " + y + " "
+ + (x + width) + " " + (y + height);
+ }
+ pdfg.addLink(getBounds(), transform, destination, type);
+ }
+ }
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java b/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java
new file mode 100644
index 000000000..0ac52f075
--- /dev/null
+++ b/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java
@@ -0,0 +1,279 @@
+/*
+ * $Id: PDFDocumentGraphics2D.java,v 1.27 2003/03/07 09:51:26 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 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.svg;
+
+import org.apache.fop.pdf.PDFDocument;
+import org.apache.fop.pdf.PDFPage;
+import org.apache.fop.pdf.PDFStream;
+import org.apache.fop.pdf.PDFState;
+import org.apache.fop.pdf.PDFNumber;
+import org.apache.fop.pdf.PDFResources;
+import org.apache.fop.pdf.PDFColor;
+import org.apache.fop.pdf.PDFAnnotList;
+import org.apache.fop.render.pdf.FontSetup;
+import org.apache.fop.layout.FontInfo;
+
+import java.awt.Graphics;
+import java.awt.Font;
+import java.awt.Color;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * This class is a wrapper for the <tt>PDFGraphics2D</tt> that
+ * is used to create a full document around the pdf rendering from
+ * <tt>PDFGraphics2D</tt>.
+ *
+ * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+ * @version $Id: PDFDocumentGraphics2D.java,v 1.27 2003/03/07 09:51:26 jeremias Exp $
+ * @see org.apache.fop.svg.PDFGraphics2D
+ */
+public class PDFDocumentGraphics2D extends PDFGraphics2D {
+ private PDFPage currentPage;
+ private PDFStream pdfStream;
+ private int width;
+ private int height;
+
+ /**
+ * Create a new PDFDocumentGraphics2D.
+ * This is used to create a new pdf document, the height,
+ * width and output stream can be setup later.
+ * For use by the transcoder which needs font information
+ * for the bridge before the document size is known.
+ * The resulting document is written to the stream after rendering.
+ *
+ * @param textAsShapes set this to true so that text will be rendered
+ * using curves and not the font.
+ */
+ PDFDocumentGraphics2D(boolean textAsShapes) {
+ super(textAsShapes);
+
+ if (!textAsShapes) {
+ fontInfo = new FontInfo();
+ FontSetup.setup(fontInfo, null);
+ //FontState fontState = new FontState("Helvetica", "normal",
+ // FontInfo.NORMAL, 12, 0);
+ }
+
+ this.pdfDoc = new PDFDocument("FOP SVG Renderer");
+
+ graphicsState = new PDFState();
+
+ currentFontName = "";
+ currentFontSize = 0;
+
+ pdfStream = this.pdfDoc.makeStream(PDFStream.CONTENT_FILTER, false);
+ }
+
+ /**
+ * Setup the document.
+ * @param stream the output stream to write the document
+ * @param width the width of the page
+ * @param height the height of the page
+ * @throws IOException an io exception if there is a problem
+ * writing to the output stream
+ */
+ public void setupDocument(OutputStream stream, int width, int height) throws IOException {
+ this.width = width;
+ this.height = height;
+
+ PDFResources pdfResources = this.pdfDoc.getResources();
+ currentPage = this.pdfDoc.makePage(pdfResources,
+ width, height);
+ resourceContext = currentPage;
+ pageRef = currentPage.referencePDF();
+ currentStream.write("1 0 0 -1 0 " + height + " cm\n");
+ graphicsState.setTransform(new AffineTransform(1.0, 0.0, 0.0, -1.0, 0.0, (double)height));
+ pdfDoc.outputHeader(stream);
+
+ setOutputStream(stream);
+ }
+
+ /**
+ * Create a new PDFDocumentGraphics2D.
+ * This is used to create a new pdf document of the given height
+ * and width.
+ * The resulting document is written to the stream after rendering.
+ *
+ * @param textAsShapes set this to true so that text will be rendered
+ * using curves and not the font.
+ * @param stream the stream that the final document should be written to.
+ * @param width the width of the document
+ * @param height the height of the document
+ * @throws IOException an io exception if there is a problem
+ * writing to the output stream
+ */
+ public PDFDocumentGraphics2D(boolean textAsShapes, OutputStream stream,
+ int width, int height) throws IOException {
+ this(textAsShapes);
+ setupDocument(stream, width, height);
+ }
+
+ /**
+ * Get the font info for this pdf document.
+ * @return the font information
+ */
+ public FontInfo getFontInfo() {
+ return fontInfo;
+ }
+
+ /**
+ * Get the pdf document created by this class.
+ * @return the pdf document
+ */
+ public PDFDocument getPDFDocument() {
+ return this.pdfDoc;
+ }
+
+ /**
+ * Set the dimensions of the svg document that will be drawn.
+ * This is useful if the dimensions of the svg document are different
+ * from the pdf document that is to be created.
+ * The result is scaled so that the svg fits correctly inside the
+ * pdf document.
+ * @param w the width of the page
+ * @param h the height of the page
+ */
+ public void setSVGDimension(float w, float h) {
+ currentStream.write("" + PDFNumber.doubleOut(width / w) + " 0 0 "
+ + PDFNumber.doubleOut(height / h) + " 0 0 cm\n");
+ }
+
+ /**
+ * Set the background of the pdf document.
+ * This is used to set the background for the pdf document
+ * Rather than leaving it as the default white.
+ * @param col the background colour to fill
+ */
+ public void setBackgroundColor(Color col) {
+ Color c = col;
+ PDFColor currentColour = new PDFColor(c.getRed(), c.getGreen(), c.getBlue());
+ currentStream.write("q\n");
+ currentStream.write(currentColour.getColorSpaceOut(true));
+
+ currentStream.write("0 0 " + width + " " + height + " re\n");
+
+ currentStream.write("f\n");
+ currentStream.write("Q\n");
+ }
+
+ /**
+ * The rendering process has finished.
+ * This should be called after the rendering has completed as there is
+ * no other indication it is complete.
+ * This will then write the results to the output stream.
+ * @throws IOException an io exception if there is a problem
+ * writing to the output stream
+ */
+ public void finish() throws IOException {
+ // restorePDFState();
+
+ pdfStream.add(getString());
+ this.pdfDoc.addStream(pdfStream);
+ currentPage.setContents(pdfStream);
+ PDFAnnotList annots = currentPage.getAnnotations();
+ if (annots != null) {
+ this.pdfDoc.addAnnotList(annots);
+ }
+ this.pdfDoc.addPage(currentPage);
+ if (fontInfo != null) {
+ FontSetup.addToResources(pdfDoc, pdfDoc.getResources(), fontInfo);
+ }
+ this.pdfDoc.output(outputStream);
+ pdfDoc.outputTrailer(outputStream);
+
+ outputStream.flush();
+ }
+
+ /**
+ * This constructor supports the create method
+ * @param g the pdf document graphics to make a copy of
+ */
+ public PDFDocumentGraphics2D(PDFDocumentGraphics2D g) {
+ super(g);
+ }
+
+ /**
+ * Creates a new <code>Graphics</code> object that is
+ * a copy of this <code>Graphics</code> object.
+ * @return a new graphics context that is a copy of
+ * this graphics context.
+ */
+ public Graphics create() {
+ return new PDFDocumentGraphics2D(this);
+ }
+
+ /**
+ * Draw a string to the pdf document.
+ * This either draws the string directly or if drawing text as
+ * shapes it converts the string into shapes and draws that.
+ * @param s the string to draw
+ * @param x the x position
+ * @param y the y position
+ */
+ public void drawString(String s, float x, float y) {
+ if (super.textAsShapes) {
+ Font font = super.getFont();
+ FontRenderContext frc = super.getFontRenderContext();
+ GlyphVector gv = font.createGlyphVector(frc, s);
+ Shape glyphOutline = gv.getOutline(x, y);
+ super.fill(glyphOutline);
+ } else {
+ super.drawString(s, x, y);
+ }
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/svg/PDFGraphics2D.java b/src/java/org/apache/fop/svg/PDFGraphics2D.java
new file mode 100644
index 000000000..64fbdcfe9
--- /dev/null
+++ b/src/java/org/apache/fop/svg/PDFGraphics2D.java
@@ -0,0 +1,1660 @@
+/*
+ * $Id: PDFGraphics2D.java,v 1.48 2003/03/07 09:51:26 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 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.svg;
+
+import org.apache.fop.pdf.PDFResourceContext;
+import org.apache.fop.pdf.PDFResources;
+import org.apache.fop.pdf.PDFGState;
+import org.apache.fop.pdf.PDFColorSpace;
+import org.apache.fop.pdf.PDFColor;
+import org.apache.fop.pdf.PDFState;
+import org.apache.fop.pdf.PDFNumber;
+import org.apache.fop.pdf.PDFXObject;
+import org.apache.fop.pdf.PDFPattern;
+import org.apache.fop.pdf.PDFDocument;
+import org.apache.fop.pdf.PDFLink;
+import org.apache.fop.pdf.PDFAnnotList;
+import org.apache.fop.pdf.BitmapImage;
+import org.apache.fop.layout.FontInfo;
+import org.apache.fop.layout.FontState;
+import org.apache.fop.render.pdf.FontSetup;
+import org.apache.fop.fonts.FontMetrics;
+import org.apache.fop.fonts.LazyFont;
+import org.apache.fop.image.JpegImage;
+import org.apache.fop.fonts.CIDFont;
+import org.apache.fop.render.pdf.FopPDFImage;
+
+import org.apache.batik.ext.awt.g2d.AbstractGraphics2D;
+import org.apache.batik.ext.awt.g2d.GraphicContext;
+//import org.apache.batik.ext.awt.MultipleGradientPaint;
+import org.apache.batik.ext.awt.RadialGradientPaint;
+import org.apache.batik.ext.awt.LinearGradientPaint;
+import org.apache.batik.gvt.PatternPaint;
+import org.apache.batik.gvt.GraphicsNode;
+
+import java.text.AttributedCharacterIterator;
+import java.text.CharacterIterator;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Color;
+import java.awt.GraphicsConfiguration;
+import java.awt.Font;
+import java.awt.Image;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.Paint;
+import java.awt.Rectangle;
+import java.awt.Dimension;
+import java.awt.BasicStroke;
+import java.awt.AlphaComposite;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferInt;
+import java.awt.image.ImageObserver;
+import java.awt.image.RenderedImage;
+import java.awt.image.Raster;
+import java.awt.image.renderable.RenderableImage;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.color.ColorSpace;
+import java.io.StringWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.util.Map;
+import java.util.List;
+
+/**
+ * PDF Graphics 2D.
+ * Used for drawing into a pdf document as if it is a graphics object.
+ * This takes a pdf document and draws into it.
+ *
+ * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+ * @version $Id: PDFGraphics2D.java,v 1.48 2003/03/07 09:51:26 jeremias Exp $
+ * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D
+ */
+public class PDFGraphics2D extends AbstractGraphics2D {
+ /**
+ * the PDF Document being created
+ */
+ protected PDFDocument pdfDoc;
+
+ /**
+ * The current resource context for adding fonts, patterns etc.
+ */
+ protected PDFResourceContext resourceContext;
+
+ /**
+ * The PDF reference of the current page.
+ */
+ protected String pageRef;
+
+ /**
+ * the current state of the pdf graphics
+ */
+ protected PDFState graphicsState;
+
+ /**
+ * The PDF graphics state level that this svg is being drawn into.
+ */
+ protected int baseLevel = 0;
+
+ /**
+ * The current font information.
+ */
+ protected FontInfo fontInfo;
+
+ /**
+ * The override font state used when drawing text and the font cannot be
+ * set using java fonts.
+ */
+ protected FontState ovFontState = null;
+
+ /**
+ * the current stream to add PDF commands to
+ */
+ protected StringWriter currentStream = new StringWriter();
+
+ /**
+ * the current (internal) font name
+ */
+ protected String currentFontName;
+
+ /**
+ * the current font size in millipoints
+ */
+ protected float currentFontSize;
+
+ /**
+ * The output stream for the pdf document.
+ * If this is set then it can progressively output
+ * the pdf document objects to reduce memory.
+ * Especially with images.
+ */
+ protected OutputStream outputStream = null;
+
+ /**
+ * Create a new PDFGraphics2D with the given pdf document info.
+ * This is used to create a Graphics object for use inside an already
+ * existing document.
+ *
+ * @param textAsShapes if true then draw text as shapes
+ * @param fi the current font information
+ * @param doc the pdf document for creating pdf objects
+ * @param page the current resource context or page
+ * @param pref the PDF reference of the current page
+ * @param font the current font name
+ * @param size the current font size
+ */
+ public PDFGraphics2D(boolean textAsShapes, FontInfo fi, PDFDocument doc,
+ PDFResourceContext page, String pref, String font, float size) {
+ super(textAsShapes);
+ pdfDoc = doc;
+ resourceContext = page;
+ currentFontName = font;
+ currentFontSize = size;
+ fontInfo = fi;
+ pageRef = pref;
+ graphicsState = new PDFState();
+ }
+
+ /**
+ * Create a new PDFGraphics2D.
+ *
+ * @param textAsShapes true if drawing text as shapes
+ */
+ protected PDFGraphics2D(boolean textAsShapes) {
+ super(textAsShapes);
+ }
+
+ /**
+ * Set the PDF state to use when starting to draw
+ * into the PDF graphics.
+ *
+ * @param state the PDF state
+ */
+ public void setPDFState(PDFState state) {
+ graphicsState = state;
+ baseLevel = graphicsState.getStackLevel();
+ }
+
+ /**
+ * Set the output stream that this PDF document is
+ * being drawn to. This is so that it can progressively
+ * use the PDF document to output data such as images.
+ * This results in a significant saving on memory.
+ *
+ * @param os the output stream that is being used for the PDF document
+ */
+ public void setOutputStream(OutputStream os) {
+ outputStream = os;
+ }
+
+ /**
+ * Get the string containing all the commands written into this
+ * Grpahics.
+ * @return the string containing the PDF markup
+ */
+ public String getString() {
+ return currentStream.toString();
+ }
+
+ /**
+ * Set the Grpahics context.
+ * @param c the graphics context to use
+ */
+ public void setGraphicContext(GraphicContext c) {
+ gc = c;
+ }
+
+ /**
+ * Set the override font state for drawing text.
+ * This is used by the PDF text painter so that it can temporarily
+ * set the font state when a java font cannot be used.
+ * The next drawString will use this font state.
+ *
+ * @param infont the font state to use
+ */
+ public void setOverrideFontState(FontState infont) {
+ ovFontState = infont;
+ }
+
+ /**
+ * This constructor supports the create method.
+ * This is not implemented properly.
+ *
+ * @param g the PDF graphics to make a copy of
+ */
+ public PDFGraphics2D(PDFGraphics2D g) {
+ super(g);
+ }
+
+ /**
+ * Creates a new <code>Graphics</code> object that is
+ * a copy of this <code>Graphics</code> object.
+ * @return a new graphics context that is a copy of
+ * this graphics context.
+ */
+ public Graphics create() {
+ return new PDFGraphics2D(this);
+ }
+
+ /**
+ * Restore the PDF graphics state to the starting state level.
+ */
+ public void restorePDFState() {
+ for (int count = graphicsState.getStackLevel(); count > baseLevel; count--) {
+ currentStream.write("Q\n");
+ }
+ graphicsState.restoreLevel(baseLevel);
+ }
+
+ /**
+ * This is a pdf specific method used to add a link to the
+ * pdf document.
+ *
+ * @param bounds the bounds of the link in user coordinates
+ * @param trans the transform of the current drawing position
+ * @param dest the PDF destination
+ * @param linkType the type of link, internal or external
+ */
+ public void addLink(Rectangle2D bounds, AffineTransform trans, String dest, int linkType) {
+ AffineTransform at = getTransform();
+ Shape b = at.createTransformedShape(bounds);
+ b = trans.createTransformedShape(b);
+ Rectangle rect = b.getBounds();
+
+ if (linkType != PDFLink.EXTERNAL) {
+ String pdfdest = "/FitR " + dest;
+ resourceContext.addAnnotation(pdfDoc.makeLink(rect, pageRef, pdfdest));
+ } else {
+ resourceContext.addAnnotation(pdfDoc.makeLink(rect,
+ dest, linkType, 0));
+ }
+ }
+
+ /**
+ * Add a JPEG image directly to the PDF document.
+ * This is used by the PDFImageElementBridge to draw a JPEG
+ * directly into the pdf document rather than converting the image into
+ * a bitmap and increasing the size.
+ *
+ * @param jpeg the jpeg image to draw
+ * @param x the x position
+ * @param y the y position
+ * @param width the width to draw the image
+ * @param height the height to draw the image
+ */
+ public void addJpegImage(JpegImage jpeg, float x, float y, float width, float height) {
+ FopPDFImage fopimage = new FopPDFImage(jpeg, "");
+ int xObjectNum = this.pdfDoc.addImage(resourceContext, fopimage).getXNumber();
+
+ AffineTransform at = getTransform();
+ double[] matrix = new double[6];
+ at.getMatrix(matrix);
+ currentStream.write("q\n");
+ Shape imclip = getClip();
+ writeClip(imclip);
+ if (!at.isIdentity()) {
+ currentStream.write("" + matrix[0] + " " + matrix[1] + " "
+ + matrix[2] + " " + matrix[3] + " "
+ + matrix[4] + " " + matrix[5] + " cm\n");
+ }
+
+ currentStream.write("" + width + " 0 0 "
+ + (-height) + " "
+ + x + " "
+ + (y + height) + " cm\n" + "/Im"
+ + xObjectNum + " Do\nQ\n");
+
+ if (outputStream != null) {
+ try {
+ this.pdfDoc.output(outputStream);
+ } catch (IOException ioe) {
+ // ignore exception, will be thrown again later
+ }
+ }
+ }
+
+ /**
+ * Draws as much of the specified image as is currently available.
+ * The image is drawn with its top-left corner at
+ * (<i>x</i>,&nbsp;<i>y</i>) in this graphics context's coordinate
+ * space. Transparent pixels in the image do not affect whatever
+ * pixels are already there.
+ * <p>
+ * This method returns immediately in all cases, even if the
+ * complete image has not yet been loaded, and it has not been dithered
+ * and converted for the current output device.
+ * <p>
+ * If the image has not yet been completely loaded, then
+ * <code>drawImage</code> returns <code>false</code>. As more of
+ * the image becomes available, the process that draws the image notifies
+ * the specified image observer.
+ * @param img the specified image to be drawn.
+ * @param x the <i>x</i> coordinate.
+ * @param y the <i>y</i> coordinate.
+ * @param observer object to be notified as more of
+ * the image is converted.
+ * @return true if the image was drawn
+ * @see java.awt.Image
+ * @see java.awt.image.ImageObserver
+ * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
+ */
+ public boolean drawImage(Image img, int x, int y,
+ ImageObserver observer) {
+ // System.err.println("drawImage:x, y");
+
+ int width = img.getWidth(observer);
+ int height = img.getHeight(observer);
+
+ if (width == -1 || height == -1) {
+ return false;
+ }
+
+ // first we look to see if we've already added this image to
+ // the pdf document. If so, we just reuse the reference;
+ // otherwise we have to build a FopImage and add it to the pdf
+ // document
+ PDFXObject imageInfo = pdfDoc.getImage("TempImage:" + img.toString());
+ if (imageInfo == null) {
+ // OK, have to build and add a PDF image
+
+ // scale factor
+ final int scaleFactor = 3;
+
+ Dimension size = new Dimension(width * scaleFactor, height * scaleFactor);
+ BufferedImage buf = buildBufferedImage(size);
+
+ java.awt.Graphics2D g = buf.createGraphics();
+ g.setComposite(AlphaComposite.SrcOver);
+ g.setBackground(new Color(1, 1, 1, 0));
+ g.setPaint(new Color(1, 1, 1, 0));
+ g.fillRect(0, 0, width * scaleFactor, height * scaleFactor);
+ g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight()));
+
+ if (!g.drawImage(img, 0, 0, buf.getWidth(), buf.getHeight(), observer)) {
+ return false;
+ }
+ g.dispose();
+
+ final byte[] result = new byte[buf.getWidth() * buf.getHeight() * 3];
+ byte[] mask = new byte[buf.getWidth() * buf.getHeight()];
+ boolean hasMask = false;
+ //boolean binaryMask = true;
+
+ Raster raster = buf.getData();
+ DataBuffer bd = raster.getDataBuffer();
+
+ int count = 0;
+ int maskpos = 0;
+ int[] iarray;
+ int i, j, val, alpha, add, mult;
+ switch (bd.getDataType()) {
+ case DataBuffer.TYPE_INT:
+ int[][] idata = ((DataBufferInt)bd).getBankData();
+ for (i = 0; i < idata.length; i++) {
+ iarray = idata[i];
+ for (j = 0; j < iarray.length; j++) {
+ val = iarray[j];
+ alpha = val >>> 24;
+ mask[maskpos++] = (byte)(alpha & 0xFF);
+ if (alpha != 255) {
+ hasMask = true;
+ /*
+ if (alpha != 0) {
+ binaryMask = false;
+ }*/
+
+ // System.out.println("Alpha: " + alpha);
+ // Composite with opaque white...
+ add = (255 - alpha);
+ mult = (alpha << 16) / 255;
+ result[count++] =
+ (byte)(add
+ + ((((val >> 16) & 0xFF) * mult) >> 16));
+ result[count++] =
+ (byte)(add
+ + ((((val >> 8) & 0xFF) * mult) >> 16));
+ result[count++] = (byte)(add
+ + ((((val) & 0xFF) * mult)
+ >> 16));
+ } else {
+ result[count++] = (byte)((val >> 16) & 0xFF);
+ result[count++] = (byte)((val >> 8) & 0xFF);
+ result[count++] = (byte)((val) & 0xFF);
+ }
+ }
+ }
+ break;
+ default:
+ // error
+ break;
+ }
+ String ref = null;
+ if (hasMask) {
+ // if the mask is binary then we could convert it into a bitmask
+ BitmapImage fopimg = new BitmapImage("TempImageMask:"
+ + img.toString(), buf.getWidth(),
+ buf.getHeight(), mask, null);
+ fopimg.setColorSpace(new PDFColorSpace(PDFColorSpace.DEVICE_GRAY));
+ PDFXObject xobj = pdfDoc.addImage(resourceContext, fopimg);
+ ref = xobj.referencePDF();
+
+ if (outputStream != null) {
+ try {
+ this.pdfDoc.output(outputStream);
+ } catch (IOException ioe) {
+ // ignore exception, will be thrown again later
+ }
+ }
+ } else {
+ mask = null;
+ }
+
+ BitmapImage fopimg = new BitmapImage("TempImage:"
+ + img.toString(), buf.getWidth(),
+ buf.getHeight(), result, ref);
+ fopimg.setTransparent(new PDFColor(255, 255, 255));
+ imageInfo = pdfDoc.addImage(resourceContext, fopimg);
+ //int xObjectNum = imageInfo.getXNumber();
+
+ if (outputStream != null) {
+ try {
+ this.pdfDoc.output(outputStream);
+ } catch (IOException ioe) {
+ // ignore exception, will be thrown again later
+ }
+ }
+ } else {
+ resourceContext.getPDFResources().addXObject(imageInfo);
+ }
+
+ // now do any transformation required and add the actual image
+ // placement instance
+ AffineTransform at = getTransform();
+ double[] matrix = new double[6];
+ at.getMatrix(matrix);
+ currentStream.write("q\n");
+ Shape imclip = getClip();
+ writeClip(imclip);
+ if (!at.isIdentity()) {
+ currentStream.write("" + matrix[0] + " " + matrix[1] + " "
+ + matrix[2] + " " + matrix[3] + " "
+ + matrix[4] + " " + matrix[5] + " cm\n");
+ }
+ currentStream.write("" + width + " 0 0 " + (-height) + " " + x
+ + " " + (y + height) + " cm\n" + "/Im"
+ + imageInfo.getXNumber() + " Do\nQ\n");
+ return true;
+ }
+
+ private BufferedImage buildBufferedImage(Dimension size) {
+ return new BufferedImage(size.width, size.height,
+ BufferedImage.TYPE_INT_ARGB);
+ }
+
+ /**
+ * Draws as much of the specified image as has already been scaled
+ * to fit inside the specified rectangle.
+ * <p>
+ * The image is drawn inside the specified rectangle of this
+ * graphics context's coordinate space, and is scaled if
+ * necessary. Transparent pixels do not affect whatever pixels
+ * are already there.
+ * <p>
+ * This method returns immediately in all cases, even if the
+ * entire image has not yet been scaled, dithered, and converted
+ * for the current output device.
+ * If the current output representation is not yet complete, then
+ * <code>drawImage</code> returns <code>false</code>. As more of
+ * the image becomes available, the process that draws the image notifies
+ * the image observer by calling its <code>imageUpdate</code> method.
+ * <p>
+ * A scaled version of an image will not necessarily be
+ * available immediately just because an unscaled version of the
+ * image has been constructed for this output device. Each size of
+ * the image may be cached separately and generated from the original
+ * data in a separate image production sequence.
+ * @param img the specified image to be drawn.
+ * @param x the <i>x</i> coordinate.
+ * @param y the <i>y</i> coordinate.
+ * @param width the width of the rectangle.
+ * @param height the height of the rectangle.
+ * @param observer object to be notified as more of
+ * the image is converted.
+ * @return true if the image was drawn
+ * @see java.awt.Image
+ * @see java.awt.image.ImageObserver
+ * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
+ */
+ public boolean drawImage(Image img, int x, int y, int width, int height,
+ ImageObserver observer) {
+ System.out.println("drawImage");
+ return true;
+ }
+
+ /**
+ * Disposes of this graphics context and releases
+ * any system resources that it is using.
+ * A <code>Graphics</code> object cannot be used after
+ * <code>dispose</code>has been called.
+ * <p>
+ * When a Java program runs, a large number of <code>Graphics</code>
+ * objects can be created within a short time frame.
+ * Although the finalization process of the garbage collector
+ * also disposes of the same system resources, it is preferable
+ * to manually free the associated resources by calling this
+ * method rather than to rely on a finalization process which
+ * may not run to completion for a long period of time.
+ * <p>
+ * Graphics objects which are provided as arguments to the
+ * <code>paint</code> and <code>update</code> methods
+ * of components are automatically released by the system when
+ * those methods return. For efficiency, programmers should
+ * call <code>dispose</code> when finished using
+ * a <code>Graphics</code> object only if it was created
+ * directly from a component or another <code>Graphics</code> object.
+ * @see java.awt.Graphics#finalize
+ * @see java.awt.Component#paint
+ * @see java.awt.Component#update
+ * @see java.awt.Component#getGraphics
+ * @see java.awt.Graphics#create
+ */
+ public void dispose() {
+ // System.out.println("dispose");
+ pdfDoc = null;
+ fontInfo = null;
+ currentStream = null;
+ currentFontName = null;
+ }
+
+ /**
+ * Strokes the outline of a <code>Shape</code> using the settings of the
+ * current <code>Graphics2D</code> context. The rendering attributes
+ * applied include the <code>Clip</code>, <code>Transform</code>,
+ * <code>Paint</code>, <code>Composite</code> and
+ * <code>Stroke</code> attributes.
+ * @param s the <code>Shape</code> to be rendered
+ * @see #setStroke
+ * @see #setPaint
+ * @see java.awt.Graphics#setColor
+ * @see #transform
+ * @see #setTransform
+ * @see #clip
+ * @see #setClip
+ * @see #setComposite
+ */
+ public void draw(Shape s) {
+ // System.out.println("draw(Shape)");
+ Color c;
+ c = getColor();
+ if (c.getAlpha() == 0) {
+ return;
+ }
+
+ AffineTransform trans = getTransform();
+ double[] tranvals = new double[6];
+ trans.getMatrix(tranvals);
+
+ Shape imclip = getClip();
+ boolean newClip = graphicsState.checkClip(imclip);
+ boolean newTransform = graphicsState.checkTransform(trans)
+ && !trans.isIdentity();
+
+ if (newClip || newTransform) {
+ currentStream.write("q\n");
+ graphicsState.push();
+ if (newClip) {
+ writeClip(imclip);
+ }
+ if (newTransform) {
+ currentStream.write(PDFNumber.doubleOut(tranvals[0], 5) + " "
+ + PDFNumber.doubleOut(tranvals[1], 5) + " "
+ + PDFNumber.doubleOut(tranvals[2], 5) + " "
+ + PDFNumber.doubleOut(tranvals[3], 5) + " "
+ + PDFNumber.doubleOut(tranvals[4], 5) + " "
+ + PDFNumber.doubleOut(tranvals[5], 5) + " cm\n");
+ }
+ }
+
+ if (c.getAlpha() != 255) {
+ Map vals = new java.util.HashMap();
+ vals.put(PDFGState.GSTATE_ALPHA_STROKE, new Float(c.getAlpha() / 255f));
+ PDFGState gstate = pdfDoc.makeGState(vals, graphicsState.getGState());
+ //gstate.setAlpha(c.getAlpha() / 255f, false);
+ resourceContext.addGState(gstate);
+ currentStream.write("/" + gstate.getName() + " gs\n");
+ }
+
+ applyColor(c, false);
+
+ applyPaint(getPaint(), false);
+ applyStroke(getStroke());
+
+ PathIterator iter = s.getPathIterator(new AffineTransform());
+ while (!iter.isDone()) {
+ double vals[] = new double[6];
+ int type = iter.currentSegment(vals);
+ switch (type) {
+ case PathIterator.SEG_CUBICTO:
+ currentStream.write(PDFNumber.doubleOut(vals[0], 5) + " "
+ + PDFNumber.doubleOut(vals[1], 5) + " "
+ + PDFNumber.doubleOut(vals[2], 5) + " "
+ + PDFNumber.doubleOut(vals[3], 5) + " "
+ + PDFNumber.doubleOut(vals[4], 5) + " "
+ + PDFNumber.doubleOut(vals[5], 5) + " c\n");
+ break;
+ case PathIterator.SEG_LINETO:
+ currentStream.write(PDFNumber.doubleOut(vals[0], 5) + " "
+ + PDFNumber.doubleOut(vals[1], 5) + " l\n");
+ break;
+ case PathIterator.SEG_MOVETO:
+ currentStream.write(PDFNumber.doubleOut(vals[0], 5) + " "
+ + PDFNumber.doubleOut(vals[1], 5) + " m\n");
+ break;
+ case PathIterator.SEG_QUADTO:
+ currentStream.write(PDFNumber.doubleOut(vals[0], 5) + " "
+ + PDFNumber.doubleOut(vals[1], 5) + " "
+ + PDFNumber.doubleOut(vals[2], 5) + " "
+ + PDFNumber.doubleOut(vals[3], 5) + " y\n");
+ break;
+ case PathIterator.SEG_CLOSE:
+ currentStream.write("h\n");
+ break;
+ default:
+ break;
+ }
+ iter.next();
+ }
+ doDrawing(false, true, false);
+ if (newClip || newTransform) {
+ currentStream.write("Q\n");
+ graphicsState.pop();
+ }
+ }
+
+/*
+ // in theory we could set the clip using these methods
+ // it doesn't seem to improve the file sizes much
+ // and makes everything more complicated
+
+ Shape lastClip = null;
+
+ public void clip(Shape cl) {
+ super.clip(cl);
+ Shape newClip = getClip();
+ if (newClip == null || lastClip == null
+ || !(new Area(newClip).equals(new Area(lastClip)))) {
+ graphicsState.setClip(newClip);
+ writeClip(newClip);
+ }
+
+ lastClip = newClip;
+ }
+
+ public void setClip(Shape cl) {
+ super.setClip(cl);
+ Shape newClip = getClip();
+ if (newClip == null || lastClip == null
+ || !(new Area(newClip).equals(new Area(lastClip)))) {
+ for (int count = graphicsState.getStackLevel(); count > baseLevel; count--) {
+ currentStream.write("Q\n");
+ }
+ graphicsState.restoreLevel(baseLevel);
+ currentStream.write("q\n");
+ graphicsState.push();
+ if (newClip != null) {
+ graphicsState.setClip(newClip);
+ }
+ writeClip(newClip);
+ }
+
+ lastClip = newClip;
+ }
+*/
+
+ /**
+ * Set the clipping shape for future PDF drawing in the current graphics state.
+ * This sets creates and writes a clipping shape that will apply
+ * to future drawings in the current graphics state.
+ *
+ * @param s the clipping shape
+ */
+ protected void writeClip(Shape s) {
+ if (s == null) {
+ return;
+ }
+ PathIterator iter = s.getPathIterator(getTransform());
+ while (!iter.isDone()) {
+ double vals[] = new double[6];
+ int type = iter.currentSegment(vals);
+ switch (type) {
+ case PathIterator.SEG_CUBICTO:
+ currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
+ + PDFNumber.doubleOut(vals[1]) + " "
+ + PDFNumber.doubleOut(vals[2]) + " "
+ + PDFNumber.doubleOut(vals[3]) + " "
+ + PDFNumber.doubleOut(vals[4]) + " "
+ + PDFNumber.doubleOut(vals[5]) + " c\n");
+ break;
+ case PathIterator.SEG_LINETO:
+ currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
+ + PDFNumber.doubleOut(vals[1]) + " l\n");
+ break;
+ case PathIterator.SEG_MOVETO:
+ currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
+ + PDFNumber.doubleOut(vals[1]) + " m\n");
+ break;
+ case PathIterator.SEG_QUADTO:
+ currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
+ + PDFNumber.doubleOut(vals[1]) + " "
+ + PDFNumber.doubleOut(vals[2]) + " "
+ + PDFNumber.doubleOut(vals[3]) + " y\n");
+ break;
+ case PathIterator.SEG_CLOSE:
+ currentStream.write("h\n");
+ break;
+ default:
+ break;
+ }
+ iter.next();
+ }
+ // clip area
+ currentStream.write("W\n");
+ currentStream.write("n\n");
+ }
+
+ /**
+ * Apply the java Color to PDF.
+ * This converts the java colour to a PDF colour and
+ * sets it for the next drawing.
+ *
+ * @param col the java colour
+ * @param fill true if the colour will be used for filling
+ */
+ protected void applyColor(Color col, boolean fill) {
+ Color c = col;
+ if (c.getColorSpace().getType()
+ == ColorSpace.TYPE_RGB) {
+ PDFColor currentColour = new PDFColor(c.getRed(), c.getGreen(),
+ c.getBlue());
+ currentStream.write(currentColour.getColorSpaceOut(fill));
+ } else if (c.getColorSpace().getType()
+ == ColorSpace.TYPE_CMYK) {
+ float[] cComps = c.getColorComponents(new float[3]);
+ double[] cmyk = new double[3];
+ for (int i = 0; i < 3; i++) {
+ // convert the float elements to doubles for pdf
+ cmyk[i] = cComps[i];
+ }
+ PDFColor currentColour = new PDFColor(cmyk[0], cmyk[1], cmyk[2], cmyk[3]);
+ currentStream.write(currentColour.getColorSpaceOut(fill));
+ } else if (c.getColorSpace().getType()
+ == ColorSpace.TYPE_2CLR) {
+ // used for black/magenta
+ float[] cComps = c.getColorComponents(new float[1]);
+ double[] blackMagenta = new double[1];
+ for (int i = 0; i < 1; i++) {
+ blackMagenta[i] = cComps[i];
+ }
+ //PDFColor currentColour = new PDFColor(blackMagenta[0], blackMagenta[1]);
+ //currentStream.write(currentColour.getColorSpaceOut(fill));
+ } else {
+ System.err.println("Color Space not supported by PDFGraphics2D");
+ }
+ }
+
+ /**
+ * Apply the java paint to the PDF.
+ * This takes the java paint sets up the appropraite PDF commands
+ * for the drawing with that paint.
+ * Currently this supports the gradients and patterns from batik.
+ *
+ * @param paint the paint to convert to PDF
+ * @param fill true if the paint should be set for filling
+ */
+ protected void applyPaint(Paint paint, boolean fill) {
+
+ if (paint instanceof LinearGradientPaint) {
+ LinearGradientPaint gp = (LinearGradientPaint)paint;
+ Color[] cols = gp.getColors();
+ float[] fractions = gp.getFractions();
+ Point2D p1 = gp.getStartPoint();
+ Point2D p2 = gp.getEndPoint();
+ //MultipleGradientPaint.CycleMethodEnum cycenum = gp.getCycleMethod();
+ //boolean cyclic = (cycenum == MultipleGradientPaint.REPEAT);
+ AffineTransform transform = graphicsState.getTransform();
+ transform.concatenate(gp.getTransform());
+
+ p1 = transform.transform(p1, null);
+ p2 = transform.transform(p2, null);
+
+ List theCoords = new java.util.ArrayList();
+ theCoords.add(new Double(p1.getX()));
+ theCoords.add(new Double(p1.getY()));
+ theCoords.add(new Double(p2.getX()));
+ theCoords.add(new Double(p2.getY()));
+
+ List theExtend = new java.util.ArrayList();
+ theExtend.add(new Boolean(true));
+ theExtend.add(new Boolean(true));
+
+ List theDomain = new java.util.ArrayList();
+ theDomain.add(new Double(0));
+ theDomain.add(new Double(1));
+
+ List theEncode = new java.util.ArrayList();
+ theEncode.add(new Double(0));
+ theEncode.add(new Double(1));
+ theEncode.add(new Double(0));
+ theEncode.add(new Double(1));
+
+ List theBounds = new java.util.ArrayList();
+
+ List someColors = new java.util.ArrayList();
+
+ for (int count = 0; count < cols.length; count++) {
+ Color c1 = cols[count];
+ PDFColor color1 = new PDFColor(c1.getRed(), c1.getGreen(),
+ c1.getBlue());
+ someColors.add(color1);
+ if (count > 0 && count < cols.length - 1) {
+ theBounds.add(new Double(fractions[count]));
+ }
+ }
+
+ PDFColorSpace aColorSpace = new PDFColorSpace(PDFColorSpace.DEVICE_RGB);
+ PDFPattern myPat = pdfDoc.createGradient(resourceContext, false, aColorSpace,
+ someColors, theBounds, theCoords);
+ currentStream.write(myPat.getColorSpaceOut(fill));
+
+ } else if (paint instanceof RadialGradientPaint) {
+ RadialGradientPaint rgp = (RadialGradientPaint)paint;
+
+ double ar = rgp.getRadius();
+ Point2D ac = rgp.getCenterPoint();
+ Point2D af = rgp.getFocusPoint();
+ AffineTransform transform = graphicsState.getTransform();
+ AffineTransform gradt = rgp.getTransform();
+ transform.concatenate(gradt);
+
+ // find largest scaling for the radius
+ double scale = gradt.getScaleX();
+ if (gradt.getScaleY() > scale) {
+ scale = gradt.getScaleY();
+ }
+ ar = ar * scale;
+ ac = transform.transform(ac, null);
+ af = transform.transform(af, null);
+
+ List theCoords = new java.util.ArrayList();
+ // the center point af must be within the circle with
+ // radius ar centered at ac
+ theCoords.add(new Double(af.getX()));
+ theCoords.add(new Double(af.getY()));
+ theCoords.add(new Double(0));
+ theCoords.add(new Double(ac.getX())); // Fx
+ theCoords.add(new Double(ac.getY())); // Fy
+ theCoords.add(new Double(ar));
+
+ Color[] cols = rgp.getColors();
+ List someColors = new java.util.ArrayList();
+ for (int count = 0; count < cols.length; count++) {
+ Color cc = cols[count];
+ someColors.add(new PDFColor(cc.getRed(), cc.getGreen(), cc.getBlue()));
+ }
+
+ float[] fractions = rgp.getFractions();
+ List theBounds = new java.util.ArrayList();
+ for (int count = 1; count < fractions.length - 1; count++) {
+ float offset = fractions[count];
+ theBounds.add(new Double(offset));
+ }
+ PDFColorSpace colSpace = new PDFColorSpace(PDFColorSpace.DEVICE_RGB);
+ PDFPattern myPat = pdfDoc.createGradient(resourceContext, true, colSpace,
+ someColors, theBounds, theCoords);
+
+ currentStream.write(myPat.getColorSpaceOut(fill));
+
+ } else if (paint instanceof PatternPaint) {
+ PatternPaint pp = (PatternPaint)paint;
+ createPattern(pp, fill);
+ }
+ }
+
+ private void createPattern(PatternPaint pp, boolean fill) {
+ Rectangle2D rect = pp.getPatternRect();
+
+ FontInfo fi = new FontInfo();
+ FontSetup.setup(fi, null);
+
+ PDFResources res = pdfDoc.makeResources();
+ PDFResourceContext context = new PDFResourceContext(0, pdfDoc, res);
+ PDFGraphics2D pattGraphic = new PDFGraphics2D(textAsShapes, fi,
+ pdfDoc, context, pageRef,
+ "", 0);
+ pattGraphic.gc = (GraphicContext)this.gc.clone();
+ pattGraphic.gc.validateTransformStack();
+ pattGraphic.setOutputStream(outputStream);
+
+ GraphicsNode gn = pp.getGraphicsNode();
+ gn.paint(pattGraphic);
+
+ StringWriter pattStream = new StringWriter();
+ pattStream.write("q\n");
+
+ // this makes the pattern the right way up, since
+ // it is outside the original transform around the
+ // whole svg document
+ pattStream.write("1 0 0 -1 0 " + (rect.getHeight() + rect.getY()) + " cm\n");
+
+ pattStream.write(pattGraphic.getString());
+ pattStream.write("Q");
+
+ List bbox = new java.util.ArrayList();
+ bbox.add(new Double(0));
+ bbox.add(new Double(0));
+ bbox.add(new Double(rect.getWidth() + rect.getX()));
+ bbox.add(new Double(rect.getHeight() + rect.getY()));
+
+ List translate = new java.util.ArrayList();
+ AffineTransform pattt = pp.getPatternTransform();
+ pattt.translate(rect.getWidth() + rect.getX(), rect.getHeight() + rect.getY());
+ double[] flatmatrix = new double[6];
+ pattt.getMatrix(flatmatrix);
+ translate.add(new Double(flatmatrix[0]));
+ translate.add(new Double(flatmatrix[1]));
+ translate.add(new Double(flatmatrix[2]));
+ translate.add(new Double(flatmatrix[3]));
+ translate.add(new Double(flatmatrix[4]));
+ translate.add(new Double(flatmatrix[5]));
+
+ FontSetup.addToResources(pdfDoc, res, fi);
+
+ PDFPattern myPat = pdfDoc.makePattern(resourceContext, 1, res, 1, 1, bbox,
+ rect.getWidth(), rect.getHeight(),
+ translate, null, pattStream.getBuffer());
+
+ currentStream.write(myPat.getColorSpaceOut(fill));
+
+ PDFAnnotList annots = context.getAnnotations();
+ if (annots != null) {
+ this.pdfDoc.addAnnotList(annots);
+ }
+
+ if (outputStream != null) {
+ try {
+ this.pdfDoc.output(outputStream);
+ } catch (IOException ioe) {
+ // ignore exception, will be thrown again later
+ }
+ }
+ }
+
+ /**
+ * Apply the stroke to the PDF.
+ * This takes the java stroke and outputs the appropriate settings
+ * to the PDF so that the stroke attributes are handled.
+ *
+ * @param stroke the java stroke
+ */
+ protected void applyStroke(Stroke stroke) {
+ if (stroke instanceof BasicStroke) {
+ BasicStroke bs = (BasicStroke)stroke;
+
+ float[] da = bs.getDashArray();
+ if (da != null) {
+ currentStream.write("[");
+ for (int count = 0; count < da.length; count++) {
+ if (((int)da[count]) == 0) {
+ // the dasharray units in pdf are (whole) numbers
+ // in user space units, cannot be 0
+ currentStream.write("1");
+ } else {
+ currentStream.write("" + ((int)da[count]));
+ }
+ if (count < da.length - 1) {
+ currentStream.write(" ");
+ }
+ }
+ currentStream.write("] ");
+ float offset = bs.getDashPhase();
+ currentStream.write(((int)offset) + " d\n");
+ }
+ int ec = bs.getEndCap();
+ switch (ec) {
+ case BasicStroke.CAP_BUTT:
+ currentStream.write(0 + " J\n");
+ break;
+ case BasicStroke.CAP_ROUND:
+ currentStream.write(1 + " J\n");
+ break;
+ case BasicStroke.CAP_SQUARE:
+ currentStream.write(2 + " J\n");
+ break;
+ }
+
+ int lj = bs.getLineJoin();
+ switch (lj) {
+ case BasicStroke.JOIN_MITER:
+ currentStream.write(0 + " j\n");
+ break;
+ case BasicStroke.JOIN_ROUND:
+ currentStream.write(1 + " j\n");
+ break;
+ case BasicStroke.JOIN_BEVEL:
+ currentStream.write(2 + " j\n");
+ break;
+ }
+ float lw = bs.getLineWidth();
+ currentStream.write(PDFNumber.doubleOut(lw) + " w\n");
+
+ float ml = bs.getMiterLimit();
+ currentStream.write(PDFNumber.doubleOut(ml) + " M\n");
+ }
+ }
+
+ /**
+ * Renders a {@link RenderedImage},
+ * applying a transform from image
+ * space into user space before drawing.
+ * The transformation from user space into device space is done with
+ * the current <code>Transform</code> in the <code>Graphics2D</code>.
+ * The specified transformation is applied to the image before the
+ * transform attribute in the <code>Graphics2D</code> context is applied.
+ * The rendering attributes applied include the <code>Clip</code>,
+ * <code>Transform</code>, and <code>Composite</code> attributes. Note
+ * that no rendering is done if the specified transform is
+ * noninvertible.
+ * @param img the image to be rendered
+ * @param xform the transformation from image space into user space
+ * @see #transform
+ * @see #setTransform
+ * @see #setComposite
+ * @see #clip
+ * @see #setClip
+ */
+ public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
+ System.out.println("drawRenderedImage");
+ }
+
+ /**
+ * Renders a
+ * {@link RenderableImage},
+ * applying a transform from image space into user space before drawing.
+ * The transformation from user space into device space is done with
+ * the current <code>Transform</code> in the <code>Graphics2D</code>.
+ * The specified transformation is applied to the image before the
+ * transform attribute in the <code>Graphics2D</code> context is applied.
+ * The rendering attributes applied include the <code>Clip</code>,
+ * <code>Transform</code>, and <code>Composite</code> attributes. Note
+ * that no rendering is done if the specified transform is
+ * noninvertible.
+ * <p>
+ * Rendering hints set on the <code>Graphics2D</code> object might
+ * be used in rendering the <code>RenderableImage</code>.
+ * If explicit control is required over specific hints recognized by a
+ * specific <code>RenderableImage</code>, or if knowledge of which hints
+ * are used is required, then a <code>RenderedImage</code> should be
+ * obtained directly from the <code>RenderableImage</code>
+ * and rendered using
+ * {@link #drawRenderedImage(RenderedImage, AffineTransform) drawRenderedImage}.
+ * @param img the image to be rendered
+ * @param xform the transformation from image space into user space
+ * @see #transform
+ * @see #setTransform
+ * @see #setComposite
+ * @see #clip
+ * @see #setClip
+ * @see #drawRenderedImage
+ */
+ public void drawRenderableImage(RenderableImage img,
+ AffineTransform xform) {
+ System.out.println("drawRenderableImage");
+ }
+
+ /**
+ * Renders the text specified by the specified <code>String</code>,
+ * using the current <code>Font</code> and <code>Paint</code> attributes
+ * in the <code>Graphics2D</code> context.
+ * The baseline of the first character is at position
+ * (<i>x</i>,&nbsp;<i>y</i>) in the User Space.
+ * The rendering attributes applied include the <code>Clip</code>,
+ * <code>Transform</code>, <code>Paint</code>, <code>Font</code> and
+ * <code>Composite</code> attributes. For characters in script systems
+ * such as Hebrew and Arabic, the glyphs can be rendered from right to
+ * left, in which case the coordinate supplied is the location of the
+ * leftmost character on the baseline.
+ * @param s the <code>String</code> to be rendered
+ * @param x the coordinate where the <code>String</code>
+ * should be rendered
+ * @param y the coordinate where the <code>String</code>
+ * should be rendered
+ * @see #setPaint
+ * @see java.awt.Graphics#setColor
+ * @see java.awt.Graphics#setFont
+ * @see #setTransform
+ * @see #setComposite
+ * @see #setClip
+ */
+ public void drawString(String s, float x, float y) {
+ // System.out.println("drawString(String)");
+
+ FontState fontState;
+ if (ovFontState == null) {
+ Font gFont = getFont();
+ String n = gFont.getFamily();
+ if (n.equals("sanserif")) {
+ n = "sans-serif";
+ }
+ int siz = gFont.getSize();
+ String style = gFont.isItalic() ? "italic" : "normal";
+ int weight = gFont.isBold() ? FontInfo.BOLD : FontInfo.NORMAL;
+ String fname = fontInfo.fontLookup(n, style, weight);
+ FontMetrics metrics = fontInfo.getMetricsFor(fname);
+ fontState = new FontState(fname, metrics, siz * 1000);
+ } else {
+ FontMetrics metrics = fontInfo.getMetricsFor(ovFontState.getFontName());
+ fontState = new FontState(ovFontState.getFontName(),
+ metrics, ovFontState.getFontSize());
+ ovFontState = null;
+ }
+ String name;
+ float size;
+ name = fontState.getFontName();
+ size = (float)fontState.getFontSize() / 1000f;
+
+ if ((!name.equals(this.currentFontName))
+ || (size != this.currentFontSize)) {
+ this.currentFontName = name;
+ this.currentFontSize = size;
+ currentStream.write("/" + name + " " + size + " Tf\n");
+
+ }
+
+ currentStream.write("q\n");
+
+ Shape imclip = getClip();
+ writeClip(imclip);
+ Color c = getColor();
+ applyColor(c, true);
+ int salpha = c.getAlpha();
+
+ if (salpha != 255) {
+ Map vals = new java.util.HashMap();
+ vals.put(PDFGState.GSTATE_ALPHA_NONSTROKE, new Float(salpha / 255f));
+ PDFGState gstate = pdfDoc.makeGState(vals, graphicsState.getGState());
+ resourceContext.addGState(gstate);
+ currentStream.write("/" + gstate.getName() + " gs\n");
+ }
+
+ currentStream.write("BT\n");
+
+ Map kerning = null;
+ boolean kerningAvailable = false;
+
+ kerning = fontState.getKerning();
+ if (kerning != null && !kerning.isEmpty()) {
+ kerningAvailable = true;
+ }
+
+ // This assumes that *all* CIDFonts use a /ToUnicode mapping
+ boolean useMultiByte = false;
+ org.apache.fop.fonts.Font f =
+ (org.apache.fop.fonts.Font)fontInfo.getFonts().get(name);
+ if (f instanceof LazyFont) {
+ if (((LazyFont) f).getRealFont() instanceof CIDFont) {
+ useMultiByte = true;
+ }
+ } else if (f instanceof CIDFont) {
+ useMultiByte = true;
+ }
+
+ // String startText = useMultiByte ? "<FEFF" : "(";
+ String startText = useMultiByte ? "<" : "(";
+ String endText = useMultiByte ? "> " : ") ";
+
+ AffineTransform trans = getTransform();
+ trans.translate(x, y);
+ double[] vals = new double[6];
+ trans.getMatrix(vals);
+
+ currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
+ + PDFNumber.doubleOut(vals[1]) + " "
+ + PDFNumber.doubleOut(vals[2]) + " "
+ + PDFNumber.doubleOut(vals[3]) + " "
+ + PDFNumber.doubleOut(vals[4]) + " "
+ + PDFNumber.doubleOut(vals[5]) + " cm\n");
+ currentStream.write("1 0 0 -1 0 0 Tm [" + startText);
+
+ int l = s.length();
+
+ for (int i = 0; i < l; i++) {
+ char ch = fontState.mapChar(s.charAt(i));
+
+ if (!useMultiByte) {
+ if (ch > 127) {
+ currentStream.write("\\");
+ currentStream.write(Integer.toOctalString((int)ch));
+ } else {
+ switch (ch) {
+ case '(':
+ case ')':
+ case '\\':
+ currentStream.write("\\");
+ break;
+ }
+ currentStream.write(ch);
+ }
+ } else {
+ currentStream.write(getUnicodeString(ch));
+ }
+
+ if (kerningAvailable && (i + 1) < l) {
+ addKerning(currentStream, (new Integer((int)ch)),
+ (new Integer((int)fontState.mapChar(s.charAt(i + 1)))),
+ kerning, startText, endText);
+ }
+
+ }
+ currentStream.write(endText);
+
+
+ currentStream.write("] TJ\n");
+
+ currentStream.write("ET\n");
+ currentStream.write("Q\n");
+ }
+
+ private void addKerning(StringWriter buf, Integer ch1, Integer ch2,
+ Map kerning, String startText,
+ String endText) {
+ Map kernPair = (Map)kerning.get(ch1);
+
+ if (kernPair != null) {
+ Integer width = (Integer)kernPair.get(ch2);
+ if (width != null) {
+ currentStream.write(endText + (-width.intValue()) + " " + startText);
+ }
+ }
+ }
+
+ /**
+ * Convert a char to a multibyte hex representation
+ */
+ private String getUnicodeString(char c) {
+
+ StringBuffer buf = new StringBuffer(4);
+ byte[] uniBytes = null;
+ try {
+ char[] a = {
+ c
+ };
+ uniBytes = new String(a).getBytes("UnicodeBigUnmarked");
+ } catch (Exception e) {
+ // This should never fail
+ }
+
+ for (int i = 0; i < uniBytes.length; i++) {
+ int b = (uniBytes[i] < 0) ? (int)(256 + uniBytes[i])
+ : (int)uniBytes[i];
+
+ String hexString = Integer.toHexString(b);
+ if (hexString.length() == 1) {
+ buf = buf.append("0" + hexString);
+ } else {
+ buf = buf.append(hexString);
+ }
+ }
+
+ return buf.toString();
+ }
+
+ /**
+ * Renders the text of the specified iterator, using the
+ * <code>Graphics2D</code> context's current <code>Paint</code>. The
+ * iterator must specify a font
+ * for each character. The baseline of the
+ * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in the
+ * User Space.
+ * The rendering attributes applied include the <code>Clip</code>,
+ * <code>Transform</code>, <code>Paint</code>, and
+ * <code>Composite</code> attributes.
+ * For characters in script systems such as Hebrew and Arabic,
+ * the glyphs can be rendered from right to left, in which case the
+ * coordinate supplied is the location of the leftmost character
+ * on the baseline.
+ * @param iterator the iterator whose text is to be rendered
+ * @param x the coordinate where the iterator's text is to be
+ * rendered
+ * @param y the coordinate where the iterator's text is to be
+ * rendered
+ * @see #setPaint
+ * @see java.awt.Graphics#setColor
+ * @see #setTransform
+ * @see #setComposite
+ * @see #setClip
+ */
+ public void drawString(AttributedCharacterIterator iterator, float x,
+ float y) {
+ System.err.println("drawString(AttributedCharacterIterator)");
+
+ FontState fontState = null;
+
+ Shape imclip = getClip();
+ writeClip(imclip);
+ Color c = getColor();
+ applyColor(c, true);
+
+ boolean fill = true;
+ boolean stroke = false;
+ if (true) {
+ Stroke currentStroke = getStroke();
+ stroke = true;
+ applyStroke(currentStroke);
+ applyColor(c, false);
+ }
+
+ currentStream.write("BT\n");
+
+ // set text rendering mode:
+ // 0 - fill, 1 - stroke, 2 - fill then stroke
+ int textr = 0;
+ if (fill && stroke) {
+ textr = 2;
+ } else if (stroke) {
+ textr = 1;
+ }
+ currentStream.write(textr + " Tr\n");
+
+ AffineTransform trans = getTransform();
+ trans.translate(x, y);
+ double[] vals = new double[6];
+ trans.getMatrix(vals);
+
+ for (char ch = iterator.first(); ch != CharacterIterator.DONE;
+ ch = iterator.next()) {
+ //Map attr = iterator.getAttributes();
+
+ String name = fontState.getFontName();
+ int size = fontState.getFontSize();
+ if ((!name.equals(this.currentFontName))
+ || (size != this.currentFontSize)) {
+ this.currentFontName = name;
+ this.currentFontSize = size;
+ currentStream.write("/" + name + " " + (size / 1000)
+ + " Tf\n");
+
+ }
+
+ currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
+ + PDFNumber.doubleOut(vals[1]) + " "
+ + PDFNumber.doubleOut(vals[2]) + " "
+ + PDFNumber.doubleOut(vals[3]) + " "
+ + PDFNumber.doubleOut(vals[4]) + " "
+ + PDFNumber.doubleOut(vals[5]) + " Tm (" + ch
+ + ") Tj\n");
+ }
+
+ currentStream.write("ET\n");
+ }
+
+ /**
+ * Fills the interior of a <code>Shape</code> using the settings of the
+ * <code>Graphics2D</code> context. The rendering attributes applied
+ * include the <code>Clip</code>, <code>Transform</code>,
+ * <code>Paint</code>, and <code>Composite</code>.
+ * @param s the <code>Shape</code> to be filled
+ * @see #setPaint
+ * @see java.awt.Graphics#setColor
+ * @see #transform
+ * @see #setTransform
+ * @see #setComposite
+ * @see #clip
+ * @see #setClip
+ */
+ public void fill(Shape s) {
+ // System.err.println("fill");
+ Color c;
+ c = getBackground();
+ if (c.getAlpha() == 0) {
+ c = getColor();
+ if (c.getAlpha() == 0) {
+ return;
+ }
+ }
+ Shape imclip = getClip();
+ boolean newState = graphicsState.checkClip(imclip);
+
+ if (newState) {
+ currentStream.write("q\n");
+ graphicsState.push();
+ writeClip(imclip);
+ graphicsState.setClip(imclip);
+ }
+
+ if (c.getAlpha() != 255) {
+ Map vals = new java.util.HashMap();
+ vals.put(PDFGState.GSTATE_ALPHA_NONSTROKE, new Float(c.getAlpha() / 255f));
+ PDFGState gstate = pdfDoc.makeGState(vals, graphicsState.getGState());
+ resourceContext.addGState(gstate);
+ currentStream.write("/" + gstate.getName() + " gs\n");
+ }
+
+ c = getColor();
+ if (graphicsState.setColor(c)) {
+ applyColor(c, true);
+ }
+ c = getBackground();
+ if (graphicsState.setBackColor(c)) {
+ applyColor(c, false);
+ }
+
+ Paint paint = getPaint();
+ if (graphicsState.setPaint(paint)) {
+ applyPaint(paint, true);
+ }
+
+ PathIterator iter = s.getPathIterator(getTransform());
+ while (!iter.isDone()) {
+ double vals[] = new double[6];
+ int type = iter.currentSegment(vals);
+ switch (type) {
+ case PathIterator.SEG_CUBICTO:
+ currentStream.write(PDFNumber.doubleOut(vals[0], 5) + " "
+ + PDFNumber.doubleOut(vals[1], 5) + " "
+ + PDFNumber.doubleOut(vals[2], 5) + " "
+ + PDFNumber.doubleOut(vals[3], 5) + " "
+ + PDFNumber.doubleOut(vals[4], 5) + " "
+ + PDFNumber.doubleOut(vals[5], 5) + " c\n");
+ break;
+ case PathIterator.SEG_LINETO:
+ currentStream.write(PDFNumber.doubleOut(vals[0], 5) + " "
+ + PDFNumber.doubleOut(vals[1], 5) + " l\n");
+ break;
+ case PathIterator.SEG_MOVETO:
+ currentStream.write(PDFNumber.doubleOut(vals[0], 5) + " "
+ + PDFNumber.doubleOut(vals[1], 5) + " m\n");
+ break;
+ case PathIterator.SEG_QUADTO:
+ currentStream.write(PDFNumber.doubleOut(vals[0], 5) + " "
+ + PDFNumber.doubleOut(vals[1], 5) + " "
+ + PDFNumber.doubleOut(vals[2], 5) + " "
+ + PDFNumber.doubleOut(vals[3], 5) + " y\n");
+ break;
+ case PathIterator.SEG_CLOSE:
+ currentStream.write("h\n");
+ break;
+ default:
+ break;
+ }
+ iter.next();
+ }
+ doDrawing(true, false,
+ iter.getWindingRule() == PathIterator.WIND_EVEN_ODD);
+ if (newState) {
+ currentStream.write("Q\n");
+ graphicsState.pop();
+ }
+ }
+
+ /**
+ * Do the PDF drawing command.
+ * This does the PDF drawing command according to fill
+ * stroke and winding rule.
+ *
+ * @param fill true if filling the path
+ * @param stroke true if stroking the path
+ * @param nonzero true if using the non-zero winding rule
+ */
+ protected void doDrawing(boolean fill, boolean stroke, boolean nonzero) {
+ if (fill) {
+ if (stroke) {
+ if (nonzero) {
+ currentStream.write("B*\n");
+ } else {
+ currentStream.write("B\n");
+ }
+ } else {
+ if (nonzero) {
+ currentStream.write("f*\n");
+ } else {
+ currentStream.write("f\n");
+ }
+ }
+ } else {
+ // if (stroke)
+ currentStream.write("S\n");
+ }
+ }
+
+ /**
+ * Returns the device configuration associated with this
+ * <code>Graphics2D</code>.
+ *
+ * @return the PDF graphics configuration
+ */
+ public GraphicsConfiguration getDeviceConfiguration() {
+ return new PDFGraphicsConfiguration();
+ }
+
+ /**
+ * Used to create proper font metrics
+ */
+ private Graphics2D fmg;
+
+ {
+ BufferedImage bi = new BufferedImage(1, 1,
+ BufferedImage.TYPE_INT_ARGB);
+
+ fmg = bi.createGraphics();
+ }
+
+ /**
+ * Gets the font metrics for the specified font.
+ * @return the font metrics for the specified font.
+ * @param f the specified font
+ * @see java.awt.Graphics#getFont
+ * @see java.awt.FontMetrics
+ * @see java.awt.Graphics#getFontMetrics()
+ */
+ public java.awt.FontMetrics getFontMetrics(Font f) {
+ return fmg.getFontMetrics(f);
+ }
+
+ /**
+ * Sets the paint mode of this graphics context to alternate between
+ * this graphics context's current color and the new specified color.
+ * This specifies that logical pixel operations are performed in the
+ * XOR mode, which alternates pixels between the current color and
+ * a specified XOR color.
+ * <p>
+ * When drawing operations are performed, pixels which are the
+ * current color are changed to the specified color, and vice versa.
+ * <p>
+ * Pixels that are of colors other than those two colors are changed
+ * in an unpredictable but reversible manner; if the same figure is
+ * drawn twice, then all pixels are restored to their original values.
+ * @param c1 the XOR alternation color
+ */
+ public void setXORMode(Color c1) {
+ System.out.println("setXORMode");
+ }
+
+
+ /**
+ * Copies an area of the component by a distance specified by
+ * <code>dx</code> and <code>dy</code>. From the point specified
+ * by <code>x</code> and <code>y</code>, this method
+ * copies downwards and to the right. To copy an area of the
+ * component to the left or upwards, specify a negative value for
+ * <code>dx</code> or <code>dy</code>.
+ * If a portion of the source rectangle lies outside the bounds
+ * of the component, or is obscured by another window or component,
+ * <code>copyArea</code> will be unable to copy the associated
+ * pixels. The area that is omitted can be refreshed by calling
+ * the component's <code>paint</code> method.
+ * @param x the <i>x</i> coordinate of the source rectangle.
+ * @param y the <i>y</i> coordinate of the source rectangle.
+ * @param width the width of the source rectangle.
+ * @param height the height of the source rectangle.
+ * @param dx the horizontal distance to copy the pixels.
+ * @param dy the vertical distance to copy the pixels.
+ */
+ public void copyArea(int x, int y, int width, int height, int dx,
+ int dy) {
+ System.out.println("copyArea");
+ }
+
+}
diff --git a/src/java/org/apache/fop/svg/PDFGraphicsConfiguration.javat b/src/java/org/apache/fop/svg/PDFGraphicsConfiguration.javat
new file mode 100644
index 000000000..8b24b18c3
--- /dev/null
+++ b/src/java/org/apache/fop/svg/PDFGraphicsConfiguration.javat
@@ -0,0 +1,178 @@
+/*
+ * $Id: PDFGraphicsConfiguration.javat,v 1.2 2003/03/07 09:51:25 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 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.svg;
+
+import java.awt.GraphicsConfiguration;
+import java.awt.Rectangle;
+import java.awt.GraphicsDevice;
+import java.awt.Transparency;
+import java.awt.image.ColorModel;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+
+/**
+ * Our implementation of the class that returns information about
+ * roughly what we can handle and want to see (alpha for example).
+ */
+class PDFGraphicsConfiguration extends GraphicsConfiguration {
+ // We use this to get a good colormodel..
+ private static final BufferedImage BI_WITH_ALPHA =
+ new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
+ // We use this to get a good colormodel..
+ private static final BufferedImage BI_WITHOUT_ALPHA =
+ new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
+
+ /**
+ * Construct a buffered image with an alpha channel, unless
+ * transparencty is OPAQUE (no alpha at all).
+ *
+ * @param width the width of the image
+ * @param height the height of the image
+ * @param transparency the alpha value of the image
+ * @return the new buffered image
+ */
+ public BufferedImage createCompatibleImage(int width, int height,
+ int transparency) {
+ if (transparency == Transparency.OPAQUE) {
+ return new BufferedImage(width, height,
+ BufferedImage.TYPE_INT_RGB);
+ } else {
+ return new BufferedImage(width, height,
+ BufferedImage.TYPE_INT_ARGB);
+ }
+ }
+
+ /**
+ * Construct a buffered image with an alpha channel.
+ *
+ * @param width the width of the image
+ * @param height the height of the image
+ * @return the new buffered image
+ */
+ public BufferedImage createCompatibleImage(int width, int height) {
+ return new BufferedImage(width, height,
+ BufferedImage.TYPE_INT_ARGB);
+ }
+
+ /**
+ * FIXX ME: This should return the page bounds in Pts,
+ * I couldn't figure out how to get this for the current
+ * page from the PDFDocument (this still works for now,
+ * but it should be fixed...).
+ *
+ * @return the bounds of the PDF document page
+ */
+ public Rectangle getBounds() {
+ System.out.println("getting getBounds");
+ return null;
+ }
+
+ /**
+ * Return a good default color model for this 'device'.
+ * @return the colour model for the configuration
+ */
+ public ColorModel getColorModel() {
+ return BI_WITH_ALPHA.getColorModel();
+ }
+
+ /**
+ * Return a good color model given <tt>transparency</tt>
+ *
+ * @param transparency the alpha value for the colour model
+ * @return the colour model for the configuration
+ */
+ public ColorModel getColorModel(int transparency) {
+ if (transparency == Transparency.OPAQUE) {
+ return BI_WITHOUT_ALPHA.getColorModel();
+ } else {
+ return BI_WITH_ALPHA.getColorModel();
+ }
+ }
+
+ /**
+ * The default transform (1:1).
+ *
+ * @return the default transform for the configuration
+ */
+ public AffineTransform getDefaultTransform() {
+ System.out.println("getting getDefaultTransform");
+ return new AffineTransform();
+ }
+
+ /**
+ * The normalizing transform (1:1) (since we currently
+ * render images at 72dpi, which we might want to change
+ * in the future).
+ *
+ * @return the normalizing transform for the configuration
+ */
+ public AffineTransform getNormalizingTransform() {
+ System.out.println("getting getNormalizingTransform");
+ return new AffineTransform(2, 0, 0, 2, 0, 0);
+ }
+
+ /**
+ * Return our dummy instance of GraphicsDevice
+ *
+ * @return the PDF graphics device
+ */
+ public GraphicsDevice getDevice() {
+ return new PDFGraphicsDevice(this);
+ }
+
+ // needed for compiling under jdk1.4
+ @jdk14codestart@
+ public java.awt.image.VolatileImage createCompatibleVolatileImage(int width, int height) {
+ return null;
+ }
+ @jdk14codeend@
+}
+
diff --git a/src/java/org/apache/fop/svg/PDFGraphicsDevice.java b/src/java/org/apache/fop/svg/PDFGraphicsDevice.java
new file mode 100644
index 000000000..6a2e337a6
--- /dev/null
+++ b/src/java/org/apache/fop/svg/PDFGraphicsDevice.java
@@ -0,0 +1,127 @@
+/*
+ * $Id: PDFGraphicsDevice.java,v 1.3 2003/03/07 09:51:25 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 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.svg;
+
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsConfigTemplate;
+
+/**
+ * This implements the GraphicsDevice interface as appropriate for
+ * a PDFGraphics2D. This is quite simple since we only have one
+ * GraphicsConfiguration for now (this might change in the future
+ * I suppose).
+ */
+class PDFGraphicsDevice extends GraphicsDevice {
+
+ /**
+ * The Graphics Config that created us...
+ */
+ protected GraphicsConfiguration gc;
+
+ /**
+ * Create a new PDF graphics device.
+ *
+ * @param The gc we should reference
+ */
+ PDFGraphicsDevice(PDFGraphicsConfiguration gc) {
+ this.gc = gc;
+ }
+
+ /**
+ * Ignore template and return the only config we have
+ *
+ * @param gct the template configuration
+ * @return the best configuration which is the only one
+ */
+ public GraphicsConfiguration getBestConfiguration(
+ GraphicsConfigTemplate gct) {
+ return gc;
+ }
+
+ /**
+ * Return an array of our one GraphicsConfig
+ *
+ * @return an array containing the one graphics configuration
+ */
+ public GraphicsConfiguration[] getConfigurations() {
+ return new GraphicsConfiguration[]{ gc };
+ }
+
+ /**
+ * Return out sole GraphicsConfig.
+ *
+ * @return the grpahics configuration that created this object
+ */
+ public GraphicsConfiguration getDefaultConfiguration() {
+ return gc;
+ }
+
+ /**
+ * Generate an IdString..
+ *
+ * @return the ID string for this device, uses toString
+ */
+ public String getIDstring() {
+ return toString();
+ }
+
+ /**
+ * Let the caller know that we are "a printer"
+ *
+ * @return the type which is always printer
+ */
+ public int getType() {
+ return GraphicsDevice.TYPE_PRINTER;
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/svg/PDFImageElementBridge.java b/src/java/org/apache/fop/svg/PDFImageElementBridge.java
new file mode 100644
index 000000000..b5222f657
--- /dev/null
+++ b/src/java/org/apache/fop/svg/PDFImageElementBridge.java
@@ -0,0 +1,181 @@
+/*
+ * $Id: PDFImageElementBridge.java,v 1.4 2003/03/07 09:51:25 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 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.svg;
+
+import org.apache.batik.bridge.SVGImageElementBridge;
+
+import org.apache.fop.image.JpegImage;
+
+import java.awt.Shape;
+import java.awt.Graphics2D;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.batik.gvt.AbstractGraphicsNode;
+
+/**
+ * Bridge class for the &lt;image> element when jpeg images.
+ *
+ * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+ */
+public class PDFImageElementBridge extends SVGImageElementBridge {
+
+ /**
+ * Constructs a new bridge for the &lt;image> element.
+ */
+ public PDFImageElementBridge() { }
+
+/*
+ /**
+ * Create the raster image node.
+ * THis checks if it is a jpeg file and creates a jpeg node
+ * so the jpeg can be inserted directly into the pdf document.
+ * @param ctx the bridge context
+ * @param e the svg element for the image
+ * @param purl the parsed url for the image resource
+ * @return a new graphics node
+ *
+ protected GraphicsNode createRasterImageNode(BridgeContext ctx,
+ Element e, ParsedURL purl) {
+
+ try {
+ JpegImage jpeg = new JpegImage(new URL(purl.toString()));
+ PDFFilter filter = jpeg.getPDFFilter();
+ PDFJpegNode node = new PDFJpegNode(jpeg);
+ Rectangle2D bounds = node.getPrimitiveBounds();
+ float [] vb = new float[4];
+ vb[0] = 0; // x
+ vb[1] = 0; // y
+ vb[2] = (float) bounds.getWidth(); // width
+ vb[3] = (float) bounds.getHeight(); // height
+
+ // handles the 'preserveAspectRatio', 'overflow' and 'clip' and sets the
+ // appropriate AffineTransform to the image node
+ initializeViewport(ctx, e, node, vb, bounds);
+
+ return node;
+ } catch (Exception ex) {
+ }
+
+ return super.createRasterImageNode(ctx, e, purl);
+ }
+*/
+
+ /**
+ * A PDF jpeg node.
+ * This holds a jpeg image so that it can be drawn into
+ * the PDFGraphics2D.
+ */
+ public static class PDFJpegNode extends AbstractGraphicsNode {
+ private JpegImage jpeg;
+
+ /**
+ * Create a new pdf jpeg node for drawing jpeg images
+ * into pdf graphics.
+ * @param j the jpeg image
+ */
+ public PDFJpegNode(JpegImage j) {
+ jpeg = j;
+ }
+
+ /**
+ * Get the outline of this image.
+ * @return the outline shape which is the primitive bounds
+ */
+ public Shape getOutline() {
+ return getPrimitiveBounds();
+ }
+
+ /**
+ * Paint this jpeg image.
+ * As this is used for inserting jpeg into pdf
+ * it adds the jpeg image to the PDFGraphics2D.
+ * @param g2d the graphics to draw the image on
+ */
+ public void primitivePaint(Graphics2D g2d) {
+ if (g2d instanceof PDFGraphics2D) {
+ PDFGraphics2D pdfg = (PDFGraphics2D) g2d;
+ pdfg.setTransform(getTransform());
+ float x = 0;
+ float y = 0;
+ try {
+ float width = jpeg.getWidth();
+ float height = jpeg.getHeight();
+ pdfg.addJpegImage(jpeg, x, y, width, height);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Get the geometrix bounds of the image.
+ * @return the primitive bounds
+ */
+ public Rectangle2D getGeometryBounds() {
+ return getPrimitiveBounds();
+ }
+
+ /**
+ * Get the primitive bounds of this bridge element.
+ * @return the bounds of the jpeg image
+ */
+ public Rectangle2D getPrimitiveBounds() {
+ try {
+ return new Rectangle2D.Double(0, 0, jpeg.getWidth(),
+ jpeg.getHeight());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/svg/PDFTextElementBridge.java b/src/java/org/apache/fop/svg/PDFTextElementBridge.java
new file mode 100644
index 000000000..664324a2b
--- /dev/null
+++ b/src/java/org/apache/fop/svg/PDFTextElementBridge.java
@@ -0,0 +1,154 @@
+/*
+ * $Id: PDFTextElementBridge.java,v 1.11 2003/03/07 09:51:26 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 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.svg;
+
+import org.apache.batik.gvt.TextNode;
+import org.apache.batik.bridge.SVGTextElementBridge;
+import org.apache.batik.bridge.BridgeContext;
+import org.apache.batik.bridge.TextUtilities;
+import org.apache.batik.gvt.GraphicsNode;
+
+import org.apache.fop.layout.FontInfo;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Bridge class for the &lt;text> element.
+ * This bridge will use the direct text painter if the text
+ * for the element is simple.
+ *
+ * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+ */
+public class PDFTextElementBridge extends SVGTextElementBridge {
+ private PDFTextPainter pdfTextPainter;
+
+ /**
+ * Constructs a new bridge for the &lt;text> element.
+ * @param fi the font infomration
+ */
+ public PDFTextElementBridge(FontInfo fi) {
+ pdfTextPainter = new PDFTextPainter(fi);
+ }
+
+ /**
+ * Create a text element bridge.
+ * This set the text painter on the node if the text is simple.
+ * @param ctx the bridge context
+ * @param e the svg element
+ * @return the text graphics node created by the super class
+ */
+ public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) {
+ GraphicsNode node = super.createGraphicsNode(ctx, e);
+ if (node != null && isSimple(ctx, e, node)) {
+ ((TextNode)node).setTextPainter(getTextPainter());
+ }
+ return node;
+ }
+
+ private PDFTextPainter getTextPainter() {
+ return pdfTextPainter;
+ }
+
+ /**
+ * Check if text element contains simple text.
+ * This checks the children of the text element to determine
+ * if the text is simple. The text is simple if it can be rendered
+ * with basic text drawing algorithms. This means there are no
+ * alternate characters, the font is known and there are no effects
+ * applied to the text.
+ *
+ * @param ctx the bridge context
+ * @param element the svg text element
+ * @param node the graphics node
+ * @return true if this text is simple of false if it cannot be
+ * easily rendered using normal drawString on the PDFGraphics2D
+ */
+ private boolean isSimple(BridgeContext ctx, Element element, GraphicsNode node) {
+ // Font size, in user space units.
+ float fs = TextUtilities.convertFontSize(element).floatValue();
+ // PDF cannot display fonts over 36pt
+ if (fs > 36) {
+ return false;
+ }
+
+ Element nodeElement;
+ for (Node n = element.getFirstChild();
+ n != null;
+ n = n.getNextSibling()) {
+
+ switch (n.getNodeType()) {
+ case Node.ELEMENT_NODE:
+
+ nodeElement = (Element)n;
+
+ if (n.getLocalName().equals(SVG_TSPAN_TAG)
+ || n.getLocalName().equals(SVG_ALT_GLYPH_TAG)) {
+ return false;
+ } else if (n.getLocalName().equals(SVG_TEXT_PATH_TAG)) {
+ return false;
+ } else if (n.getLocalName().equals(SVG_TREF_TAG)) {
+ return false;
+ }
+ break;
+ case Node.TEXT_NODE:
+ case Node.CDATA_SECTION_NODE:
+ }
+ }
+
+ /*if (CSSUtilities.convertFilter(element, node, ctx) != null) {
+ return false;
+ }*/
+
+ return true;
+ }
+}
+
diff --git a/src/java/org/apache/fop/svg/PDFTextPainter.java b/src/java/org/apache/fop/svg/PDFTextPainter.java
new file mode 100644
index 000000000..153ee5cba
--- /dev/null
+++ b/src/java/org/apache/fop/svg/PDFTextPainter.java
@@ -0,0 +1,434 @@
+/*
+ * $Id: PDFTextPainter.java,v 1.16 2003/03/07 09:51:25 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 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.svg;
+
+import java.awt.Graphics2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.Font;
+
+import java.text.AttributedCharacterIterator;
+import java.awt.font.TextAttribute;
+import java.awt.Shape;
+import java.awt.Paint;
+import java.awt.Stroke;
+import java.awt.Color;
+import java.util.List;
+import java.util.Iterator;
+
+import org.apache.batik.gvt.text.Mark;
+import org.apache.batik.gvt.TextPainter;
+import org.apache.batik.gvt.TextNode;
+import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
+import org.apache.batik.gvt.font.GVTFontFamily;
+import org.apache.batik.bridge.SVGFontFamily;
+import org.apache.batik.gvt.renderer.StrokingTextPainter;
+
+import org.apache.fop.fonts.FontMetrics;
+import org.apache.fop.layout.FontState;
+import org.apache.fop.layout.FontInfo;
+
+/**
+ * Renders the attributed character iterator of a <tt>TextNode</tt>.
+ * This class draws the text directly into the PDFGraphics2D so that
+ * the text is not drawn using shapes which makes the PDF files larger.
+ * If the text is simple enough to draw then it sets the font and calls
+ * drawString. If the text is complex or the cannot be translated
+ * into a simple drawString the StrokingTextPainter is used instead.
+ *
+ * @todo handle underline, overline and strikethrough
+ * @todo use drawString(AttributedCharacterIterator iterator...) for some
+ *
+ * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+ * @version $Id: PDFTextPainter.java,v 1.16 2003/03/07 09:51:25 jeremias Exp $
+ */
+public class PDFTextPainter implements TextPainter {
+ private FontInfo fontInfo;
+
+ /**
+ * Use the stroking text painter to get the bounds and shape.
+ * Also used as a fallback to draw the string with strokes.
+ */
+ protected static final TextPainter PROXY_PAINTER =
+ StrokingTextPainter.getInstance();
+
+ /**
+ * Create a new PDF text painter with the given font information.
+ * @param fi the fint info
+ */
+ public PDFTextPainter(FontInfo fi) {
+ fontInfo = fi;
+ }
+
+ /**
+ * Paints the specified attributed character iterator using the
+ * specified Graphics2D and context and font context.
+ * @param node the TextNode to paint
+ * @param g2d the Graphics2D to use
+ */
+ public void paint(TextNode node, Graphics2D g2d) {
+ // System.out.println("PDFText paint");
+ String txt = node.getText();
+ Point2D loc = node.getLocation();
+
+ AttributedCharacterIterator aci =
+ node.getAttributedCharacterIterator();
+ // reset position to start of char iterator
+ if (aci.getBeginIndex() == aci.getEndIndex()) {
+ return;
+ }
+ char ch = aci.first();
+ if (ch == AttributedCharacterIterator.DONE) {
+ return;
+ }
+ TextNode.Anchor anchor;
+ anchor = (TextNode.Anchor) aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE);
+
+ List gvtFonts;
+ gvtFonts = (List) aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
+ Paint forg = (Paint) aci.getAttribute(TextAttribute.FOREGROUND);
+ Paint strokePaint;
+ strokePaint = (Paint) aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.STROKE_PAINT);
+ Float size = (Float) aci.getAttribute(TextAttribute.SIZE);
+ if (size == null) {
+ return;
+ }
+ Stroke stroke = (Stroke) aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.STROKE);
+ /*
+ Float xpos = (Float) aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.X);
+ Float ypos = (Float) aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.Y);
+ */
+
+ Float posture = (Float) aci.getAttribute(TextAttribute.POSTURE);
+ Float taWeight = (Float) aci.getAttribute(TextAttribute.WEIGHT);
+
+ boolean useStrokePainter = false;
+
+ if (forg instanceof Color) {
+ Color col = (Color) forg;
+ if (col.getAlpha() != 255) {
+ useStrokePainter = true;
+ }
+ g2d.setColor(col);
+ }
+ g2d.setPaint(forg);
+ g2d.setStroke(stroke);
+
+ if (strokePaint != null) {
+ // need to draw using AttributedCharacterIterator
+ useStrokePainter = true;
+ }
+
+ if (hasUnsupportedAttributes(aci)) {
+ useStrokePainter = true;
+ }
+
+ // text contains unsupported information
+ if (useStrokePainter) {
+ PROXY_PAINTER.paint(node, g2d);
+ return;
+ }
+
+ String style = ((posture != null) && (posture.floatValue() > 0.0))
+ ? "italic" : "normal";
+ int weight = ((taWeight != null)
+ && (taWeight.floatValue() > 1.0)) ? FontInfo.BOLD
+ : FontInfo.NORMAL;
+
+ FontState fontState = null;
+ FontInfo fi = fontInfo;
+ boolean found = false;
+ String fontFamily = null;
+ if (gvtFonts != null) {
+ Iterator i = gvtFonts.iterator();
+ while (i.hasNext()) {
+ GVTFontFamily fam = (GVTFontFamily) i.next();
+ if (fam instanceof SVGFontFamily) {
+ PROXY_PAINTER.paint(node, g2d);
+ return;
+ }
+ fontFamily = fam.getFamilyName();
+ if (fi.hasFont(fontFamily, style, weight)) {
+ String fname = fontInfo.fontLookup(fontFamily, style,
+ weight);
+ FontMetrics metrics = fontInfo.getMetricsFor(fname);
+ int fsize = (int)(size.floatValue() * 1000);
+ fontState = new FontState(fname, metrics, fsize);
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ String fname =
+ fontInfo.fontLookup("any", style, FontInfo.NORMAL);
+ FontMetrics metrics = fontInfo.getMetricsFor(fname);
+ int fsize = (int)(size.floatValue() * 1000);
+ fontState = new FontState(fname, metrics, fsize);
+ } else {
+ if (g2d instanceof PDFGraphics2D) {
+ ((PDFGraphics2D) g2d).setOverrideFontState(fontState);
+ }
+ }
+ int fStyle = Font.PLAIN;
+ if (weight == FontInfo.BOLD) {
+ if (style.equals("italic")) {
+ fStyle = Font.BOLD | Font.ITALIC;
+ } else {
+ fStyle = Font.BOLD;
+ }
+ } else {
+ if (style.equals("italic")) {
+ fStyle = Font.ITALIC;
+ } else {
+ fStyle = Font.PLAIN;
+ }
+ }
+ Font font = new Font(fontFamily, fStyle,
+ (int)(fontState.getFontSize() / 1000));
+
+ g2d.setFont(font);
+
+ float advance = getStringWidth(txt, fontState);
+ float tx = 0;
+ if (anchor != null) {
+ switch (anchor.getType()) {
+ case TextNode.Anchor.ANCHOR_MIDDLE:
+ tx = -advance / 2;
+ break;
+ case TextNode.Anchor.ANCHOR_END:
+ tx = -advance;
+ }
+ }
+ g2d.drawString(txt, (float)(loc.getX() + tx), (float)(loc.getY()));
+ }
+
+ private boolean hasUnsupportedAttributes(AttributedCharacterIterator aci) {
+ boolean hasunsupported = false;
+ Object letSpace = aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.LETTER_SPACING);
+ if (letSpace != null) {
+ hasunsupported = true;
+ }
+
+ Object wordSpace = aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.WORD_SPACING);
+ if (wordSpace != null) {
+ hasunsupported = true;
+ }
+
+ AttributedCharacterIterator.Attribute key;
+ key = GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE;
+ Object writeMod = aci.getAttribute(key);
+ if (!GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE_LTR.equals(
+ writeMod)) {
+ hasunsupported = true;
+ }
+
+ Object vertOr = aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION);
+ if (GVTAttributedCharacterIterator.TextAttribute.ORIENTATION_ANGLE.equals(
+ vertOr)) {
+ hasunsupported = true;
+ }
+ return hasunsupported;
+ }
+
+ private float getStringWidth(String str, FontState fontState) {
+ float wordWidth = 0;
+ float whitespaceWidth = fontState.getWidth(fontState.mapChar(' '));
+
+ for (int i = 0; i < str.length(); i++) {
+ float charWidth;
+ char c = str.charAt(i);
+ if (!((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))) {
+ charWidth = fontState.getWidth(fontState.mapChar(c));
+ if (charWidth <= 0) {
+ charWidth = whitespaceWidth;
+ }
+ } else {
+ charWidth = whitespaceWidth;
+ }
+ wordWidth += charWidth;
+ }
+ return wordWidth / 1000f;
+ }
+
+ /**
+ * Get the outline shape of the text characters.
+ * This uses the StrokingTextPainter to get the outline
+ * shape since in theory it should be the same.
+ *
+ * @param node the text node
+ * @return the outline shape of the text characters
+ */
+ public Shape getOutline(TextNode node) {
+ return PROXY_PAINTER.getOutline(node);
+ }
+
+ /**
+ * Get the bounds.
+ * This uses the StrokingTextPainter to get the bounds
+ * since in theory it should be the same.
+ *
+ * @param node the text node
+ * @return the bounds of the text
+ */
+ public Rectangle2D getBounds2D(TextNode node) {
+ return PROXY_PAINTER.getBounds2D(node);
+ }
+
+ /**
+ * Get the geometry bounds.
+ * This uses the StrokingTextPainter to get the bounds
+ * since in theory it should be the same.
+ * @param node the text node
+ * @return the bounds of the text
+ */
+ public Rectangle2D getGeometryBounds(TextNode node) {
+ return PROXY_PAINTER.getGeometryBounds(node);
+ }
+
+ // Methods that have no purpose for PDF
+
+ /**
+ * Get the mark.
+ * This does nothing since the output is pdf and not interactive.
+ * @param node the text node
+ * @param pos the position
+ * @param all select all
+ * @return null
+ */
+ public Mark getMark(TextNode node, int pos, boolean all) {
+ System.out.println("PDFText getMark");
+ return null;
+ }
+
+ /**
+ * Select at.
+ * This does nothing since the output is pdf and not interactive.
+ * @param x the x position
+ * @param y the y position
+ * @param node the text node
+ * @return null
+ */
+ public Mark selectAt(double x, double y, TextNode node) {
+ System.out.println("PDFText selectAt");
+ return null;
+ }
+
+ /**
+ * Select to.
+ * This does nothing since the output is pdf and not interactive.
+ * @param x the x position
+ * @param y the y position
+ * @param beginMark the start mark
+ * @return null
+ */
+ public Mark selectTo(double x, double y, Mark beginMark) {
+ System.out.println("PDFText selectTo");
+ return null;
+ }
+
+ /**
+ * Selec first.
+ * This does nothing since the output is pdf and not interactive.
+ * @param node the text node
+ * @return null
+ */
+ public Mark selectFirst(TextNode node) {
+ System.out.println("PDFText selectFirst");
+ return null;
+ }
+
+ /**
+ * Select last.
+ * This does nothing since the output is pdf and not interactive.
+ * @param node the text node
+ * @return null
+ */
+ public Mark selectLast(TextNode node) {
+ System.out.println("PDFText selectLast");
+ return null;
+ }
+
+ /**
+ * Get selected.
+ * This does nothing since the output is pdf and not interactive.
+ * @param start the start mark
+ * @param finish the finish mark
+ * @return null
+ */
+ public int[] getSelected(Mark start, Mark finish) {
+ System.out.println("PDFText getSelected");
+ return null;
+ }
+
+ /**
+ * Get the highlighted shape.
+ * This does nothing since the output is pdf and not interactive.
+ * @param beginMark the start mark
+ * @param endMark the end mark
+ * @return null
+ */
+ public Shape getHighlightShape(Mark beginMark, Mark endMark) {
+ System.out.println("PDFText getHighlightShape");
+ return null;
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/svg/PDFTranscoder.java b/src/java/org/apache/fop/svg/PDFTranscoder.java
new file mode 100644
index 000000000..eb5bfb12b
--- /dev/null
+++ b/src/java/org/apache/fop/svg/PDFTranscoder.java
@@ -0,0 +1,439 @@
+/*
+ * $Id: PDFTranscoder.java,v 1.24 2003/03/07 09:51:26 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 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.svg;
+
+import java.awt.Dimension;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Dimension2D;
+import java.awt.geom.Rectangle2D;
+
+import java.awt.Color;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import java.io.IOException;
+
+import org.apache.batik.bridge.BridgeContext;
+import org.apache.batik.bridge.BridgeException;
+import org.apache.batik.bridge.GVTBuilder;
+import org.apache.batik.bridge.UserAgent;
+import org.apache.batik.bridge.UserAgentAdapter;
+import org.apache.batik.bridge.ViewBox;
+
+import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
+import org.apache.batik.dom.svg.SVGDOMImplementation;
+import org.apache.batik.dom.svg.SVGOMDocument;
+import org.apache.batik.dom.util.DocumentFactory;
+
+import org.apache.batik.gvt.GraphicsNode;
+
+import org.apache.batik.transcoder.TranscoderException;
+import org.apache.batik.transcoder.TranscoderOutput;
+import org.apache.batik.transcoder.XMLAbstractTranscoder;
+import org.apache.batik.transcoder.image.resources.Messages;
+
+import org.apache.batik.transcoder.image.ImageTranscoder;
+
+import org.apache.batik.util.SVGConstants;
+import org.apache.batik.util.XMLResourceDescriptor;
+
+import org.apache.batik.gvt.TextPainter;
+import org.apache.batik.gvt.renderer.StrokingTextPainter;
+
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.svg.SVGDocument;
+import org.w3c.dom.svg.SVGSVGElement;
+
+/**
+ * This class enables to transcode an input to a pdf document.
+ *
+ * <p>Two transcoding hints (<tt>KEY_WIDTH</tt> and
+ * <tt>KEY_HEIGHT</tt>) can be used to respectively specify the image
+ * width and the image height. If only one of these keys is specified,
+ * the transcoder preserves the aspect ratio of the original image.
+ *
+ * <p>The <tt>KEY_BACKGROUND_COLOR</tt> defines the background color
+ * to use for opaque image formats, or the background color that may
+ * be used for image formats that support alpha channel.
+ *
+ * <p>The <tt>KEY_AOI</tt> represents the area of interest to paint
+ * in device space.
+ *
+ * <p>Three additional transcoding hints that act on the SVG
+ * processor can be specified:
+ *
+ * <p><tt>KEY_LANGUAGE</tt> to set the default language to use (may be
+ * used by a &lt;switch> SVG element for example),
+ * <tt>KEY_USER_STYLESHEET_URI</tt> to fix the URI of a user
+ * stylesheet, and <tt>KEY_PIXEL_TO_MM</tt> to specify the pixel to
+ * millimeter conversion factor.
+ *
+ * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+ * @version $Id: PDFTranscoder.java,v 1.24 2003/03/07 09:51:26 jeremias Exp $
+ */
+public class PDFTranscoder extends XMLAbstractTranscoder {
+ /*
+ public static final TranscodingHints.Key KEY_STROKE_TEXT =
+ new BooleanKey();
+ */
+
+ /**
+ * The user agent dedicated to an <tt>ImageTranscoder</tt>.
+ */
+ protected UserAgent userAgent = new ImageTranscoderUserAgent();
+
+ /**
+ * Constructs a new <tt>ImageTranscoder</tt>.
+ */
+ public PDFTranscoder() {
+ hints.put(KEY_DOCUMENT_ELEMENT_NAMESPACE_URI,
+ SVGConstants.SVG_NAMESPACE_URI);
+ hints.put(KEY_DOCUMENT_ELEMENT, SVGConstants.SVG_SVG_TAG);
+ hints.put(KEY_DOM_IMPLEMENTATION,
+ SVGDOMImplementation.getDOMImplementation());
+ }
+
+ /**
+ * Transcodes the specified Document as an image in the specified output.
+ *
+ * @param document the document to transcode
+ * @param uri the uri of the document or null if any
+ * @param output the ouput where to transcode
+ * @exception TranscoderException if an error occured while transcoding
+ */
+ protected void transcode(Document document, String uri,
+ TranscoderOutput output) throws TranscoderException {
+
+ if (!(document instanceof SVGOMDocument)) {
+ throw new TranscoderException(Messages.formatMessage("notsvg",
+ null));
+ }
+ SVGDocument svgDoc = (SVGDocument)document;
+ SVGSVGElement root = svgDoc.getRootElement();
+ // initialize the SVG document with the appropriate context
+ String parserClassname = (String)hints.get(KEY_XML_PARSER_CLASSNAME);
+
+ /*boolean stroke = true;
+ if (hints.containsKey(KEY_STROKE_TEXT)) {
+ stroke = ((Boolean)hints.get(KEY_STROKE_TEXT)).booleanValue();
+ }*/
+ PDFDocumentGraphics2D graphics = new PDFDocumentGraphics2D(false);
+
+ // build the GVT tree
+ GVTBuilder builder = new GVTBuilder();
+ BridgeContext ctx = new BridgeContext(userAgent);
+ TextPainter textPainter = null;
+ textPainter = new StrokingTextPainter();
+ ctx.setTextPainter(textPainter);
+
+ PDFTextElementBridge pdfTextElementBridge;
+ pdfTextElementBridge = new PDFTextElementBridge(graphics.getFontInfo());
+ ctx.putBridge(pdfTextElementBridge);
+
+ PDFAElementBridge pdfAElementBridge = new PDFAElementBridge();
+ AffineTransform currentTransform = new AffineTransform(1, 0, 0, 1, 0, 0);
+ pdfAElementBridge.setCurrentTransform(currentTransform);
+ ctx.putBridge(pdfAElementBridge);
+ ctx.putBridge(new PDFImageElementBridge());
+ GraphicsNode gvtRoot;
+ try {
+ gvtRoot = builder.build(ctx, svgDoc);
+ } catch (BridgeException ex) {
+ throw new TranscoderException(ex);
+ }
+ // get the 'width' and 'height' attributes of the SVG document
+ float docWidth = (float)ctx.getDocumentSize().getWidth();
+ float docHeight = (float)ctx.getDocumentSize().getHeight();
+ ctx = null;
+ builder = null;
+
+ // compute the image's width and height according the hints
+ float imgWidth = -1;
+ if (hints.containsKey(ImageTranscoder.KEY_WIDTH)) {
+ imgWidth =
+ ((Float)hints.get(ImageTranscoder.KEY_WIDTH)).floatValue();
+ }
+ float imgHeight = -1;
+ if (hints.containsKey(ImageTranscoder.KEY_HEIGHT)) {
+ imgHeight =
+ ((Float)hints.get(ImageTranscoder.KEY_HEIGHT)).floatValue();
+ }
+ float width, height;
+ if (imgWidth > 0 && imgHeight > 0) {
+ width = imgWidth;
+ height = imgHeight;
+ } else if (imgHeight > 0) {
+ width = (docWidth * imgHeight) / docHeight;
+ height = imgHeight;
+ } else if (imgWidth > 0) {
+ width = imgWidth;
+ height = (docHeight * imgWidth) / docWidth;
+ } else {
+ width = docWidth;
+ height = docHeight;
+ }
+ // compute the preserveAspectRatio matrix
+ AffineTransform px;
+ String ref = null;
+ try {
+ ref = new URL(uri).getRef();
+ } catch (MalformedURLException ex) {
+ // nothing to do, catched previously
+ }
+
+ try {
+ px = ViewBox.getViewTransform(ref, root, width, height);
+ } catch (BridgeException ex) {
+ throw new TranscoderException(ex);
+ }
+
+ if (px.isIdentity() && (width != docWidth || height != docHeight)) {
+ // The document has no viewBox, we need to resize it by hand.
+ // we want to keep the document size ratio
+ float d = Math.max(docWidth, docHeight);
+ float dd = Math.max(width, height);
+ float scale = dd / d;
+ px = AffineTransform.getScaleInstance(scale, scale);
+ }
+ // take the AOI into account if any
+ if (hints.containsKey(ImageTranscoder.KEY_AOI)) {
+ Rectangle2D aoi = (Rectangle2D)hints.get(ImageTranscoder.KEY_AOI);
+ // transform the AOI into the image's coordinate system
+ aoi = px.createTransformedShape(aoi).getBounds2D();
+ AffineTransform mx = new AffineTransform();
+ double sx = width / aoi.getWidth();
+ double sy = height / aoi.getHeight();
+ mx.scale(sx, sy);
+ double tx = -aoi.getX();
+ double ty = -aoi.getY();
+ mx.translate(tx, ty);
+ // take the AOI transformation matrix into account
+ // we apply first the preserveAspectRatio matrix
+ px.preConcatenate(mx);
+ }
+ // prepare the image to be painted
+ int w = (int)width;
+ int h = (int)height;
+
+ try {
+ graphics.setupDocument(output.getOutputStream(), w, h);
+ } catch (IOException ex) {
+ throw new TranscoderException(ex);
+ }
+ graphics.setSVGDimension(docWidth, docHeight);
+ currentTransform.setTransform(1, 0, 0, -1, 0, height);
+ /*if (!stroke) {
+ textPainter = new PDFTextPainter(graphics.getFontInfo());
+ ctx.setTextPainter(textPainter);
+ }*/
+
+ if (hints.containsKey(ImageTranscoder.KEY_BACKGROUND_COLOR)) {
+ graphics.setBackgroundColor((Color)hints.get(ImageTranscoder.KEY_BACKGROUND_COLOR));
+ }
+ graphics.setGraphicContext(new org.apache.batik.ext.awt.g2d.GraphicContext());
+ graphics.setTransform(px);
+
+ gvtRoot.paint(graphics);
+
+ try {
+ graphics.finish();
+ } catch (IOException ex) {
+ throw new TranscoderException(ex);
+ }
+ }
+
+ /**
+ * Creates a <tt>DocumentFactory</tt> that is used to create an SVG DOM
+ * tree. The specified DOM Implementation is ignored and the Batik
+ * SVG DOM Implementation is automatically used.
+ *
+ * @param domImpl the DOM Implementation (not used)
+ * @param parserClassname the XML parser classname
+ * @return the document factory
+ */
+ protected DocumentFactory createDocumentFactory(DOMImplementation domImpl,
+ String parserClassname) {
+ return new SAXSVGDocumentFactory(parserClassname);
+ }
+
+ // --------------------------------------------------------------------
+ // UserAgent implementation
+ // --------------------------------------------------------------------
+
+ /**
+ * A user agent implementation for <tt>ImageTranscoder</tt>.
+ */
+ protected class ImageTranscoderUserAgent extends UserAgentAdapter {
+
+ /**
+ * Returns the default size of this user agent (400x400).
+ * @return the default viewport size
+ */
+ public Dimension2D getViewportSize() {
+ return new Dimension(400, 400);
+ }
+
+ /**
+ * Displays the specified error message using the <tt>ErrorHandler</tt>.
+ * @param message the message to display
+ */
+ public void displayError(String message) {
+ try {
+ getErrorHandler().error(new TranscoderException(message));
+ } catch (TranscoderException ex) {
+ throw new RuntimeException();
+ }
+ }
+
+ /**
+ * Displays the specified error using the <tt>ErrorHandler</tt>.
+ * @param e the exception to display
+ */
+ public void displayError(Exception e) {
+ try {
+ getErrorHandler().error(new TranscoderException(e));
+ } catch (TranscoderException ex) {
+ throw new RuntimeException();
+ }
+ }
+
+ /**
+ * Displays the specified message using the <tt>ErrorHandler</tt>.
+ * @param message the message to display
+ */
+ public void displayMessage(String message) {
+ try {
+ getErrorHandler().warning(new TranscoderException(message));
+ } catch (TranscoderException ex) {
+ throw new RuntimeException();
+ }
+ }
+
+ /**
+ * Returns the pixel to millimeter conversion factor specified in the
+ * <tt>TranscodingHints</tt> or 0.3528 if any.
+ * @return the pixel unit to millimeter factor
+ */
+ public float getPixelUnitToMillimeter() {
+ Object key = ImageTranscoder.KEY_PIXEL_UNIT_TO_MILLIMETER;
+ if (getTranscodingHints().containsKey(key)) {
+ return ((Float)getTranscodingHints().get(key)).floatValue();
+ } else {
+ // return 0.3528f; // 72 dpi
+ return 0.26458333333333333333333333333333f; // 96dpi
+ }
+ }
+
+ /**
+ * Returns the user language specified in the
+ * <tt>TranscodingHints</tt> or "en" (english) if any.
+ * @return the languages for the transcoder
+ */
+ public String getLanguages() {
+ Object key = ImageTranscoder.KEY_LANGUAGE;
+ if (getTranscodingHints().containsKey(key)) {
+ return (String)getTranscodingHints().get(key);
+ } else {
+ return "en";
+ }
+ }
+
+ /**
+ * Get the media for this transcoder. Which is always print.
+ * @return PDF media is "print"
+ */
+ public String getMedia() {
+ return "print";
+ }
+
+ /**
+ * Returns the user stylesheet specified in the
+ * <tt>TranscodingHints</tt> or null if any.
+ * @return the user style sheet URI specified in the hints
+ */
+ public String getUserStyleSheetURI() {
+ return (String)getTranscodingHints()
+ .get(ImageTranscoder.KEY_USER_STYLESHEET_URI);
+ }
+
+ /**
+ * Returns the XML parser to use from the TranscodingHints.
+ * @return the XML parser class name
+ */
+ public String getXMLParserClassName() {
+ Object key = KEY_XML_PARSER_CLASSNAME;
+ if (getTranscodingHints().containsKey(key)) {
+ return (String)getTranscodingHints().get(key);
+ } else {
+ return XMLResourceDescriptor.getXMLParserClassName();
+ }
+ }
+
+ /**
+ * Check if the XML parser is validating.
+ * @return true if the XML parser is validating
+ */
+ public boolean isXMLParserValidating() {
+ return false;
+ }
+
+ /**
+ * Unsupported operation.
+ * @return null since this is unsupported
+ */
+ public AffineTransform getTransform() {
+ return null;
+ }
+ }
+}
diff --git a/src/java/org/apache/fop/svg/SVGElement.java b/src/java/org/apache/fop/svg/SVGElement.java
new file mode 100644
index 000000000..24708d3db
--- /dev/null
+++ b/src/java/org/apache/fop/svg/SVGElement.java
@@ -0,0 +1,314 @@
+/*
+ * $Id: SVGElement.java,v 1.34 2003/03/05 15:08:45 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 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.svg;
+
+// FOP
+import org.apache.fop.fo.FONode;
+import org.apache.fop.apps.FOPException;
+
+import org.apache.batik.dom.svg.SVGOMDocument;
+import org.apache.batik.dom.svg.SVGOMElement;
+import org.apache.batik.dom.svg.SVGContext;
+import org.apache.batik.dom.util.XMLSupport;
+import org.w3c.dom.Element;
+import org.w3c.dom.svg.SVGDocument;
+import org.xml.sax.Attributes;
+import org.apache.batik.bridge.UnitProcessor;
+import org.apache.batik.util.SVGConstants;
+
+import org.w3c.dom.DOMImplementation;
+
+import org.apache.batik.dom.svg.SVGDOMImplementation;
+
+import java.net.URL;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * class representing the SVG root element
+ * for constructing an svg document.
+ */
+public class SVGElement extends SVGObj {
+
+ /**
+ * Constructs an SVG object
+ *
+ * @param parent the parent formatting object
+ */
+ public SVGElement(FONode parent) {
+ super(parent);
+ }
+
+ /**
+ * Handle the xml attributes from SAX.
+ * @param attlist the attribute list
+ * @throws FOPException not thrown from here
+ */
+ public void handleAttrs(Attributes attlist) throws FOPException {
+ super.handleAttrs(attlist);
+ init();
+ }
+
+ /**
+ * Get the dimensions of this XML document.
+ * @param view the viewport dimensions
+ * @return the dimensions of this SVG document
+ */
+ public Point2D getDimension(final Point2D view) {
+
+ // TODO - change so doesn't hold onto fo,area tree
+ Element svgRoot = element;
+ /* create an SVG area */
+ /* if width and height are zero, get the bounds of the content. */
+
+ try {
+ String baseDir = userAgent.getBaseURL();
+ if (baseDir != null) {
+ ((SVGOMDocument)doc).setURLObject(new URL(baseDir));
+ }
+ } catch (Exception e) {
+ getLogger().error("Could not set base URL for svg", e);
+ }
+
+ Element e = ((SVGDocument)doc).getRootElement();
+ final float ptmm = userAgent.getPixelUnitToMillimeter();
+ // temporary svg context
+ SVGContext dc = new SVGContext() {
+ public float getPixelToMM() {
+ return ptmm;
+ }
+ public float getPixelUnitToMillimeter() {
+ return ptmm;
+ }
+
+ public Rectangle2D getBBox() {
+ return new Rectangle2D.Double(0, 0, view.getX(), view.getY());
+ }
+
+ /**
+ * Returns the transform from the global transform space to pixels.
+ */
+ public AffineTransform getScreenTransform() {
+ throw new UnsupportedOperationException("NYI");
+ }
+
+ /**
+ * Sets the transform to be used from the global transform space
+ * to pixels.
+ */
+ public void setScreenTransform(AffineTransform at) {
+ throw new UnsupportedOperationException("NYI");
+ }
+
+ public AffineTransform getCTM() {
+ return new AffineTransform();
+ }
+
+ public AffineTransform getGlobalTransform() {
+ return new AffineTransform();
+ }
+
+ public float getViewportWidth() {
+ return (float)view.getX();
+ }
+
+ public float getViewportHeight() {
+ return (float)view.getY();
+ }
+
+ public float getFontSize() {
+ return 12;
+ }
+ };
+ ((SVGOMElement)e).setSVGContext(dc);
+
+ //if (!e.hasAttributeNS(XMLSupport.XMLNS_NAMESPACE_URI, "xmlns")) {
+ e.setAttributeNS(XMLSupport.XMLNS_NAMESPACE_URI, "xmlns",
+ SVGDOMImplementation.SVG_NAMESPACE_URI);
+ //}
+ int fontSize = 12;
+ Point2D p2d = getSize(fontSize, svgRoot, userAgent.getPixelUnitToMillimeter());
+ ((SVGOMElement)e).setSVGContext(null);
+
+ return p2d;
+ }
+
+ private void init() {
+ DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
+ String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
+ doc = impl.createDocument(svgNS, "svg", null);
+
+ element = doc.getDocumentElement();
+
+ buildTopLevel(doc, element);
+ }
+
+ /**
+ * Get the size of the SVG root element.
+ * @param size the font size
+ * @param svgRoot the svg root element
+ * @param ptmm the pixel to millimeter conversion factor
+ * @return the size of the SVG document
+ */
+ public static Point2D getSize(int size, Element svgRoot, float ptmm) {
+ String str;
+ UnitProcessor.Context ctx;
+ ctx = new PDFUnitContext(size, svgRoot, ptmm);
+ str = svgRoot.getAttributeNS(null, SVGConstants.SVG_WIDTH_ATTRIBUTE);
+ if (str.length() == 0) {
+ str = "100%";
+ }
+ float width = UnitProcessor.svgHorizontalLengthToUserSpace
+ (str, SVGConstants.SVG_WIDTH_ATTRIBUTE, ctx);
+
+ str = svgRoot.getAttributeNS(null, SVGConstants.SVG_HEIGHT_ATTRIBUTE);
+ if (str.length() == 0) {
+ str = "100%";
+ }
+ float height = UnitProcessor.svgVerticalLengthToUserSpace
+ (str, SVGConstants.SVG_HEIGHT_ATTRIBUTE, ctx);
+ return new Point2D.Float(width, height);
+ }
+
+ /**
+ * This class is the default context for a particular
+ * element. Informations not available on the element are get from
+ * the bridge context (such as the viewport or the pixel to
+ * millimeter factor.
+ */
+ public static class PDFUnitContext implements UnitProcessor.Context {
+
+ /** The element. */
+ private Element e;
+ private int fontSize;
+ private float pixeltoMM;
+
+ /**
+ * Create a PDF unit context.
+ * @param size the font size.
+ * @param e the svg element
+ * @param ptmm the pixel to millimeter factor
+ */
+ public PDFUnitContext(int size, Element e, float ptmm) {
+ this.e = e;
+ this.fontSize = size;
+ this.pixeltoMM = ptmm;
+ }
+
+ /**
+ * Returns the element.
+ * @return the element
+ */
+ public Element getElement() {
+ return e;
+ }
+
+ /**
+ * Returns the context of the parent element of this context.
+ * Since this is always for the root SVG element there never
+ * should be one...
+ * @return null
+ */
+ public UnitProcessor.Context getParentElementContext() {
+ return null;
+ }
+
+ /**
+ * Returns the pixel to mm factor. (this is deprecated)
+ * @return the pixel to millimeter factor
+ */
+ public float getPixelToMM() {
+ return pixeltoMM;
+ }
+
+ /**
+ * Returns the pixel to mm factor.
+ * @return the pixel to millimeter factor
+ */
+ public float getPixelUnitToMillimeter() {
+ return pixeltoMM;
+ }
+
+ /**
+ * Returns the font-size value.
+ * @return the default font size
+ */
+ public float getFontSize() {
+ return fontSize;
+ }
+
+ /**
+ * Returns the x-height value.
+ * @return the x-height value
+ */
+ public float getXHeight() {
+ return 0.5f;
+ }
+
+ /**
+ * Returns the viewport width used to compute units.
+ * @return the default viewport width of 100
+ */
+ public float getViewportWidth() {
+ return 100;
+ }
+
+ /**
+ * Returns the viewport height used to compute units.
+ * @return the default viewport height of 100
+ */
+ public float getViewportHeight() {
+ return 100;
+ }
+ }
+}
+
diff --git a/src/java/org/apache/fop/svg/SVGElementMapping.java b/src/java/org/apache/fop/svg/SVGElementMapping.java
new file mode 100644
index 000000000..dd6296cd5
--- /dev/null
+++ b/src/java/org/apache/fop/svg/SVGElementMapping.java
@@ -0,0 +1,115 @@
+/*
+ * $Id: SVGElementMapping.java,v 1.24 2003/03/07 09:51:25 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 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.svg;
+
+import java.util.HashMap;
+
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.FOTreeBuilder;
+import org.apache.fop.fo.ElementMapping;
+import org.apache.fop.apps.Driver;
+
+import org.apache.batik.util.XMLResourceDescriptor;
+import org.apache.batik.dom.svg.SVGDOMImplementation;
+
+/**
+ * Setup the SVG element mapping.
+ * This adds the svg element mappings used to create the objects
+ * that create the SVG Document.
+ */
+public class SVGElementMapping implements ElementMapping {
+ private static HashMap foObjs = null;
+ private static boolean batik = true;
+
+ private static synchronized void setupSVG() {
+ if (foObjs == null) {
+ // this sets the parser that will be used
+ // by default (SVGBrokenLinkProvider)
+ // normally the user agent value is used
+ XMLResourceDescriptor.setXMLParserClassName(
+ Driver.getParserClassName());
+
+ foObjs = new HashMap();
+ foObjs.put("svg", new SE());
+ foObjs.put(DEFAULT, new SVGMaker());
+ }
+ }
+
+ /**
+ * Add the SVG element mappings to the tree builder.
+ * @param builder the FOTreeBuilder to add the mappings to
+ */
+ public void addToBuilder(FOTreeBuilder builder) {
+ if (batik) {
+ try {
+ setupSVG();
+ String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
+ builder.addMapping(svgNS, foObjs);
+ } catch (Throwable t) {
+ // if the classes are not available
+ // the DISPLAY is not checked
+ batik = false;
+ }
+ }
+ }
+
+ static class SVGMaker extends ElementMapping.Maker {
+ public FONode make(FONode parent) {
+ return new SVGObj(parent);
+ }
+ }
+
+ static class SE extends ElementMapping.Maker {
+ public FONode make(FONode parent) {
+ return new SVGElement(parent);
+ }
+ }
+}
diff --git a/src/java/org/apache/fop/svg/SVGObj.java b/src/java/org/apache/fop/svg/SVGObj.java
new file mode 100644
index 000000000..07019acd4
--- /dev/null
+++ b/src/java/org/apache/fop/svg/SVGObj.java
@@ -0,0 +1,79 @@
+/*
+ * $Id: SVGObj.java,v 1.12 2003/03/07 09:51:25 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 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.svg;
+
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.XMLObj;
+
+/**
+ * Class for SVG element objects.
+ * This aids in the construction of the SVG Document.
+ */
+public class SVGObj extends XMLObj {
+ /**
+ * constructs an svg object (called by Maker).
+ *
+ * @param parent the parent formatting object
+ */
+ public SVGObj(FONode parent) {
+ super(parent);
+ }
+
+ /**
+ * Get the namespace for svg.
+ * @return the svg namespace
+ */
+ public String getNameSpace() {
+ return "http://www.w3.org/2000/svg";
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/svg/SVGUserAgent.java b/src/java/org/apache/fop/svg/SVGUserAgent.java
new file mode 100644
index 000000000..b90609d81
--- /dev/null
+++ b/src/java/org/apache/fop/svg/SVGUserAgent.java
@@ -0,0 +1,184 @@
+/*
+ * $Id: SVGUserAgent.java,v 1.14 2003/03/07 09:51:25 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 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.svg;
+
+import org.apache.fop.fo.FOUserAgent;
+
+import org.apache.batik.bridge.UserAgentAdapter;
+
+import org.apache.avalon.framework.logger.Logger;
+
+// Java
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Dimension2D;
+import java.awt.Dimension;
+
+/**
+ * The SVG user agent.
+ * This is an implementation of the batik svg user agent
+ * for handling errors and getting user agent values.
+ */
+public class SVGUserAgent extends UserAgentAdapter {
+ private AffineTransform currentTransform = null;
+ private Logger log;
+ private FOUserAgent userAgent;
+
+ /**
+ * Creates a new SVGUserAgent.
+ * @param ua the FO user agent
+ * @param at the current transform
+ */
+ public SVGUserAgent(FOUserAgent ua, AffineTransform at) {
+ currentTransform = at;
+ userAgent = ua;
+ log = userAgent.getLogger();
+ }
+
+ /**
+ * Displays an error message.
+ * @param message the message to display
+ */
+ public void displayError(String message) {
+ log.error(message);
+ }
+
+ /**
+ * Displays an error resulting from the specified Exception.
+ * @param ex the exception to display
+ */
+ public void displayError(Exception ex) {
+ log.error("SVG Error" + ex.getMessage(), ex);
+ }
+
+ /**
+ * Displays a message in the User Agent interface.
+ * The given message is typically displayed in a status bar.
+ * @param message the message to display
+ */
+ public void displayMessage(String message) {
+ log.info(message);
+ }
+
+ /**
+ * Shows an alert dialog box.
+ * @param message the message to display
+ */
+ public void showAlert(String message) {
+ log.warn(message);
+ }
+
+ /**
+ * Returns a customized the pixel to mm factor.
+ * @return the pixel unit to millimeter conversion factor
+ */
+ public float getPixelUnitToMillimeter() {
+ return userAgent.getPixelUnitToMillimeter();
+ }
+
+ /**
+ * Returns the language settings.
+ * @return the languages supported
+ */
+ public String getLanguages() {
+ return "en"; // userLanguages;
+ }
+
+ /**
+ * Returns the media type for this rendering.
+ * @return the media for fo documents is "print"
+ */
+ public String getMedia() {
+ return "print";
+ }
+
+ /**
+ * Returns the user stylesheet uri.
+ * @return null if no user style sheet was specified.
+ */
+ public String getUserStyleSheetURI() {
+ return null; // userStyleSheetURI;
+ }
+
+ /**
+ * Returns the class name of the XML parser.
+ * @return the XML parser class name
+ */
+ public String getXMLParserClassName() {
+ return org.apache.fop.apps.Driver.getParserClassName();
+ }
+
+ /**
+ * Is the XML parser validating.
+ * @return true if the xml parser is validating
+ */
+ public boolean isXMLParserValidating() {
+ return false;
+ }
+
+ /**
+ * Get the transform of the svg document.
+ * @return the transform
+ */
+ public AffineTransform getTransform() {
+ return currentTransform;
+ }
+
+ /**
+ * Get the default viewport size for an svg document.
+ * This returns a default value of 100x100.
+ * @return the default viewport size
+ */
+ public Dimension2D getViewportSize() {
+ return new Dimension(100, 100);
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/svg/SVGUtilities.java b/src/java/org/apache/fop/svg/SVGUtilities.java
new file mode 100644
index 000000000..b82771c57
--- /dev/null
+++ b/src/java/org/apache/fop/svg/SVGUtilities.java
@@ -0,0 +1,301 @@
+/*
+ * $Id: SVGUtilities.java,v 1.6 2003/03/07 09:51:26 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 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.svg;
+
+import java.util.StringTokenizer;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.font.FontRenderContext;
+
+//import org.apache.fop.fo.*;
+//import org.apache.fop.datatypes.*;
+import org.w3c.dom.Element;
+import org.w3c.dom.Document;
+import org.w3c.dom.DOMImplementation;
+
+import org.apache.batik.dom.svg.SVGDOMImplementation;
+
+/**
+ * Some utilities for creating svg DOM documents and elements.
+ */
+public class SVGUtilities {
+ private static final String SVG_NS = SVGDOMImplementation.SVG_NAMESPACE_URI;
+
+ /**
+ * Create a new svg document with batik.
+ * @param width the width of the root svg element
+ * @param height the height of the root svg element
+ * @return a new SVG Document
+ */
+ public static final Document createSVGDocument(float width,
+ float height) {
+ DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
+ Document doc = impl.createDocument(SVG_NS, "svg", null);
+
+ Element svgRoot = doc.getDocumentElement();
+ svgRoot.setAttributeNS(null, "width", "" + width);
+ svgRoot.setAttributeNS(null, "height", "" + height);
+ return doc;
+ }
+
+ /**
+ * Get the string width for a particular string given the font.
+ * @param str the string
+ * @param font the font
+ * @return the width of the string in the given font
+ */
+ public static final float getStringWidth(String str, java.awt.Font font) {
+ Rectangle2D rect =
+ font.getStringBounds(str, 0, str.length(),
+ new FontRenderContext(new AffineTransform(),
+ true, true));
+ return (float)rect.getWidth();
+ }
+
+ /**
+ * Get the string height for a particular string given the font.
+ * @param str the string
+ * @param font the font
+ * @return the height of the string in the given font
+ */
+ public static final float getStringHeight(String str,
+ java.awt.Font font) {
+ Rectangle2D rect =
+ font.getStringBounds(str, 0, str.length(),
+ new FontRenderContext(new AffineTransform(),
+ true, true));
+ return (float)rect.getHeight();
+ }
+
+ /**
+ * Get the string bounds for a particular string given the font.
+ * @param str the string
+ * @param font the font
+ * @return the bounds of the string
+ */
+ public static final Rectangle2D getStringBounds(String str,
+ java.awt.Font font) {
+ return font.getStringBounds(str, 0, str.length(),
+ new FontRenderContext(new AffineTransform(),
+ true, true));
+ }
+
+ /**
+ * Create an SVG Line
+ * @param doc the document to create the element
+ * @param x the start x position
+ * @param y the start y position
+ * @param x2 the end x position
+ * @param y2 the end y position
+ * @return the new line element
+ */
+ public static final Element createLine(Document doc, float x, float y,
+ float x2, float y2) {
+ Element ellipse = doc.createElementNS(SVG_NS, "line");
+ ellipse.setAttributeNS(null, "x1", "" + x);
+ ellipse.setAttributeNS(null, "x2", "" + x2);
+ ellipse.setAttributeNS(null, "y1", "" + y);
+ ellipse.setAttributeNS(null, "y2", "" + y2);
+ return ellipse;
+ }
+
+ /**
+ * Create an SVG Ellipse
+ * @param doc the document to create the element
+ * @param cx the centre x position
+ * @param cy the centre y position
+ * @param rx the x axis radius
+ * @param ry the y axis radius
+ * @return the new ellipse element
+ */
+ public static final Element createEllipse(Document doc, float cx,
+ float cy, float rx, float ry) {
+ Element ellipse = doc.createElementNS(SVG_NS, "ellipse");
+ ellipse.setAttributeNS(null, "cx", "" + cx);
+ ellipse.setAttributeNS(null, "rx", "" + rx);
+ ellipse.setAttributeNS(null, "cy", "" + cy);
+ ellipse.setAttributeNS(null, "ry", "" + ry);
+ return ellipse;
+ }
+
+ /**
+ * Create an SVG Path.
+ * @param doc the document to create the element
+ * @param str the string for the d attribute on the path
+ * @return the new path element
+ */
+ public static final Element createPath(Document doc, String str) {
+ Element path = doc.createElementNS(SVG_NS, "path");
+ path.setAttributeNS(null, "d", str);
+ return path;
+ }
+
+ /**
+ * Create an SVG Text object.
+ * @param doc the document to create the element
+ * @param x the start x position
+ * @param y the start y position
+ * @param str the string
+ * @return the new text element
+ */
+ public static final Element createText(Document doc, float x, float y,
+ String str) {
+ Element textGraph = doc.createElementNS(SVG_NS, "text");
+ textGraph.setAttributeNS(null, "x", "" + x);
+ textGraph.setAttributeNS(null, "y", "" + y);
+ org.w3c.dom.Text text = doc.createTextNode(str);
+ textGraph.appendChild(text);
+ return textGraph;
+ }
+
+ /**
+ * Create an SVG Rectangle.
+ * @param doc the document to create the element
+ * @param x the start x position
+ * @param y the start y position
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ * @return the new rectangle element
+ */
+ public static final Element createRect(Document doc, float x, float y,
+ float width, float height) {
+ Element border = doc.createElementNS(SVG_NS, "rect");
+ border.setAttributeNS(null, "x", "" + x);
+ border.setAttributeNS(null, "y", "" + y);
+ border.setAttributeNS(null, "width", "" + width);
+ border.setAttributeNS(null, "height", "" + height);
+ return border;
+ }
+
+ /**
+ * Create an SVG G.
+ * @param doc the document to create the element
+ * @return the new g element
+ */
+ public static final Element createG(Document doc) {
+ Element border = doc.createElementNS(SVG_NS, "g");
+ return border;
+ }
+
+ /**
+ * Create an SVG Clip.
+ * @param doc the document to create the element
+ * @param els the child elements that make the clip
+ * @param id the id of the clipping path
+ * @return the new clip element
+ */
+ public static final Element createClip(Document doc, Element els,
+ String id) {
+ Element border = doc.createElementNS(SVG_NS, "clipPath");
+ border.setAttributeNS(null, "id", id);
+ border.appendChild(els);
+ return border;
+ }
+
+ /**
+ * Create and svg image element.
+ * @param doc the document to create the element
+ * @param ref the href link to the image
+ * @param width the width to set on the image
+ * @param height the height to set on the image
+ * @return a new image element
+ */
+ public static final Element createImage(Document doc, String ref,
+ float width, float height) {
+ Element border = doc.createElementNS(SVG_NS, "image");
+ border.setAttributeNS("http://www.w3.org/1999/xlink", "href",
+ ref);
+ border.setAttributeNS(null, "width", "" + width);
+ border.setAttributeNS(null, "height", "" + height);
+ return border;
+ }
+
+ /**
+ * Create some SVG text that is wrapped into a specified width.
+ * @param doc the document to create the elements
+ * @param str the string to wrap
+ * @param font the font
+ * @param width the width to wrap
+ * @return the new element containing the wrapped text
+ */
+ public static final Element wrapText(Document doc, String str,
+ java.awt.Font font, float width) {
+ Element g = createG(doc);
+ Element text;
+ StringTokenizer st = new StringTokenizer(str, " \t\r\n");
+ float totalWidth = 0;
+ String totalStr = "";
+ int line = 0;
+ float height = getStringHeight(str, font);
+ while (st.hasMoreTokens()) {
+ String token = st.nextToken();
+ float strwidth = getStringWidth(token, font);
+ totalWidth += strwidth;
+ if (totalWidth > width) {
+ if (totalStr.equals("")) {
+ totalStr = token;
+ token = "";
+ strwidth = 0;
+ }
+ text = createText(doc, 0, line * (height + 5), totalStr);
+ g.appendChild(text);
+ totalStr = token;
+ totalWidth = strwidth;
+ line++;
+ } else {
+ totalStr = totalStr + " " + token;
+ }
+ }
+
+ return g;
+ }
+
+}
diff --git a/src/java/org/apache/fop/svg/package.html b/src/java/org/apache/fop/svg/package.html
new file mode 100644
index 000000000..1f7cfb6be
--- /dev/null
+++ b/src/java/org/apache/fop/svg/package.html
@@ -0,0 +1,31 @@
+<HTML>
+<TITLE>org.apache.fop.svg Package</TITLE>
+<BODY>
+<P>Classes that add SVG support to FOP and SVG->PDF conversion for Batik.</P>
+<P>
+This package contains classes for drawing to PDF using
+a Graphics2D implementation.
+</P>
+<P>
+The classes: PDFAElementBridge, PDFANode, PDFImageElementBridge,
+PDFTextElementBridge and PDFTextPainter are used in conjunction
+with batik to draw the SVG into the PDF document.
+</P>
+<P>
+The PDFTranscoder is a transcoder for use with batik to convert
+from SVG to a single page PDF document.
+</P>
+<P>
+SVGElement, SVGElementMapping, SVGObj and SVGUserAgent are used by
+FOP for handling embedded SVG or external SVG graphics.
+</P>
+<P>
+The PDFGraphics2D does all the work to draw into a PDF document and
+the PDFDocumentGraphics2D is used when drawing into a single document.
+</P>
+<P>
+SVGUtilities contains some useful svg element creation methods.
+</P>
+</BODY>
+</HTML>
+