]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
svg renderer now basically works, pages, text, leader, svg
authorKeiron Liddle <keiron@apache.org>
Fri, 2 Nov 2001 07:45:18 +0000 (07:45 +0000)
committerKeiron Liddle <keiron@apache.org>
Fri, 2 Nov 2001 07:45:18 +0000 (07:45 +0000)
some other misc updates to areas

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

17 files changed:
src/org/apache/fop/apps/Driver.java
src/org/apache/fop/area/Footnote.java
src/org/apache/fop/area/Property.java
src/org/apache/fop/area/inline/Container.java
src/org/apache/fop/area/inline/InlineArea.java
src/org/apache/fop/area/inline/Word.java
src/org/apache/fop/datatypes/IDReferences.java
src/org/apache/fop/fo/FOTreeBuilder.java
src/org/apache/fop/fo/FOUserAgent.java
src/org/apache/fop/fo/pagination/PageSequence.java
src/org/apache/fop/messaging/DefaultMessageListener.java
src/org/apache/fop/messaging/MessageEvent.java
src/org/apache/fop/render/AbstractRenderer.java
src/org/apache/fop/render/svg/SVGRenderer.java
src/org/apache/fop/render/xml/XMLRenderer.java
src/org/apache/fop/svg/SVGElementMapping.java
src/org/apache/fop/tools/AreaTreeBuilder.java

index e885fafb5f3540edabfd7492cfabbdff5fbc0fac..7cb5579c5f297f26629ebb64dc9f2260f12f806e 100644 (file)
@@ -566,6 +566,10 @@ class Service {
 
     public static synchronized Enumeration providers(Class cls) {
         ClassLoader cl = cls.getClassLoader();
+        // null if loaded by bootstrap class loader
+        if(cl == null) {
+            cl = ClassLoader.getSystemClassLoader();
+        }
         String serviceFile = "META-INF/services/" + cls.getName();
 
         // System.out.println("File: " + serviceFile);
index dcd62ecdf4f9bf091c0ee6c05b2ec468ed6eb54b..d36a769bcf656b4ece7a5187268efeac225b860f 100644 (file)
@@ -7,11 +7,12 @@
 
 package org.apache.fop.area;
 
+import java.io.Serializable;
 import java.util.List;
 import java.util.ArrayList;
 
 // may combine with before float into a conditional area
-public class Footnote {
+public class Footnote implements Serializable {
     Block separator = null;
 
     // footnote has an optional separator
index 3b9a836e0e3c1c2efaa0f2d262ff210fe30b74ac..4c6d5914c53d344f0d664f3273461b19588650c5 100644 (file)
@@ -7,6 +7,8 @@
 
 package org.apache.fop.area;
 
+import org.apache.fop.datatypes.ColorType;
+
 import java.io.Serializable;
 
 // properties should be serialized by the holder
@@ -26,8 +28,16 @@ public class Property implements Serializable {
     public static final int LINETHROUGH = 12;
     public static final int OFFSET = 13;
     public static final int SHADOW = 14;
+
     public int propType;
     public Object data;
 
+    public static class Background {
+        ColorType color;
+        String url;
+        int repeat;
+        int horiz;
+        int vertical;
+    }
 }
 
index 76c987e21f99ef585133c34e83687ba424f7fcc4..daf347fff189700ba867aaec8305e36cdab49700 100644 (file)
@@ -14,10 +14,13 @@ import org.apache.fop.render.Renderer;
 import java.util.List;
 import java.util.ArrayList;
 
+// this is an inline area that can have blocks as children
 public class Container extends Area {
     ArrayList blocks = new ArrayList();
+    int width;
 
-    // this is an inline area that can have blocks as children
+    public Container() {
+    }
 
     public void render(Renderer renderer) {
         renderer.renderContainer(this);
@@ -31,4 +34,8 @@ public class Container extends Area {
         return blocks;
     }
 
+    public int getWidth() {
+        return width;
+    }
+
 }
index aa229316f99082ef72a47b60f7d0ffe1bcc0bdc5..d688ae038e7b4bb30f2b1b8cd8c95e983ddffd1f 100644 (file)
@@ -45,6 +45,14 @@ public class InlineArea extends Area {
         return width;
     }
 
+    public void setOffset(int v) {
+        verticalPosition = v;
+    }
+
+    public int getOffset() {
+        return verticalPosition;
+    }
+
     public void addProperty(Property prop) {
         if (props == null) {
             props = new ArrayList();
index 070af40ff41fdaed890b05d35d7155c50a23afd1..51b009b283264fe981fe27ff688e56c9cb25cc7b 100644 (file)
@@ -17,4 +17,12 @@ public class Word extends InlineArea {
     public void render(Renderer renderer) {
         renderer.renderWord(this);
     }
+
+    public void setWord(String w) {
+        word = w;
+    }
+
+    public String getWord() {
+        return word;
+    }
 }
index 3701c6662231cd63aea6d85c284153ffbe5ff4f8..8f157cc81e6ca0fcfaa8246ab17557d3615831f5 100644 (file)
@@ -91,7 +91,6 @@ public class IDReferences {
      * Creates id entry that hasn't been validated
      *
      * @param id     The id to create
-     * @exception FOPException
      */
     public void createUnvalidatedID(String id) {
         if (id != null &&!id.equals("")) {
@@ -178,7 +177,6 @@ public class IDReferences {
      * Removes id from IDReferences
      *
      * @param id     The id to remove
-     * @exception FOPException
      */
     public void removeID(String id) {
         idReferences.remove(id);
index 4e4cefafe8d1c17335cd871d910146f8ca9eadbe..e4ac2575851993405eccb305fcf0e944e8c6d08e 100644 (file)
@@ -27,7 +27,7 @@ import org.xml.sax.Attributes;
 // Java
 import java.util.HashMap;
 import java.util.Stack;
-import java.util.Vector;
+import java.util.ArrayList;
 import java.io.IOException;
 
 /**
@@ -49,7 +49,7 @@ public class FOTreeBuilder extends DefaultHandler implements TreeBuilder {
      */
     protected HashMap fobjTable = new HashMap();
 
-    protected Vector namespaces = new Vector();
+    protected ArrayList namespaces = new ArrayList();
 
     /**
      * class that builds a property list for each formatting object
@@ -101,7 +101,7 @@ public class FOTreeBuilder extends DefaultHandler implements TreeBuilder {
      */
     public void addMapping(String namespaceURI, HashMap table) {
         this.fobjTable.put(namespaceURI, table);
-        this.namespaces.addElement(namespaceURI.intern());
+        this.namespaces.add(namespaceURI.intern());
     }
 
     /**
@@ -212,8 +212,6 @@ public class FOTreeBuilder extends DefaultHandler implements TreeBuilder {
         /* the maker for the formatting object started */
         FObj.Maker fobjMaker = null;
 
-        // String fullName = mapName(rawName);
-        //String fullName = uri + "^" + localName;
         HashMap table = (HashMap)fobjTable.get(uri);
         if(table != null) {
             fobjMaker = (FObj.Maker)table.get(localName);
@@ -275,17 +273,6 @@ public class FOTreeBuilder extends DefaultHandler implements TreeBuilder {
         currentFObj = fobj;
     }
 
-    /**
-     * format this formatting object tree
-     *
-     * @param areaTree the area tree to format into
-     */
-/*    public void format(AreaTree areaTree) throws FOPException {
-        log.info("formatting FOs into areas");
-        this.bufferManager.readComplete();
-        ((Root)this.rootFObj).format(areaTree);
-    }
-*/
     public void reset() {
         currentFObj = null;
         rootFObj = null;
index 05ae93456928b5dbdf42071fd3a560d1622c4693..d89f308e4a75bf9bb82fd0b61adb9f4ce85d9f73 100644 (file)
@@ -73,7 +73,7 @@ public class FOUserAgent {
                 handler.handleXML(ctx, doc, namespace);
             } catch (Throwable t) {
                 // could not handle document
-                //t.printStackTrace();
+                t.printStackTrace();
             }
         } else {
             // no handler found for document
index 290f194543e438fe2719adc4f75346adbd685fe7..5b957d8a82b8b58687d46b342033596b0d58d0d0 100644 (file)
@@ -28,10 +28,10 @@ import org.apache.fop.apps.FOPException;
 // Java
 import java.util.*;
 
-
 /**
- * This provides pagination of flows onto pages. Much of the logic for paginating
- * flows is contained in this class. The main entry point is the format method.
+ * This provides pagination of flows onto pages. Much of the
+ * logic for paginating flows is contained in this class.
+ * The main entry point is the format method.
  */
 public class PageSequence extends FObj {
     //
index 55e6e70f4345b089479c48c6310f38542505cc61..081bd6032e6b4b9d5773dee041a16af02a1e83c1 100644 (file)
@@ -7,14 +7,10 @@
 
 package org.apache.fop.messaging;
 
-
 /**
  * A trivial implementation of a MessageListener
  * For further explanation
- * @see MessageListener
  */
-
-
 public class DefaultMessageListener implements MessageListener {
 
     /**
index ac4c6f683263851e4633a0a272323fea01d36fcf..92a742aaaa6836d2276c331865dbde2d6fd8f816 100644 (file)
@@ -13,10 +13,7 @@ import java.util.EventObject;
  * a container for the text and the type of a message
  * MessageEvents are created by MessageHandler and can be received by any
  * MessageListener, which is added to MessageHandler;
- * @see org.apache.fop.MessageListener MessageListener
- *
  */
-
 public class MessageEvent extends EventObject {
     public static final int LOG = 0;
     public static final int ERROR = 1;
index a76a32f5e202153e5434a99eb53afec629c5bb2b..d2bebb77c41e724670502af2fb53df95b5c81bf0 100644 (file)
@@ -13,12 +13,14 @@ import org.apache.fop.apps.FOPException;
 import org.apache.fop.area.*;
 import org.apache.fop.area.Span;
 import org.apache.fop.area.inline.*;
+import org.apache.fop.area.inline.Character;
 import org.apache.fop.area.inline.Space;
 import org.apache.fop.fo.FOUserAgent;
 
 import org.apache.log.Logger;
 
 // Java
+import java.awt.geom.Rectangle2D;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.HashMap;
@@ -56,6 +58,29 @@ public abstract class AbstractRenderer implements Renderer {
         options = opt;
     }
 
+    /**
+     * Utility method to convert a page sequence title to a string.
+     * Some renderers may only be able to use a string title.
+     * A title is a sequence of inline areas that this method
+     * attempts to convert to an equivalent string.
+     */
+    public String convertTitleToString(Title title) {
+        String str = "";
+        List children = title.getInlineAreas();
+
+        for (int count = 0; count < children.size(); count++) {
+            InlineArea inline = (InlineArea) children.get(count);
+            if (inline instanceof Character) {
+                str += ((Character) inline).getChar();
+            } else if (inline instanceof Word) {
+                str += ((Word) inline).getWord();
+            } else {
+                str += " ";
+            }
+        }
+        return str.trim();
+    }
+
     public void startPageSequence(Title seqTitle) {
     }
 
@@ -87,6 +112,11 @@ public abstract class AbstractRenderer implements Renderer {
     // a position from where the region is placed
     protected void renderRegionViewport(RegionViewport port) {
         if (port != null) {
+            Rectangle2D view = port.getViewArea();
+            currentBPPosition = (int) view.getY();
+            currentIPPosition = (int) view.getX();
+            currentBlockIPPosition = currentIPPosition;
+
             Region region = port.getRegion();
             if (region.getRegionClass() == Region.BODY) {
                 renderBodyRegion((BodyRegion) region);
@@ -185,7 +215,9 @@ public abstract class AbstractRenderer implements Renderer {
                 // of the line, each inline object is offset from there
                 for (int count = 0; count < children.size(); count++) {
                     LineArea line = (LineArea) children.get(count);
+                    currentBlockIPPosition = currentIPPosition;
                     renderLineArea(line);
+                    currentBPPosition += line.getHeight();
                 }
 
             }
@@ -213,21 +245,30 @@ public abstract class AbstractRenderer implements Renderer {
         } else if (content instanceof ForeignObject) {
             renderForeignObject((ForeignObject) content);
         }
+        currentBlockIPPosition += viewport.getWidth();
     }
 
     public void renderImage(Image image) {
     }
 
     public void renderContainer(Container cont) {
+        int saveIP = currentIPPosition;
+        currentIPPosition = currentBlockIPPosition;
+        int saveBlockIP = currentBlockIPPosition;
+        int saveBP = currentBPPosition;
+
         List blocks = cont.getBlocks();
         renderBlocks(blocks);
+        currentIPPosition = saveIP;
+        currentBlockIPPosition = saveBlockIP;
+        currentBPPosition = saveBP;
     }
 
     public void renderForeignObject(ForeignObject fo) {
 
     }
 
-    public void renderCharacter(org.apache.fop.area.inline.Character ch) {
+    public void renderCharacter(Character ch) {
         currentBlockIPPosition += ch.getWidth();
     }
 
index 46458f420feab54f075ff3d50ee4413729d7acdc..b47a832fd5995c1db32af835c40ce9e2f9c0ad02 100644 (file)
@@ -7,13 +7,16 @@
 
 package org.apache.fop.render.svg;
 
-import org.apache.fop.layout.*;
-import org.apache.fop.layout.inline.*;
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.area.*;
+import org.apache.fop.area.inline.*;
 import org.apache.fop.datatypes.IDReferences;
 import org.apache.fop.datatypes.ColorType;
 import org.apache.fop.image.*;
 import org.apache.fop.svg.SVGArea;
 import org.apache.fop.svg.SVGUtilities;
+import org.apache.fop.layout.FontInfo;
+import org.apache.fop.fo.FOUserAgent;
 
 import org.w3c.dom.Node;
 import org.w3c.dom.ProcessingInstruction;
@@ -22,6 +25,7 @@ import org.w3c.dom.svg.SVGDocument;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Text;
 
 import org.apache.batik.dom.svg.SVGDOMImplementation;
 import org.apache.batik.dom.svg.SVGOMElement;
@@ -30,12 +34,13 @@ import org.apache.batik.transcoder.svg2svg.SVGTranscoder;
 import org.apache.batik.transcoder.TranscoderInput;
 import org.apache.batik.transcoder.TranscoderOutput;
 import org.apache.batik.transcoder.TranscoderException;
+import org.apache.batik.dom.util.DOMUtilities;
 
 import java.awt.Color;
 import java.awt.Image;
 import java.awt.image.BufferedImage;
 import java.awt.geom.Rectangle2D;
-import java.util.Hashtable;
+import java.util.HashMap;
 import java.net.URL;
 import java.net.MalformedURLException;
 import java.io.OutputStream;
@@ -44,23 +49,40 @@ import java.io.OutputStreamWriter;
 import javax.swing.ImageIcon;
 
 import org.apache.fop.render.AbstractRenderer;
+import org.apache.fop.render.XMLHandler;
+import org.apache.fop.render.RendererContext;
 
-public class SVGRenderer extends AbstractRenderer {
+public class SVGRenderer extends AbstractRenderer implements XMLHandler {
+    public static final String mimeType = "image/svg+xml";
     static final String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
     Document svgDocument;
     Element svgRoot;
     Element currentPageG = null;
     Element lastLink = null;
+    String lastViewbox = null;
+
+    Element docDefs = null;
+    Element pageDefs = null;
+    Element pagesGroup = null;
+
+    // first sequence title
+    Title docTitle = null;
+
+    RendererContext context;
+
+    OutputStream ostream;
 
     float totalWidth = 0;
     float totalHeight = 0;
+    float sequenceWidth = 0;
+    float sequenceHeight = 0;
 
-    protected int pageWidth = 0;
-    protected int pageHeight = 0;
+    protected float pageWidth = 0;
+    protected float pageHeight = 0;
     protected int pageNumber = 0;
 
-    protected Hashtable fontNames = new Hashtable();
-    protected Hashtable fontStyles = new Hashtable();
+    protected HashMap fontNames = new HashMap();
+    protected HashMap fontStyles = new HashMap();
     protected Color saveColor = null;
 
     protected IDReferences idReferences = null;
@@ -83,26 +105,267 @@ public class SVGRenderer extends AbstractRenderer {
     protected float currentBlue = 0;
 
     public SVGRenderer() {
+        context = new RendererContext(mimeType);
+    }
+
+    public void setUserAgent(FOUserAgent agent) {
+        super.setUserAgent(agent);
+        userAgent.setDefaultXMLHandler(mimeType, this);
+        userAgent.addXMLHandler(mimeType, svgNS, this);
     }
 
     public void setupFontInfo(FontInfo fontInfo) {
         // create a temp Image to test font metrics on
         BufferedImage fontImage =
-            new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
-        org.apache.fop.render.awt.FontSetup.setup(fontInfo, fontImage.createGraphics());
+          new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
+        org.apache.fop.render.awt.FontSetup.setup(fontInfo,
+                fontImage.createGraphics());
     }
 
     public void setProducer(String producer) {
     }
 
     public void startRenderer(OutputStream outputStream)
-    throws IOException {}
+    throws IOException {
+        ostream = outputStream;
+        DOMImplementation impl =
+          SVGDOMImplementation.getDOMImplementation();
+        svgDocument = impl.createDocument(svgNS, "svg", null);
+        ProcessingInstruction pi =
+          svgDocument.createProcessingInstruction("xml", " version=\"1.0\" encoding=\"ISO-8859-1\"");
+        svgRoot = svgDocument.getDocumentElement();
+        svgDocument.insertBefore(pi, svgRoot);
+
+        docDefs = svgDocument.createElementNS(svgNS, "defs");
+        svgRoot.appendChild(docDefs);
+
+        pagesGroup = svgDocument.createElementNS(svgNS, "g");
+        pageDefs = svgDocument.createElementNS(svgNS, "defs");
+        pagesGroup.appendChild(pageDefs);
+        svgRoot.appendChild(pagesGroup);
+
+    }
 
     /**
      *
      */
-    public void stopRenderer()
-    throws IOException
-    {
+    public void stopRenderer() throws IOException {
+        totalWidth += sequenceWidth;
+        if (sequenceHeight > totalHeight) {
+            totalHeight = sequenceHeight;
+        }
+
+        svgRoot.setAttributeNS(null, "width", "" + (totalWidth + 1));
+        svgRoot.setAttributeNS(null, "height", "" + (totalHeight + 1));
+        //svgRoot.setAttributeNS(null, "viewBox", "0 0 " + pageWidth + " " + pageHeight);
+        SVGTranscoder svgT = new SVGTranscoder();
+        TranscoderInput input = new TranscoderInput(svgDocument);
+        TranscoderOutput output =
+          new TranscoderOutput(new OutputStreamWriter(ostream));
+        try {
+            svgT.transcode(input, output);
+        } catch (TranscoderException e) {
+            log.error("could not write svg file :" + e.getMessage(), e);
+        }
+        ostream.flush();
+        ostream = null;
+
+        svgDocument = null;
+        svgRoot = null;
+        currentPageG = null;
+        lastLink = null;
+
+        totalWidth = 0;
+        totalHeight = 0;
+
+        pageNumber = 0;
+    }
+
+    public void startPageSequence(Title seqTitle) {
+        totalWidth += sequenceWidth;
+        if (sequenceHeight > totalHeight) {
+            totalHeight = sequenceHeight;
+        }
+        sequenceWidth = 0;
+        sequenceHeight = 0;
+        if (seqTitle != null && docTitle == null) {
+            // convert first title to a string and set for svg document title
+            docTitle = seqTitle;
+            String str = convertTitleToString(seqTitle);
+            Element svgTitle = svgDocument.createElementNS(svgNS, "title");
+            Text strNode = svgDocument.createTextNode(str);
+            svgTitle.appendChild(strNode);
+            svgRoot.insertBefore(svgTitle, svgRoot.getFirstChild());
+        }
+    }
+
+    public void renderPage(PageViewport page) throws IOException,
+    FOPException {
+        float lastWidth = pageWidth;
+        float lastHeight = pageHeight;
+
+        Rectangle2D area = page.getViewArea();
+        pageWidth = (float) area.getWidth() / 1000f;
+        pageHeight = (float) area.getHeight() / 1000f;
+
+        // if there is a link from the last page
+        if (lastLink != null) {
+            lastLink.setAttributeNS(null, "xlink:href",
+                                    "#svgView(viewBox(" + totalWidth + ", "+
+                                    sequenceHeight + ", " + pageWidth + ", " +
+                                    pageHeight + "))");
+            pagesGroup.appendChild(lastLink);
+        }
+
+        currentPageG = svgDocument.createElementNS(svgNS, "svg");
+        currentPageG.setAttributeNS(null, "viewbox",
+                                    "0 0 " + (int) pageWidth + " " + (int) pageHeight);
+        currentPageG.setAttributeNS(null, "width",
+                                    "" + ((int) pageWidth + 1));
+        currentPageG.setAttributeNS(null, "height",
+                                    "" + ((int) pageHeight + 1));
+        currentPageG.setAttributeNS(null, "id", "Page-" + pageNumber);
+        currentPageG.setAttributeNS(null, "style", "font-family:sanserif;font-size:12");
+        pageDefs.appendChild(currentPageG);
+
+        if (pageWidth > sequenceWidth) {
+            sequenceWidth = pageWidth;
+        }
+        sequenceHeight += pageHeight;
+
+        Element border =
+          SVGUtilities.createRect(svgDocument, 0, 0, pageWidth,
+                                  pageHeight);
+        border.setAttributeNS(null, "style", "fill:none;stroke:black");
+        currentPageG.appendChild(border);
+
+        // render the page contents
+        super.renderPage(page);
+
+        Element use = svgDocument.createElementNS(svgNS, "use");
+        use.setAttributeNS(null, "xlink:href", "#Page-" + pageNumber);
+        use.setAttributeNS(null, "x", "" + totalWidth);
+        use.setAttributeNS(null, "y", "" + (sequenceHeight - pageHeight));
+        pagesGroup.appendChild(use);
+
+        Element lastPageLink = svgDocument.createElementNS(svgNS, "a");
+        if (lastLink != null) {
+            lastPageLink.setAttributeNS(null, "xlink:href", lastViewbox);
+        } else {
+            lastPageLink.setAttributeNS(null, "xlink:href",
+                                        "#svgView(viewBox(" + totalWidth + ", " +
+                                        (sequenceHeight - pageHeight) + ", " + pageWidth +
+                                        ", " + pageHeight + "))");
+        }
+        pagesGroup.appendChild(lastPageLink);
+
+        // setup a link to the next page, only added when the
+        // next page is rendered
+        Element rect = SVGUtilities.createRect(svgDocument, totalWidth,
+                                               (sequenceHeight - pageHeight), pageWidth / 2, pageHeight);
+        rect.setAttributeNS(null, "style", "fill:blue;visibility:hidden");
+        lastPageLink.appendChild(rect);
+
+        lastLink = svgDocument.createElementNS(svgNS, "a");
+        rect = SVGUtilities.createRect(svgDocument,
+                                       totalWidth + pageWidth / 2,
+                                       (sequenceHeight - pageHeight), pageWidth / 2, pageHeight);
+        rect.setAttributeNS(null, "style", "fill:blue;visibility:hidden");
+        lastLink.appendChild(rect);
+
+        lastViewbox = "#svgView(viewBox(" + totalWidth + ", " +
+                      (sequenceHeight - pageHeight) + ", " + pageWidth +
+                      ", " + pageHeight + "))";
+
+        pageNumber++;
+
+    }
+
+    public void renderForeignObject(ForeignObject fo) {
+        Document doc = fo.getDocument();
+        String ns = fo.getNameSpace();
+        userAgent.renderXML(context, doc, ns);
+    }
+
+    public void handleXML(RendererContext context, Document doc,
+                          String ns) throws Exception {
+        if (svgNS.equals(ns)) {
+            if (!(doc instanceof SVGDocument)) {
+                DOMImplementation impl =
+                  SVGDOMImplementation.getDOMImplementation();
+                doc = DOMUtilities.deepCloneDocument(doc, impl);
+            }
+            SVGSVGElement svg = ((SVGDocument) doc).getRootElement();
+            Element view = svgDocument.createElementNS(svgNS, "svg");
+            Node newsvg = svgDocument.importNode(svg, true);
+            //view.setAttributeNS(null, "viewBox", "0 0 ");
+            view.setAttributeNS(null, "x",
+                                "" + currentBlockIPPosition / 1000f);
+            view.setAttributeNS(null, "y", "" + currentBPPosition / 1000f);
+
+            // this fixes a problem where the xmlns is repeated sometimes
+            Element ele = (Element) newsvg;
+            ele.setAttributeNS(XMLSupport.XMLNS_NAMESPACE_URI, "xmlns",
+                               svgNS);
+            if (ele.hasAttributeNS(null, "xmlns")) {
+                ele.removeAttributeNS(null, "xmlns");
+            }
+
+            view.appendChild(newsvg);
+            currentPageG.appendChild(view);
+        }
+    }
+
+    public void renderLeader(Leader area) {
+        String style = "stroke:black;stroke-width:" +
+                       (area.getRuleThickness() / 1000) + ";";
+        switch (area.getRuleStyle()) {
+            case Leader.DOTTED:
+                style += "stroke-dasharray:1,1";
+                break;
+            case Leader.DASHED:
+                style += "stroke-dasharray:5,1";
+                break;
+            case Leader.SOLID:
+                break;
+            case Leader.DOUBLE:
+                break;
+            case Leader.GROOVE:
+                break;
+            case Leader.RIDGE:
+                break;
+        }
+        Element line = SVGUtilities.createLine(svgDocument,
+                                               currentBlockIPPosition / 1000,
+                                               (currentBPPosition + area.getOffset() -
+                                                area.getRuleThickness() / 2) / 1000,
+                                               (currentBlockIPPosition + area.getWidth()) / 1000,
+                                               (currentBPPosition + area.getOffset() -
+                                                area.getRuleThickness() / 2) / 1000);
+        line.setAttributeNS(null, "style", style);
+        currentPageG.appendChild(line);
+
+        super.renderLeader(area);
+    }
+
+    public void renderWord(Word word) {
+        Element text = SVGUtilities.createText(svgDocument,
+                                               currentBlockIPPosition / 1000,
+                                               (currentBPPosition + word.getOffset()) / 1000,
+                                               word.getWord());
+        currentPageG.appendChild(text);
+
+        super.renderWord(word);
+    }
+
+    public void renderCharacter(org.apache.fop.area.inline.Character ch) {
+        Element text = SVGUtilities.createText(svgDocument,
+                                               currentBlockIPPosition / 1000,
+                                               (currentBPPosition + ch.getOffset()) / 1000,
+                                               "" + ch.getChar());
+        currentPageG.appendChild(text);
+
+        super.renderCharacter(ch);
     }
 }
+
index 33fa2ed9a8d91a341de5cf73613d417f42095ff4..e0a35fd36e66a07f40448db3841625615a06d204 100644 (file)
@@ -37,6 +37,10 @@ import org.w3c.dom.Document;
 
 /**
  * Renderer that renders areas to XML for debugging purposes.
+ * This creates an xml that contains the information of the area
+ * tree. It does not output any state or derived information.
+ * The output can be used to build a new area tree (@see AreaTreeBuilder)
+ * which can be rendered to any renderer.
  */
 public class XMLRenderer extends AbstractRenderer {
     public static final String mimeType = "text/xml";
@@ -353,7 +357,7 @@ public class XMLRenderer extends AbstractRenderer {
                 style = "ridge";
                 break;
         }
-        writeElement("<leader ruleStyle=\"" + style +
+        writeElement("<leader width=\"" + area.getWidth() + "\" ruleStyle=\"" + style +
                      "\" ruleThickness=\"" + area.getRuleThickness() + "\"/>");
         super.renderLeader(area);
     }
index 012cd9b89ee507b4fd3eb05a246a6361fe6306da..dc7df3dfb909dd0a7862dab5955084a960723d71 100644 (file)
@@ -17,78 +17,84 @@ 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;
 
 public class SVGElementMapping implements ElementMapping {
 
-    private static HashMap foObjs = null;    
-    
-    public synchronized void addToBuilder(TreeBuilder builder) {
+    private static HashMap foObjs = null;
 
-        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", SVGElement.maker());
-            foObjs.put("rect", SVGObj.maker("rect"));
-            foObjs.put("line", SVGObj.maker("line"));
-            foObjs.put("text", SVGObj.maker("text"));
-
-            foObjs.put("desc", SVGObj.maker("desc"));
-            foObjs.put("title", SVGObj.maker("title"));
-            foObjs.put("circle", SVGObj.maker("circle"));
-            foObjs.put("ellipse", SVGObj.maker("ellipse"));
-            foObjs.put("g", SVGObj.maker("g"));
-            foObjs.put("polyline", SVGObj.maker("polyline"));
-            foObjs.put("polygon", SVGObj.maker("polygon"));
-            foObjs.put("defs", SVGObj.maker("defs"));
-            foObjs.put("path", SVGObj.maker("path"));
-            foObjs.put("use", SVGObj.maker("use"));
-            foObjs.put("tspan", SVGObj.maker("tspan"));
-            foObjs.put("tref", SVGObj.maker("tref"));
-            foObjs.put("image", SVGObj.maker("image"));
-            foObjs.put("style", SVGObj.maker("style"));
-
-            foObjs.put("textPath", SVGObj.maker("textPath"));
-            foObjs.put("clipPath", SVGObj.maker("clipPath"));
-            foObjs.put("mask", SVGObj.maker("mask"));
-            foObjs.put("linearGradient", SVGObj.maker("linearGradient"));
-            foObjs.put("radialGradient", SVGObj.maker("radialGradient"));
-            foObjs.put("stop", SVGObj.maker("stop"));
-            foObjs.put("a", SVGObj.maker("a"));
-            foObjs.put("switch", SVGObj.maker("switch"));
-            foObjs.put("symbol", SVGObj.maker("symbol"));
-
-            foObjs.put("pattern", SVGObj.maker("pattern"));
-
-            foObjs.put("marker", SVGObj.maker("marker"));
-            foObjs.put("animate", SVGObj.maker("animate"));
-            foObjs.put("altGlyph", SVGObj.maker("altGlyph"));
-            foObjs.put("font", SVGObj.maker("font"));
-            foObjs.put("glyph", SVGObj.maker("glyph"));
-            foObjs.put("missing-glyph", SVGObj.maker("missing-glyph"));
-            foObjs.put("hkern", SVGObj.maker("hkern"));
-            foObjs.put("vkern", SVGObj.maker("vkern"));
-            foObjs.put("set", SVGObj.maker("set"));
-            foObjs.put("animateMotion", SVGObj.maker("animateMotion"));
-            foObjs.put("animateColor", SVGObj.maker("animateColor"));
-            foObjs.put("animateTransform", SVGObj.maker("animateTransform"));
-            foObjs.put("cursor", SVGObj.maker("cursor"));
-            foObjs.put("filter", SVGObj.maker("filter"));
-
-            foObjs.put("feFlood", SVGObj.maker("feFlood"));
-            foObjs.put("feGaussianBlur", SVGObj.maker("feGaussianBlur"));
-            foObjs.put("feOffset", SVGObj.maker("feOffset"));
-            foObjs.put("feMerge", SVGObj.maker("feMerge"));
-            foObjs.put("feMergeNode", SVGObj.maker("feMergeNode"));
+    public synchronized void addToBuilder(TreeBuilder builder) {
+        try {
+            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", SVGElement.maker());
+                foObjs.put("rect", SVGObj.maker("rect"));
+                foObjs.put("line", SVGObj.maker("line"));
+                foObjs.put("text", SVGObj.maker("text"));
+
+                foObjs.put("desc", SVGObj.maker("desc"));
+                foObjs.put("title", SVGObj.maker("title"));
+                foObjs.put("circle", SVGObj.maker("circle"));
+                foObjs.put("ellipse", SVGObj.maker("ellipse"));
+                foObjs.put("g", SVGObj.maker("g"));
+                foObjs.put("polyline", SVGObj.maker("polyline"));
+                foObjs.put("polygon", SVGObj.maker("polygon"));
+                foObjs.put("defs", SVGObj.maker("defs"));
+                foObjs.put("path", SVGObj.maker("path"));
+                foObjs.put("use", SVGObj.maker("use"));
+                foObjs.put("tspan", SVGObj.maker("tspan"));
+                foObjs.put("tref", SVGObj.maker("tref"));
+                foObjs.put("image", SVGObj.maker("image"));
+                foObjs.put("style", SVGObj.maker("style"));
+
+                foObjs.put("textPath", SVGObj.maker("textPath"));
+                foObjs.put("clipPath", SVGObj.maker("clipPath"));
+                foObjs.put("mask", SVGObj.maker("mask"));
+                foObjs.put("linearGradient", SVGObj.maker("linearGradient"));
+                foObjs.put("radialGradient", SVGObj.maker("radialGradient"));
+                foObjs.put("stop", SVGObj.maker("stop"));
+                foObjs.put("a", SVGObj.maker("a"));
+                foObjs.put("switch", SVGObj.maker("switch"));
+                foObjs.put("symbol", SVGObj.maker("symbol"));
+
+                foObjs.put("pattern", SVGObj.maker("pattern"));
+
+                foObjs.put("marker", SVGObj.maker("marker"));
+                foObjs.put("animate", SVGObj.maker("animate"));
+                foObjs.put("altGlyph", SVGObj.maker("altGlyph"));
+                foObjs.put("font", SVGObj.maker("font"));
+                foObjs.put("glyph", SVGObj.maker("glyph"));
+                foObjs.put("missing-glyph", SVGObj.maker("missing-glyph"));
+                foObjs.put("hkern", SVGObj.maker("hkern"));
+                foObjs.put("vkern", SVGObj.maker("vkern"));
+                foObjs.put("set", SVGObj.maker("set"));
+                foObjs.put("animateMotion", SVGObj.maker("animateMotion"));
+                foObjs.put("animateColor", SVGObj.maker("animateColor"));
+                foObjs.put("animateTransform", SVGObj.maker("animateTransform"));
+                foObjs.put("cursor", SVGObj.maker("cursor"));
+                foObjs.put("filter", SVGObj.maker("filter"));
+
+                foObjs.put("feFlood", SVGObj.maker("feFlood"));
+                foObjs.put("feGaussianBlur", SVGObj.maker("feGaussianBlur"));
+                foObjs.put("feOffset", SVGObj.maker("feOffset"));
+                foObjs.put("feMerge", SVGObj.maker("feMerge"));
+                foObjs.put("feMergeNode", SVGObj.maker("feMergeNode"));
+            }
+
+            String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
+            builder.addMapping(svgNS, foObjs);
+
+            builder.addPropertyListBuilder(svgNS,
+                                           new DirectPropertyListBuilder());
+        } catch (Throwable t) {
+            // if the classes are not available
         }
-
-        String uri = "http://www.w3.org/2000/svg";
-        builder.addMapping(uri, foObjs);
-
-        builder.addPropertyListBuilder(uri, new DirectPropertyListBuilder());
     }
 
 }
index e77713da85a6e2ec7cce5002350c5228c0606eda..63fac5c91d36a1a99e32f7078e9973acaee4e4e7 100644 (file)
@@ -17,6 +17,7 @@ import org.apache.fop.render.pdf.*;
 import org.apache.fop.render.svg.*;
 import org.apache.fop.render.xml.*;
 import org.apache.fop.layout.FontInfo;
+import org.apache.fop.layout.FontState;
 import org.apache.fop.fo.FOUserAgent;
 
 import org.apache.log.*;
@@ -30,6 +31,8 @@ import java.util.*;
 import java.awt.geom.Rectangle2D;
 import java.util.StringTokenizer;
 
+import javax.xml.parsers.DocumentBuilderFactory;
+
 import org.w3c.dom.*;
 
 import org.apache.batik.dom.svg.SVGDOMImplementation;
@@ -41,12 +44,14 @@ import org.apache.batik.dom.util.DOMUtilities;
  * for the purpose of testing the area tree and rendering.
  * This covers the set of possible properties that can be set
  * on the area tree for rendering.
+ * As this is not for general purpose there is no attempt to handle
+ * invalid area tree xml.
+ *
  * Tests: different renderers, saving and loading pages with serialization
  * out of order rendering
  */
 public class AreaTreeBuilder {
     private Logger log;
-    //String baseName = "temp";
 
     /**
      */
@@ -129,6 +134,7 @@ public class AreaTreeBuilder {
                 while (c < pagec) {
                     PageViewport page = sm.getPage(count, c);
                     c++;
+                    // save the page to a stream for testing
                     ObjectOutputStream tempstream = new ObjectOutputStream(
                                                       new BufferedOutputStream(
                                                         new FileOutputStream("temp.ser")));
@@ -142,6 +148,7 @@ public class AreaTreeBuilder {
                                                new FileInputStream("temp.ser")));
                     page.loadPage(in);
                     in.close();
+
                     rend.renderPage(page);
                 }
                 count++;
@@ -163,6 +170,7 @@ class TreeLoader {
     AreaTree areaTree;
     AreaTree.AreaTreeModel model;
     FontInfo fontInfo;
+    FontState currentFontState;
 
     TreeLoader(FontInfo fi) {
         fontInfo = fi;
@@ -175,8 +183,10 @@ class TreeLoader {
     public void buildAreaTree(InputStream is) {
         Document doc = null;
         try {
-            doc = javax.xml.parsers.DocumentBuilderFactory.newInstance().
-                  newDocumentBuilder().parse(is);
+            DocumentBuilderFactory fact =
+              DocumentBuilderFactory.newInstance();
+            fact.setNamespaceAware(true);
+            doc = fact.newDocumentBuilder().parse(is);
         } catch (Exception e) {
             e.printStackTrace();
         }
@@ -475,6 +485,16 @@ class TreeLoader {
                 Character ch =
                   new Character(getString((Element) obj).charAt(0));
                 addProperties((Element) obj, ch);
+                try {
+                    currentFontState =
+                      new FontState(fontInfo, "sans-serif", "normal",
+                                    "normal", 12000, 0);
+                } catch (FOPException e) {
+
+                }
+
+                ch.setWidth(currentFontState.width(ch.getChar()));
+                ch.setOffset(currentFontState.getCapHeight());
                 list.add(ch);
             } else if (obj.getNodeName().equals("space")) {
                 Space space = new Space();
@@ -520,6 +540,11 @@ class TreeLoader {
             return null;
         }
         Viewport viewport = new Viewport(child);
+        String str = root.getAttribute("width");
+        if (str != null && !"".equals(str)) {
+            int width = Integer.parseInt(str);
+            viewport.setWidth(width);
+        }
         return viewport;
     }
 
@@ -544,15 +569,19 @@ class TreeLoader {
                 //System.out.println(obj.getNodeName());
                 Element rootEle = (Element) obj;
                 String space = rootEle.getAttribute("xmlns");
-                if (space.equals(svgNS)) {
+                if (svgNS.equals(space)) {
                     try {
-                        doc = javax.xml.parsers.DocumentBuilderFactory.newInstance().
-                              newDocumentBuilder().newDocument();
+                        DocumentBuilderFactory fact =
+                          DocumentBuilderFactory.newInstance();
+                        fact.setNamespaceAware(true);
+
+                        doc = fact. newDocumentBuilder().newDocument();
                         Node node = doc.importNode(obj, true);
                         doc.appendChild(node);
                         DOMImplementation impl =
                           SVGDOMImplementation.getDOMImplementation();
                         // due to namespace problem attributes are not cloned
+                        // serializing causes an npe
                         //doc = DOMUtilities.deepCloneDocument(doc, impl);
 
                         ForeignObject fo = new ForeignObject(doc, svgNS);
@@ -562,8 +591,10 @@ class TreeLoader {
                     }
                 } else {
                     try {
-                        doc = javax.xml.parsers.DocumentBuilderFactory.newInstance().
-                              newDocumentBuilder().newDocument();
+                        DocumentBuilderFactory fact =
+                          DocumentBuilderFactory.newInstance();
+                        fact.setNamespaceAware(true);
+                        doc = fact. newDocumentBuilder().newDocument();
                         Node node = doc.importNode(obj, true);
                         doc.appendChild(node);
                         ForeignObject fo = new ForeignObject(doc, space);
@@ -602,14 +633,28 @@ class TreeLoader {
         String rt = root.getAttribute("ruleThickness");
         int thick = Integer.parseInt(rt);
         leader.setRuleThickness(thick);
+        rt = root.getAttribute("width");
+        if (rt != null && !"".equals(rt)) {
+            thick = Integer.parseInt(rt);
+            leader.setWidth(thick);
+        }
+        leader.setOffset(currentFontState.getCapHeight());
         addProperties(root, leader);
         return leader;
     }
 
     Word getWord(Element root) {
-        String url = root.getAttribute("url");
+        String str = getString(root);
         Word word = new Word();
+        word.setWord(str);
         addProperties(root, word);
+        int width = 0;
+        for (int count = 0; count < str.length(); count++) {
+            width += currentFontState.width(str.charAt(count));
+        }
+        word.setWidth(width);
+        word.setOffset(currentFontState.getCapHeight());
+
         return word;
     }