From af113ef5a388ac87b4f1dac63e07ffc7160f8b14 Mon Sep 17 00:00:00 2001 From: Keiron Liddle Date: Fri, 26 Oct 2001 09:27:00 +0000 Subject: [PATCH] updates to area tree and reading/rendering with xml added user agent, xml handlers added inline level property git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@194521 13f79535-47bb-0310-9956-ffa450edef68 --- src/org/apache/fop/apps/XSLTInputHandler.java | 4 + src/org/apache/fop/area/Area.java | 6 +- src/org/apache/fop/area/AreaTree.java | 47 +- src/org/apache/fop/area/BeforeFloat.java | 11 + src/org/apache/fop/area/Block.java | 17 +- src/org/apache/fop/area/BodyRegion.java | 13 + src/org/apache/fop/area/Flow.java | 4 + src/org/apache/fop/area/Footnote.java | 11 + src/org/apache/fop/area/LineArea.java | 30 +- src/org/apache/fop/area/LineProperty.java | 13 + src/org/apache/fop/area/MainReference.java | 7 +- src/org/apache/fop/area/Page.java | 4 +- src/org/apache/fop/area/PageViewport.java | 23 +- src/org/apache/fop/area/Property.java | 33 ++ src/org/apache/fop/area/Region.java | 3 +- src/org/apache/fop/area/RegionViewport.java | 32 +- src/org/apache/fop/area/Span.java | 10 +- src/org/apache/fop/area/inline/Container.java | 8 +- .../apache/fop/area/inline/ForeignObject.java | 12 + src/org/apache/fop/area/inline/Image.java | 10 +- .../apache/fop/area/inline/InlineArea.java | 25 ++ src/org/apache/fop/area/inline/Leader.java | 35 ++ src/org/apache/fop/area/inline/Viewport.java | 39 +- src/org/apache/fop/area/inline/Word.java | 5 + src/org/apache/fop/fo/FOUserAgent.java | 62 ++- src/org/apache/fop/pdf/PDFDocument.java | 6 +- .../apache/fop/render/AbstractRenderer.java | 66 ++- src/org/apache/fop/render/Renderer.java | 22 +- .../apache/fop/render/RendererContext.java | 37 ++ src/org/apache/fop/render/XMLHandler.java | 26 ++ .../apache/fop/render/pdf/PDFRenderer.java | 68 ++- .../apache/fop/render/xml/XMLRenderer.java | 298 ++++++++++--- .../apache/fop/render/xml/XMLXMLHandler.java | 161 +++++++ src/org/apache/fop/tools/AreaTreeBuilder.java | 416 ++++++++++++++++-- 34 files changed, 1380 insertions(+), 184 deletions(-) create mode 100644 src/org/apache/fop/area/LineProperty.java create mode 100644 src/org/apache/fop/area/Property.java create mode 100644 src/org/apache/fop/render/RendererContext.java create mode 100644 src/org/apache/fop/render/XMLHandler.java create mode 100644 src/org/apache/fop/render/xml/XMLXMLHandler.java diff --git a/src/org/apache/fop/apps/XSLTInputHandler.java b/src/org/apache/fop/apps/XSLTInputHandler.java index 2b7e58fee..89ba30876 100644 --- a/src/org/apache/fop/apps/XSLTInputHandler.java +++ b/src/org/apache/fop/apps/XSLTInputHandler.java @@ -21,6 +21,10 @@ import java.io.*; // FOP import org.apache.fop.tools.xslt.XSLTransform; +/* +add url constructer +*/ + /** * XSLTInputHandler basically takes an xmlfile and transforms it with an xsltfile * and the resulting xsl:fo document is input for Fop. diff --git a/src/org/apache/fop/area/Area.java b/src/org/apache/fop/area/Area.java index 3d43a5f5b..6a0318275 100644 --- a/src/org/apache/fop/area/Area.java +++ b/src/org/apache/fop/area/Area.java @@ -7,10 +7,12 @@ package org.apache.fop.area; +import java.io.Serializable; + /** - * base object for all areas + * Base object for all areas. */ -public class Area { +public class Area implements Serializable { // stacking directions public static final int LR = 0; public static final int RL = 1; diff --git a/src/org/apache/fop/area/AreaTree.java b/src/org/apache/fop/area/AreaTree.java index 6f3157773..b8544878c 100644 --- a/src/org/apache/fop/area/AreaTree.java +++ b/src/org/apache/fop/area/AreaTree.java @@ -9,6 +9,24 @@ package org.apache.fop.area; import java.util.ArrayList; + +/** + * Area tree for formatting objects. + * + * Concepts: + * The area tree is to be as small as possible. With minimal classes + * and data to fully represent an area tree for formatting objects. + * The area tree needs to be simple to render and follow the spec + * closely. + * This area tree has the concept of page sequences. + * Where ever possible information is discarded or optimised to + * keep memory use low. The data is also organised to make it + * possible for renderers to minimise their output. + * A page can be saved if not fully resolved and once rendered + * a page contains only size and id reference information. + * The area tree pages are organised in a model that depends on the + * type of renderer. + */ public class AreaTree { // allows for different models to deal with adding/rendering // in different situations @@ -40,15 +58,6 @@ public class AreaTree { public abstract void addPage(PageViewport page); } - // this queues pages and will call the render listener - // when the page is ready to be rendered - // if the render supports out of order rendering - // then a ready page is rendered immediately - public static class RenderPagesModel extends AreaTreeModel { - public void startPageSequence(Area title) {} - public void addPage(PageViewport page) {} - } - // this class stores all the pages in the document // for interactive agents public static class StorePagesModel extends AreaTreeModel { @@ -89,10 +98,20 @@ public class AreaTree { return (PageViewport) sequence.get(count); } } -} -abstract class PageRenderListener { - public abstract void startPageSequence(Area title); - public abstract void preparePage(PageViewport page); - public abstract void renderPage(PageViewport page); + // this queues pages and will call the render listener + // when the page is ready to be rendered + // if the render supports out of order rendering + // then a ready page is rendered immediately + public static class RenderPagesModel extends StorePagesModel { + public void startPageSequence(Area title) {} + public void addPage(PageViewport page) {} + } + + public static abstract class PageRenderListener { + public abstract void renderPage(RenderPagesModel model, + int pageseq, int count); + } + } + diff --git a/src/org/apache/fop/area/BeforeFloat.java b/src/org/apache/fop/area/BeforeFloat.java index f313eb559..034d467d2 100644 --- a/src/org/apache/fop/area/BeforeFloat.java +++ b/src/org/apache/fop/area/BeforeFloat.java @@ -21,6 +21,17 @@ public class BeforeFloat extends Area { ArrayList blocks = null; + public void addBlock(Block block) { + if (blocks == null) { + blocks = new ArrayList(); + } + blocks.add(block); + } + + public void setSeparator(Block sep) { + separator = sep; + } + public List getBlocks() { return blocks; } diff --git a/src/org/apache/fop/area/Block.java b/src/org/apache/fop/area/Block.java index cf070497f..9a7e3b30c 100644 --- a/src/org/apache/fop/area/Block.java +++ b/src/org/apache/fop/area/Block.java @@ -7,6 +7,7 @@ package org.apache.fop.area; +import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.awt.geom.Rectangle2D; @@ -17,7 +18,7 @@ import java.awt.geom.Rectangle2D; // or by relative to the parent for floats, tables and lists // cacheable object // has id information -public class Block extends Area { +public class Block extends Area implements Serializable { // normally stacked with other blocks public static final int STACK = 0; // placed relative to the parent area @@ -79,4 +80,18 @@ public class Block extends Area { public int getPositioning() { return positioning; } + + // store properties in array list, need better solution + ArrayList props = null; + + public void addProperty(Property prop) { + if (props == null) { + props = new ArrayList(); + } + props.add(prop); + } + + public List getPropertyList() { + return props; + } } diff --git a/src/org/apache/fop/area/BodyRegion.java b/src/org/apache/fop/area/BodyRegion.java index 0661ebdd7..e6e886404 100644 --- a/src/org/apache/fop/area/BodyRegion.java +++ b/src/org/apache/fop/area/BodyRegion.java @@ -16,6 +16,19 @@ public class BodyRegion extends Region { super(BODY); } + public void setBeforeFloat(BeforeFloat bf) { + beforeFloat = bf; + } + + public void setMainReference(MainReference mr) { + mainReference = mr; + } + + public void setFootnote(Footnote foot) { + footnote = foot; + } + + public BeforeFloat getBeforeFloat() { return beforeFloat; } diff --git a/src/org/apache/fop/area/Flow.java b/src/org/apache/fop/area/Flow.java index d054a51d5..6cfa09a53 100644 --- a/src/org/apache/fop/area/Flow.java +++ b/src/org/apache/fop/area/Flow.java @@ -18,6 +18,10 @@ public class Flow extends Area { int stacking = TB; int width; + public void addBlock(Block block) { + blocks.add(block); + } + public List getBlocks() { return blocks; } diff --git a/src/org/apache/fop/area/Footnote.java b/src/org/apache/fop/area/Footnote.java index 1baf1502c..dcd62ecdf 100644 --- a/src/org/apache/fop/area/Footnote.java +++ b/src/org/apache/fop/area/Footnote.java @@ -23,6 +23,17 @@ public class Footnote { ArrayList blocks = null; + public void setSeparator(Block sep) { + separator = sep; + } + + public void addBlock(Block block) { + if (blocks == null) { + blocks = new ArrayList(); + } + blocks.add(block); + } + public Block getSeparator() { return separator; } diff --git a/src/org/apache/fop/area/LineArea.java b/src/org/apache/fop/area/LineArea.java index 2e39b5175..8184d332a 100644 --- a/src/org/apache/fop/area/LineArea.java +++ b/src/org/apache/fop/area/LineArea.java @@ -31,6 +31,14 @@ public class LineArea extends Area { ArrayList inlineAreas = new ArrayList(); + public void setHeight(int height) { + lineHeight = height; + } + + public int getHeight() { + return lineHeight; + } + public void addInlineArea(InlineArea area) { inlineAreas.add(area); } @@ -38,11 +46,19 @@ public class LineArea extends Area { public List getInlineAreas() { return inlineAreas; } + + // store properties in array list, need better solution + ArrayList props = null; + + public void addProperty(Property prop) { + if (props == null) { + props = new ArrayList(); + } + props.add(prop); + } + + public List getPropertyList() { + return props; + } } -/* -class LineProperty { - int propType; - int[] range; - Object data; -} -*/ + diff --git a/src/org/apache/fop/area/LineProperty.java b/src/org/apache/fop/area/LineProperty.java new file mode 100644 index 000000000..d5eb3dad9 --- /dev/null +++ b/src/org/apache/fop/area/LineProperty.java @@ -0,0 +1,13 @@ +/* + * $Id$ + * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.area; + +public class LineProperty extends Property { + int[] range; +} + diff --git a/src/org/apache/fop/area/MainReference.java b/src/org/apache/fop/area/MainReference.java index 4c705637f..b18008b42 100644 --- a/src/org/apache/fop/area/MainReference.java +++ b/src/org/apache/fop/area/MainReference.java @@ -7,15 +7,20 @@ package org.apache.fop.area; +import java.io.Serializable; import java.util.ArrayList; import java.util.List; // the area that contains the flow via the span areas -public class MainReference { +public class MainReference implements Serializable { List spanAreas = new ArrayList(); int columnGap; int width; + public void addSpan(Span span) { + spanAreas.add(span); + } + public List getSpans() { return spanAreas; } diff --git a/src/org/apache/fop/area/Page.java b/src/org/apache/fop/area/Page.java index 059d98150..e8b1bfd62 100644 --- a/src/org/apache/fop/area/Page.java +++ b/src/org/apache/fop/area/Page.java @@ -7,7 +7,9 @@ package org.apache.fop.area; -public class Page { +import java.io.Serializable; + +public class Page implements Serializable { // contains before, start, body, end and after regions RegionViewport regionBefore = null; RegionViewport regionStart = null; diff --git a/src/org/apache/fop/area/PageViewport.java b/src/org/apache/fop/area/PageViewport.java index 29354eda2..18e8ba4ff 100644 --- a/src/org/apache/fop/area/PageViewport.java +++ b/src/org/apache/fop/area/PageViewport.java @@ -8,6 +8,8 @@ package org.apache.fop.area; import java.awt.geom.Rectangle2D; +import java.io.ObjectOutputStream; +import java.io.ObjectInputStream; import java.util.ArrayList; // this is the level that creates the page @@ -15,17 +17,36 @@ import java.util.ArrayList; public class PageViewport { Page page; Rectangle2D viewArea; + boolean clip = false; - public PageViewport(Page p) { + public PageViewport(Page p, Rectangle2D bounds) { page = p; + viewArea = bounds; } // this list is only used when the page is discarded // the information is kept for future reference ArrayList idReferences = null; + public void setClip(boolean c) { + clip = c; + } + + public Rectangle2D getViewArea() { + return viewArea; + } + // a viewport area for page and reference areas public Page getPage() { return page; } + + public void savePage(ObjectOutputStream out) throws Exception { + out.writeObject(page); + page = null; + } + + public void loadPage(ObjectInputStream in) throws Exception { + page = (Page) in.readObject(); + } } diff --git a/src/org/apache/fop/area/Property.java b/src/org/apache/fop/area/Property.java new file mode 100644 index 000000000..3b9a836e0 --- /dev/null +++ b/src/org/apache/fop/area/Property.java @@ -0,0 +1,33 @@ +/* + * $Id$ + * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.area; + +import java.io.Serializable; + +// properties should be serialized by the holder +public class Property implements Serializable { + public static final int ID_LINK = 0; + public static final int INTERNAL_LINK = 1; //resolved + public static final int EXTERNAL_LINK = 2; + public static final int FONT_FAMILY = 3; + public static final int FONT_SIZE = 4; + public static final int FONT_WEIGHT = 5; + public static final int FONT_STYLE = 6; + public static final int COLOR = 7; + public static final int ID_AREA = 8; + public static final int BACKGROUND = 9; + public static final int UNDERLINE = 10; + public static final int OVERLINE = 11; + public static final int LINETHROUGH = 12; + public static final int OFFSET = 13; + public static final int SHADOW = 14; + public int propType; + public Object data; + +} + diff --git a/src/org/apache/fop/area/Region.java b/src/org/apache/fop/area/Region.java index d51da6e2d..47f2dbfd9 100644 --- a/src/org/apache/fop/area/Region.java +++ b/src/org/apache/fop/area/Region.java @@ -7,10 +7,11 @@ package org.apache.fop.area; +import java.io.Serializable; import java.util.ArrayList; import java.util.List; -public class Region { +public class Region implements Serializable { public static final int BEFORE = 0; public static final int START = 1; public static final int BODY = 2; diff --git a/src/org/apache/fop/area/RegionViewport.java b/src/org/apache/fop/area/RegionViewport.java index 3a90bb95e..43b320399 100644 --- a/src/org/apache/fop/area/RegionViewport.java +++ b/src/org/apache/fop/area/RegionViewport.java @@ -8,20 +8,48 @@ package org.apache.fop.area; import java.awt.geom.Rectangle2D; +import java.io.Serializable; +import java.io.IOException; -public class RegionViewport { +public class RegionViewport implements Serializable { // this rectangle is relative to the page Rectangle2D regionArea; - boolean clip; + boolean clip = false; Region region; + public RegionViewport(Rectangle2D area) { + regionArea = area; + } + public void setRegion(Region reg) { region = reg; } + public Rectangle2D getViewArea() { + return regionArea; + } + public Region getRegion() { return region; } + private void writeObject(java.io.ObjectOutputStream out) + throws IOException { + out.writeFloat((float) regionArea.getX()); + out.writeFloat((float) regionArea.getY()); + out.writeFloat((float) regionArea.getWidth()); + out.writeFloat((float) regionArea.getHeight()); + out.writeBoolean(clip); + out.writeObject(region); + } + + private void readObject(java.io.ObjectInputStream in) + throws IOException, ClassNotFoundException { + regionArea = new Rectangle2D.Float(in.readFloat(), in.readFloat(), + in.readFloat(), in.readFloat()); + clip = in.readBoolean(); + region = (Region) in.readObject(); + } + } diff --git a/src/org/apache/fop/area/Span.java b/src/org/apache/fop/area/Span.java index 28dddc7da..fc8b45913 100644 --- a/src/org/apache/fop/area/Span.java +++ b/src/org/apache/fop/area/Span.java @@ -12,9 +12,17 @@ import java.util.ArrayList; // this is a reference area block area with 0 border and padding public class Span extends Area { // the list of flow reference areas in this span area - ArrayList flowAreas = new ArrayList(); + ArrayList flowAreas; int height; + public Span(int cols) { + flowAreas = new ArrayList(cols); + } + + public void addFlow(Flow flow) { + flowAreas.add(flow); + } + public int getColumnCount() { return flowAreas.size(); } diff --git a/src/org/apache/fop/area/inline/Container.java b/src/org/apache/fop/area/inline/Container.java index 54a9ac493..76c987e21 100644 --- a/src/org/apache/fop/area/inline/Container.java +++ b/src/org/apache/fop/area/inline/Container.java @@ -7,12 +7,14 @@ package org.apache.fop.area.inline; +import org.apache.fop.area.Area; +import org.apache.fop.area.Block; import org.apache.fop.render.Renderer; import java.util.List; import java.util.ArrayList; -public class Container extends InlineArea { +public class Container extends Area { ArrayList blocks = new ArrayList(); // this is an inline area that can have blocks as children @@ -21,6 +23,10 @@ public class Container extends InlineArea { renderer.renderContainer(this); } + public void addBlock(Block block) { + blocks.add(block); + } + public List getBlocks() { return blocks; } diff --git a/src/org/apache/fop/area/inline/ForeignObject.java b/src/org/apache/fop/area/inline/ForeignObject.java index b67575737..54f35f73c 100644 --- a/src/org/apache/fop/area/inline/ForeignObject.java +++ b/src/org/apache/fop/area/inline/ForeignObject.java @@ -18,4 +18,16 @@ public class ForeignObject extends Area { // dom object // height, width + public ForeignObject(Document d, String ns) { + doc = d; + namespace = ns; + } + + public Document getDocument() { + return doc; + } + + public String getNameSpace() { + return namespace; + } } diff --git a/src/org/apache/fop/area/inline/Image.java b/src/org/apache/fop/area/inline/Image.java index 4cf1b7f72..3899997a5 100644 --- a/src/org/apache/fop/area/inline/Image.java +++ b/src/org/apache/fop/area/inline/Image.java @@ -10,8 +10,16 @@ package org.apache.fop.area.inline; import org.apache.fop.area.Area; // cacheable object +// image object, mime type, url public class Image extends Area { + String url; - // image object, mime type, url + public Image(String u) { + url = u; + } + + public String getURL() { + return url; + } } diff --git a/src/org/apache/fop/area/inline/InlineArea.java b/src/org/apache/fop/area/inline/InlineArea.java index 3c61377dc..aa229316f 100644 --- a/src/org/apache/fop/area/inline/InlineArea.java +++ b/src/org/apache/fop/area/inline/InlineArea.java @@ -8,8 +8,19 @@ package org.apache.fop.area.inline; import org.apache.fop.area.Area; +import org.apache.fop.area.Property; import org.apache.fop.render.Renderer; +import java.util.List; +import java.util.ArrayList; + +/** + * Inline Area + * This area is for all inline areas that can be placed + * in a line area. + * Extensions of this class should render themselves with the + * requested renderer. + */ public class InlineArea extends Area { int width; int height; @@ -17,6 +28,9 @@ public class InlineArea extends Area { int verticalPosition; // width, height, vertical alignment + // store properties in array list, need better solution + ArrayList props = null; + // inline areas are expected to implement this method // to render themselves public void render(Renderer renderer) { @@ -30,4 +44,15 @@ public class InlineArea extends Area { public int getWidth() { return width; } + + public void addProperty(Property prop) { + if (props == null) { + props = new ArrayList(); + } + props.add(prop); + } + + public List getPropertyList() { + return props; + } } diff --git a/src/org/apache/fop/area/inline/Leader.java b/src/org/apache/fop/area/inline/Leader.java index f31949acb..2475cac80 100644 --- a/src/org/apache/fop/area/inline/Leader.java +++ b/src/org/apache/fop/area/inline/Leader.java @@ -7,6 +7,8 @@ package org.apache.fop.area.inline; +import org.apache.fop.render.Renderer; + public class Leader extends Stretch { // pattern, length min opt max @@ -16,4 +18,37 @@ public class Leader extends Stretch { // if space replaced with a space // otherwise this is a holder for a line + public static final int DOTTED = 0; + public static final int DASHED = 1; + public static final int SOLID = 2; + public static final int DOUBLE = 3; + public static final int GROOVE = 4; + public static final int RIDGE = 5; + + int ruleStyle = SOLID; + int ruleThickness = 1000; + + public Leader() { + + } + + public void setRuleStyle(int style) { + ruleStyle = style; + } + + public void setRuleThickness(int rt) { + ruleThickness = rt; + } + + public int getRuleStyle() { + return ruleStyle; + } + + public int getRuleThickness() { + return ruleThickness; + } + + public void render(Renderer renderer) { + renderer.renderLeader(this); + } } diff --git a/src/org/apache/fop/area/inline/Viewport.java b/src/org/apache/fop/area/inline/Viewport.java index a7458c53a..5e1ce23d0 100644 --- a/src/org/apache/fop/area/inline/Viewport.java +++ b/src/org/apache/fop/area/inline/Viewport.java @@ -8,15 +8,52 @@ package org.apache.fop.area.inline; import org.apache.fop.area.Area; +import org.apache.fop.render.Renderer; +import java.io.IOException; import java.awt.geom.Rectangle2D; public class Viewport extends InlineArea { - // contents could be foreign object or image + // contents could be container, foreign object or image Area content; // an inline-level viewport area for graphic and instream foreign object boolean clip = false; // position relative to this area Rectangle2D contentPosition; + public Viewport(Area child) { + content = child; + } + + public Area getContent() { + return content; + } + + public void render(Renderer renderer) { + renderer.renderViewport(this); + } + + private void writeObject(java.io.ObjectOutputStream out) + throws IOException { + out.writeBoolean(contentPosition != null); + if (contentPosition != null) { + out.writeFloat((float) contentPosition.getX()); + out.writeFloat((float) contentPosition.getY()); + out.writeFloat((float) contentPosition.getWidth()); + out.writeFloat((float) contentPosition.getHeight()); + } + out.writeBoolean(clip); + out.writeObject(content); + } + + private void readObject(java.io.ObjectInputStream in) + throws IOException, ClassNotFoundException { + if (in.readBoolean()) { + contentPosition = new Rectangle2D.Float(in.readFloat(), + in.readFloat(), in.readFloat(), in.readFloat()); + } + clip = in.readBoolean(); + content = (Area) in.readObject(); + } + } diff --git a/src/org/apache/fop/area/inline/Word.java b/src/org/apache/fop/area/inline/Word.java index 73c9ec26d..070af40ff 100644 --- a/src/org/apache/fop/area/inline/Word.java +++ b/src/org/apache/fop/area/inline/Word.java @@ -7,9 +7,14 @@ package org.apache.fop.area.inline; +import org.apache.fop.render.Renderer; + public class Word extends InlineArea { // character info: font, char spacing, colour, baseline String word; + public void render(Renderer renderer) { + renderer.renderWord(this); + } } diff --git a/src/org/apache/fop/fo/FOUserAgent.java b/src/org/apache/fop/fo/FOUserAgent.java index b9f74a9f6..05ae93456 100644 --- a/src/org/apache/fop/fo/FOUserAgent.java +++ b/src/org/apache/fop/fo/FOUserAgent.java @@ -7,13 +7,18 @@ package org.apache.fop.fo; +import org.apache.fop.render.XMLHandler; +import org.apache.fop.render.RendererContext; + import org.w3c.dom.*; +import java.util.HashMap; + /** * The User Agent for fo. * This user agent is used by the processing to obtain user configurable * options. - * + * * Renderer specific extensions (that do not produce normal areas on * the output) will be done like so: * The extension will create an area, custom if necessary @@ -24,14 +29,55 @@ import org.w3c.dom.*; * These areas may contain resolveable areas that will be processed * with other resolveable areas */ -public interface FOUserAgent { -public void renderXML(RendererContext ctx, Document doc, String namespace); +public class FOUserAgent { + HashMap defaults = new HashMap(); + HashMap handlers = new HashMap(); -} + /** + * Set the default xml handler for the given mime type. + */ + public void setDefaultXMLHandler(String mime, XMLHandler handler) { + defaults.put(mime, handler); + } -class RendererContext { -String getMimeType() { -return null; -} + /** + * Add an xml handler for the given mime type and xml namespace. + */ + public void addXMLHandler(String mime, String ns, XMLHandler handler) { + HashMap mh = (HashMap) handlers.get(mime); + if (mh == null) { + mh = new HashMap(); + handlers.put(mime, mh); + } + mh.put(ns, handler); + } + + /** + * Render the xml document with the given xml namespace. + * The Render Context is by the handle to render into the current + * rendering target. + */ + public void renderXML(RendererContext ctx, Document doc, + String namespace) { + String mime = ctx.getMimeType(); + HashMap mh = (HashMap) handlers.get(mime); + XMLHandler handler = null; + if (mh != null) { + handler = (XMLHandler) mh.get(namespace); + } + if (handler == null) { + handler = (XMLHandler) defaults.get(mime); + } + if (handler != null) { + try { + handler.handleXML(ctx, doc, namespace); + } catch (Throwable t) { + // could not handle document + //t.printStackTrace(); + } + } else { + // no handler found for document + } + } } diff --git a/src/org/apache/fop/pdf/PDFDocument.java b/src/org/apache/fop/pdf/PDFDocument.java index cdf039b9f..09dcfd277 100644 --- a/src/org/apache/fop/pdf/PDFDocument.java +++ b/src/org/apache/fop/pdf/PDFDocument.java @@ -937,7 +937,7 @@ public class PDFDocument { * @return the created /Page object */ public PDFPage makePage(PDFResources resources, PDFStream contents, - int pagewidth, int pageheight, Page currentPage) { + int pagewidth, int pageheight) { /* * create a PDFPage with the next object number, the given @@ -959,7 +959,7 @@ public class PDFDocument { } pendingLinks = null; } - +/* if (currentPage != null) { Enumeration enum = currentPage.getIDList().elements(); while (enum.hasMoreElements()) { @@ -968,7 +968,7 @@ public class PDFDocument { page.referencePDF()); } } - +*/ /* add it to the list of objects */ this.objects.addElement(page); diff --git a/src/org/apache/fop/render/AbstractRenderer.java b/src/org/apache/fop/render/AbstractRenderer.java index 8d99f6767..a76a32f5e 100644 --- a/src/org/apache/fop/render/AbstractRenderer.java +++ b/src/org/apache/fop/render/AbstractRenderer.java @@ -28,7 +28,8 @@ import java.util.List; * Abstract base class for all renderers. * The Abstract renderer does all the top level processing * of the area tree and adds some abstract methods to handle - * viewports. + * viewports. This keeps track of the current block and inline + * position. */ public abstract class AbstractRenderer implements Renderer { protected Logger log; @@ -48,7 +49,7 @@ public abstract class AbstractRenderer implements Renderer { } public void setUserAgent(FOUserAgent agent) { -userAgent = agent; + userAgent = agent; } public void setOptions(HashMap opt) { @@ -64,7 +65,7 @@ userAgent = agent; FOPException { Page p = page.getPage(); -renderPageAreas(p); + renderPageAreas(p); } protected void renderPageAreas(Page page) { @@ -85,13 +86,13 @@ renderPageAreas(p); // the region may clip the area and it establishes // a position from where the region is placed protected void renderRegionViewport(RegionViewport port) { - if(port != null) { - Region region = port.getRegion(); - if (region.getRegionClass() == Region.BODY) { - renderBodyRegion((BodyRegion) region); - } else { - renderRegion(region); - } + if (port != null) { + Region region = port.getRegion(); + if (region.getRegionClass() == Region.BODY) { + renderBodyRegion((BodyRegion) region); + } else { + renderRegion(region); + } } } @@ -104,17 +105,17 @@ renderPageAreas(p); protected void renderBodyRegion(BodyRegion region) { BeforeFloat bf = region.getBeforeFloat(); -if(bf != null) { - renderBeforeFloat(bf); -} + if (bf != null) { + renderBeforeFloat(bf); + } MainReference mr = region.getMainReference(); -if(mr != null) { - renderMainReference(mr); -} + if (mr != null) { + renderMainReference(mr); + } Footnote foot = region.getFootnote(); -if(foot != null) { - renderFootnote(foot); -} + if (foot != null) { + renderFootnote(foot); + } } protected void renderBeforeFloat(BeforeFloat bf) { @@ -180,6 +181,8 @@ if(foot != null) { if (children == null) { // simply move position } else { + // a line area is rendered from the top left position + // of the line, each inline object is offset from there for (int count = 0; count < children.size(); count++) { LineArea line = (LineArea) children.get(count); renderLineArea(line); @@ -201,9 +204,26 @@ if(foot != null) { } + public void renderViewport(Viewport viewport) { + Area content = viewport.getContent(); + if (content instanceof Image) { + renderImage((Image) content); + } else if (content instanceof Container) { + renderContainer((Container) content); + } else if (content instanceof ForeignObject) { + renderForeignObject((ForeignObject) content); + } + } + + public void renderImage(Image image) { + } + public void renderContainer(Container cont) { List blocks = cont.getBlocks(); renderBlocks(blocks); + } + + public void renderForeignObject(ForeignObject fo) { } @@ -219,6 +239,14 @@ if(foot != null) { currentBlockIPPosition += space.getWidth(); } + public void renderLeader(Leader area) { + currentBlockIPPosition += area.getWidth(); + } + + public void renderWord(Word word) { + currentBlockIPPosition += word.getWidth(); + } + protected void renderBlocks(List blocks) { for (int count = 0; count < blocks.size(); count++) { Block block = (Block) blocks.get(count); diff --git a/src/org/apache/fop/render/Renderer.java b/src/org/apache/fop/render/Renderer.java index 6568e07db..fe4af30f6 100644 --- a/src/org/apache/fop/render/Renderer.java +++ b/src/org/apache/fop/render/Renderer.java @@ -32,11 +32,9 @@ import java.util.HashMap; */ public interface Renderer { - public void startRenderer(OutputStream outputStream) - throws IOException; + public void startRenderer(OutputStream outputStream) throws IOException; - public void stopRenderer() - throws IOException; + public void stopRenderer() throws IOException; /** * Set the logger @@ -65,25 +63,19 @@ public interface Renderer { public void startPageSequence(Title seqTitle); - public void renderPage(PageViewport page) - throws IOException, FOPException; + public void renderPage(PageViewport page) throws IOException, FOPException; + public void renderViewport(Viewport viewport); public void renderContainer(Container cont); -/* - public void renderInlineViewport(org.apache.fop.area.inline.Viewport view); public void renderWord(Word area); -*/ - public void renderCharacter(org.apache.fop.area.inline.Character ch); - public void renderInlineSpace(Space space); -/* - public void renderForeignObject(ForeignObject area); + public void renderCharacter( + org.apache.fop.area.inline.Character ch); - public void renderImage(Image area); + public void renderInlineSpace(Space space); public void renderLeader(Leader area); -*/ } diff --git a/src/org/apache/fop/render/RendererContext.java b/src/org/apache/fop/render/RendererContext.java new file mode 100644 index 000000000..1fa2a1616 --- /dev/null +++ b/src/org/apache/fop/render/RendererContext.java @@ -0,0 +1,37 @@ +/* + * $Id$ + * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ +package org.apache.fop.render; + +import java.util.HashMap; + +/** + * The Render Context for external handlers. + * This provides a rendering context so that external handlers + * can get information to be able to render to the render target. + */ +public class RendererContext { + String mime; + HashMap props = new HashMap(); + + public RendererContext(String m) { + mime = m; + } + + public String getMimeType() { + return mime; + } + + public void setProperty(String name, Object val) { + props.put(name, val); + } + + public Object getProperty(String prop) { + return props.get(prop); + } + +} + diff --git a/src/org/apache/fop/render/XMLHandler.java b/src/org/apache/fop/render/XMLHandler.java new file mode 100644 index 000000000..f734efc1f --- /dev/null +++ b/src/org/apache/fop/render/XMLHandler.java @@ -0,0 +1,26 @@ +/* + * $Id$ + * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.render; + +import org.apache.log.Logger; + +import org.w3c.dom.Document; + +/** + */ +public interface XMLHandler { + + /** + * Handle an external xml document inside a Foreign Object Area + * This may throw an exception if for some reason it cannot be handled. + * The caller is expected to deal with this exception. + */ + public void handleXML(RendererContext context, Document doc, + String ns) throws Exception; +} + diff --git a/src/org/apache/fop/render/pdf/PDFRenderer.java b/src/org/apache/fop/render/pdf/PDFRenderer.java index 581e4514c..3a7d3fbef 100644 --- a/src/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/org/apache/fop/render/pdf/PDFRenderer.java @@ -29,6 +29,24 @@ import org.w3c.dom.Document; import java.io.IOException; import java.io.OutputStream; +import java.awt.geom.Rectangle2D; + +/* +TODO: + +viewport clipping +word rendering and optimistion +pdf state optimistation +line and border +leader +background pattern +user agent xml (svg) rendering +orientation +writing mode +text decoration + + */ + /** * Renderer that renders areas to PDF * @@ -40,6 +58,10 @@ public class PDFRenderer extends PrintRenderer { */ protected PDFDocument pdfDoc; + protected String producer; + + protected OutputStream ostream; + /** * the /Resources object of the PDF document being created */ @@ -80,7 +102,7 @@ public class PDFRenderer extends PrintRenderer { int prevWordX = 0; /** - * The width of the previous word. Used to calculate space between + * The width of the previous word. Used to calculate space between */ int prevWordWidth = 0; @@ -93,7 +115,6 @@ public class PDFRenderer extends PrintRenderer { * create the PDF renderer */ public PDFRenderer() { - this.pdfDoc = new PDFDocument(); } /** @@ -101,23 +122,50 @@ public class PDFRenderer extends PrintRenderer { * * @param producer string indicating application producing PDF */ - public void setProducer(String producer) { - this.pdfDoc.setProducer(producer); + public void setProducer(String prod) { + producer = prod; } - public void startRenderer(OutputStream stream) - throws IOException { + public void startRenderer(OutputStream stream) throws IOException { + ostream = stream; + this.pdfDoc = new PDFDocument(); + this.pdfDoc.setProducer(producer); pdfDoc.outputHeader(stream); } - public void stopRenderer() - throws IOException { + public void stopRenderer() throws IOException { + FontSetup.addToResources(this.pdfDoc, fontInfo); + pdfDoc.outputTrailer(ostream); + + this.pdfDoc = null; + ostream = null; } - public void renderPage(PageViewport page) throws IOException, FOPException { + /** + * This method creates a pdf stream for the current page + * uses it as the contents of a new page. The page is wriiten + * immediately to the output stream. + */ + public void renderPage(PageViewport page) throws IOException, + FOPException { + + this.pdfResources = this.pdfDoc.getResources(); + + currentStream = this.pdfDoc.makeStream(); + currentStream.add("BT\n"); Page p = page.getPage(); -renderPageAreas(p); + renderPageAreas(p); + + currentStream.add("ET\n"); + + Rectangle2D bounds = page.getViewArea(); + double w = bounds.getWidth(); + double h = bounds.getHeight(); + currentPage = this.pdfDoc.makePage(this.pdfResources, currentStream, + (int) Math.round(w / 1000), (int) Math.round(h / 1000)); + + this.pdfDoc.output(ostream); } diff --git a/src/org/apache/fop/render/xml/XMLRenderer.java b/src/org/apache/fop/render/xml/XMLRenderer.java index 10b15127e..33fa2ed9a 100644 --- a/src/org/apache/fop/render/xml/XMLRenderer.java +++ b/src/org/apache/fop/render/xml/XMLRenderer.java @@ -11,11 +11,14 @@ package org.apache.fop.render.xml; import org.apache.fop.svg.*; import org.apache.fop.render.Renderer; import org.apache.fop.render.AbstractRenderer; +import org.apache.fop.render.RendererContext; +import org.apache.fop.render.XMLHandler; import org.apache.fop.image.ImageArea; import org.apache.fop.area.*; import org.apache.fop.area.inline.*; import org.apache.fop.pdf.*; import org.apache.fop.fo.properties.LeaderPattern; +import org.apache.fop.fo.FOUserAgent; import org.apache.fop.layout.FontInfo; import org.apache.fop.apps.FOPException; @@ -28,12 +31,18 @@ import java.io.OutputStream; import java.util.Enumeration; import java.util.HashMap; import java.util.List; +import java.awt.geom.Rectangle2D; + +import org.w3c.dom.Document; /** * Renderer that renders areas to XML for debugging purposes. */ public class XMLRenderer extends AbstractRenderer { -boolean startedSequence = false; + public static final String mimeType = "text/xml"; + + boolean startedSequence = false; + RendererContext context; public void setProducer(String producer) { } @@ -58,7 +67,18 @@ boolean startedSequence = false; */ private boolean consistentOutput = false; - public XMLRenderer() {} + public XMLRenderer() { + context = new RendererContext(mimeType); + } + + public void setUserAgent(FOUserAgent agent) { + super.setUserAgent(agent); + //userAgent.addExtensionHandler(); + XMLHandler handler = new XMLXMLHandler(); + userAgent.setDefaultXMLHandler(mimeType, handler); + String svg = "http://www.w3.org/2000/svg"; + userAgent.addXMLHandler(mimeType, svg, handler); + } /** * write out spaces to make indent @@ -125,11 +145,11 @@ boolean startedSequence = false; } private boolean isCoarseXml() { - return ((Boolean)options.get("fineDetail")).booleanValue(); + return ((Boolean) options.get("fineDetail")).booleanValue(); } /** - */ + */ public void startRenderer(OutputStream outputStream) throws IOException { log.debug("rendering areas to XML"); @@ -140,110 +160,254 @@ boolean startedSequence = false; } /** - */ - public void stopRenderer() - throws IOException { + */ + public void stopRenderer() throws IOException { writeEndTag(""); writeEndTag(""); this.writer.flush(); log.debug("written out XML"); } - public void renderPage(PageViewport page) - throws IOException, FOPException { - writeStartTag(""); + public void renderPage(PageViewport page) throws IOException, + FOPException { + writeStartTag(""); writeStartTag(""); -super.renderPage(page); + super.renderPage(page); writeEndTag(""); writeEndTag(""); } + private String createString(Rectangle2D rect) { + return "" + (int) rect.getX() + " " + (int) rect.getY() + " " + + (int) rect.getWidth() + " " + (int) rect.getHeight(); + } + public void startPageSequence(Title seqTitle) { -if(startedSequence) { - writeEndTag(""); -} -startedSequence = true; + if (startedSequence) { + writeEndTag(""); + } + startedSequence = true; writeStartTag(""); -if(seqTitle != null) { - writeStartTag(""); - List children = seqTitle.getInlineAreas(); + if (seqTitle != null) { + writeStartTag("<title>"); + List children = seqTitle.getInlineAreas(); - for (int count = 0; count < children.size(); count++) { - InlineArea inline = (InlineArea) children.get(count); - inline.render(this); - } + for (int count = 0; count < children.size(); count++) { + InlineArea inline = (InlineArea) children.get(count); + inline.render(this); + } - writeEndTag(""); -} + writeEndTag(""); + } } protected void renderRegionViewport(RegionViewport port) { - if(port != null) { - writeStartTag(""); - Region region = port.getRegion(); - if (region.getRegionClass() == Region.BEFORE) { - writeStartTag(""); - renderRegion(region); - writeEndTag(""); - } else if (region.getRegionClass() == Region.START) { - writeStartTag(""); - renderRegion(region); - writeEndTag(""); - } else if (region.getRegionClass() == Region.BODY) { - writeStartTag(""); - renderBodyRegion((BodyRegion)region); - writeEndTag(""); - } else if (region.getRegionClass() == Region.END) { - writeStartTag(""); - renderRegion(region); - writeEndTag(""); - } else if (region.getRegionClass() == Region.AFTER) { - writeStartTag(""); - renderRegion(region); - writeEndTag(""); + if (port != null) { + writeStartTag(""); + Region region = port.getRegion(); + if (region.getRegionClass() == Region.BEFORE) { + writeStartTag(""); + renderRegion(region); + writeEndTag(""); + } else if (region.getRegionClass() == Region.START) { + writeStartTag(""); + renderRegion(region); + writeEndTag(""); + } else if (region.getRegionClass() == Region.BODY) { + writeStartTag(""); + renderBodyRegion((BodyRegion) region); + writeEndTag(""); + } else if (region.getRegionClass() == Region.END) { + writeStartTag(""); + renderRegion(region); + writeEndTag(""); + } else if (region.getRegionClass() == Region.AFTER) { + writeStartTag(""); + renderRegion(region); + writeEndTag(""); + } + writeEndTag(""); } - writeEndTag(""); -} - - -} + } protected void renderBeforeFloat(BeforeFloat bf) { writeStartTag(""); -super.renderBeforeFloat(bf); + super.renderBeforeFloat(bf); writeEndTag(""); -} + } protected void renderFootnote(Footnote footnote) { writeStartTag(""); -super.renderFootnote(footnote); + super.renderFootnote(footnote); writeEndTag(""); -} + } protected void renderMainReference(MainReference mr) { - writeStartTag(""); -super.renderMainReference(mr); + writeStartTag(""); + + Span span = null; + List spans = mr.getSpans(); + for (int count = 0; count < spans.size(); count++) { + span = (Span) spans.get(count); + writeStartTag(""); + for (int c = 0; c < span.getColumnCount(); c++) { + Flow flow = (Flow) span.getFlow(c); + + renderFlow(flow); + } + writeEndTag(""); + } writeEndTag(""); -} + } + + // the normal flow reference area contains stacked blocks + protected void renderFlow(Flow flow) { + writeStartTag(""); + super.renderFlow(flow); + writeEndTag(""); + } protected void renderBlock(Block block) { - writeStartTag(""); -super.renderBlock(block); + String prop = ""; + List list = block.getPropertyList(); + if (list != null) { + prop = " props=\"" + getPropString(list) + "\""; + } + writeStartTag(""); + super.renderBlock(block); writeEndTag(""); } protected void renderLineArea(LineArea line) { - writeStartTag(""); -super.renderLineArea(line); + String prop = ""; + List list = line.getPropertyList(); + if (list != null) { + prop = " props=\"" + getPropString(list) + "\""; + } + writeStartTag(""); + super.renderLineArea(line); writeEndTag(""); } - public void renderCharacter(org.apache.fop.area.inline.Character ch) { -writeElement("" + ch.getChar() + ""); - } + public void renderViewport(Viewport viewport) { + writeStartTag(""); + super.renderViewport(viewport); + writeEndTag(""); + } + + public void renderImage(Image image) { + writeElement(""); + } + + public void renderContainer(Container cont) { + writeStartTag(""); + + super.renderContainer(cont); + writeEndTag(""); + } + + public void renderForeignObject(ForeignObject fo) { + writeStartTag(""); + Document doc = fo.getDocument(); + String ns = fo.getNameSpace(); + context.setProperty(XMLXMLHandler.WRITER, writer); + userAgent.renderXML(context, doc, ns); + writeEndTag(""); + } + + public void renderCharacter(org.apache.fop.area.inline.Character ch) { + String prop = ""; + List list = ch.getPropertyList(); + if (list != null) { + prop = " props=\"" + getPropString(list) + "\""; + } + writeElement("" + ch.getChar() + ""); + } public void renderInlineSpace(Space space) { -writeElement(""); + writeElement(""); } + public void renderLeader(Leader area) { + String style = "solid"; + switch (area.getRuleStyle()) { + case Leader.DOTTED: + style = "dotted"; + break; + case Leader.DASHED: + style = "dashed"; + break; + case Leader.SOLID: + break; + case Leader.DOUBLE: + style = "double"; + break; + case Leader.GROOVE: + style = "groove"; + break; + case Leader.RIDGE: + style = "ridge"; + break; + } + writeElement(""); + super.renderLeader(area); + } + + protected String getPropString(List list) { + String str = ""; + for (int count = 0; count < list.size(); count++) { + Property prop = (Property) list.get(count); + switch (prop.propType) { + case Property.INTERNAL_LINK: + str += "internal-link:" + prop.data; + break; + case Property.EXTERNAL_LINK: + str += "external-link:" + prop.data; + break; + case Property.FONT_FAMILY: + str += "font-family:" + prop.data; + break; + case Property.FONT_SIZE: + str += "font-size:" + prop.data; + break; + case Property.FONT_WEIGHT: + str += "font-weight:" + prop.data; + break; + case Property.FONT_STYLE: + str += "font-style:" + prop.data; + break; + case Property.COLOR: + str += "color:" + prop.data; + break; + case Property.BACKGROUND: + str += "background:" + prop.data; + break; + case Property.UNDERLINE: + str += "underline:" + prop.data; + break; + case Property.OVERLINE: + str += "overline:" + prop.data; + break; + case Property.LINETHROUGH: + str += "linethrough:" + prop.data; + break; + case Property.OFFSET: + str += "offset:" + prop.data; + break; + case Property.SHADOW: + str += "shadow:" + prop.data; + break; + default: + break; + } + str += ";"; + } + return str; + } } + diff --git a/src/org/apache/fop/render/xml/XMLXMLHandler.java b/src/org/apache/fop/render/xml/XMLXMLHandler.java new file mode 100644 index 000000000..c1174503a --- /dev/null +++ b/src/org/apache/fop/render/xml/XMLXMLHandler.java @@ -0,0 +1,161 @@ +/* + * $Id$ + * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.render.xml; + +import org.apache.fop.fo.FOUserAgent; +import org.apache.fop.render.XMLHandler; +import org.apache.fop.render.RendererContext; + +import org.apache.log.Logger; + +import org.apache.batik.dom.util.DOMUtilities; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Attr; + +import java.io.Writer; +import java.io.IOException; + +/** + */ +public class XMLXMLHandler implements XMLHandler { +public static final String WRITER = "writer"; + + public XMLXMLHandler() { + } + + public void handleXML(RendererContext context, Document doc, + String ns) throws Exception { + Writer writer = (Writer) context.getProperty(WRITER); + + String svg = "http://www.w3.org/2000/svg"; + // actually both do the same thing but one requires + // batik + if (svg.equals(ns)) { + DOMUtilities.writeDocument(doc, writer); + } else { + writeDocument(doc, writer); + } + writer.write("\n"); + } + + /** + * Writes the given document using the given writer. + */ + public static void writeDocument(Document doc, + Writer w) throws IOException { + for (Node n = doc.getFirstChild(); n != null; + n = n.getNextSibling()) { + writeNode(n, w); + } + } + + /** + * Writes a node using the given writer. + */ + public static void writeNode(Node n, Writer w) throws IOException { + switch (n.getNodeType()) { + case Node.ELEMENT_NODE: + w.write("<"); + w.write(n.getNodeName()); + + if (n.hasAttributes()) { + NamedNodeMap attr = n.getAttributes(); + int len = attr.getLength(); + for (int i = 0; i < len; i++) { + Attr a = (Attr) attr.item(i); + w.write(" "); + w.write(a.getNodeName()); + w.write("=\""); + w.write(contentToString(a.getNodeValue())); + w.write("\""); + } + } + + Node c = n.getFirstChild(); + if (c != null) { + w.write(">"); + for (; c != null; c = c.getNextSibling()) { + writeNode(c, w); + } + w.write(""); + } else { + w.write("/>"); + } + break; + case Node.TEXT_NODE: + w.write(contentToString(n.getNodeValue())); + break; + case Node.CDATA_SECTION_NODE: + w.write(""); + break; + case Node.ENTITY_REFERENCE_NODE: + w.write("&"); + w.write(n.getNodeName()); + w.write(";"); + break; + case Node.PROCESSING_INSTRUCTION_NODE: + w.write(""); + break; + case Node.COMMENT_NODE: + w.write(""); + break; + case Node.DOCUMENT_TYPE_NODE: + break; + default: + throw new Error("Internal error (" + n.getNodeType() + ")"); + } + } + + /** + * Returns the given content value transformed to replace invalid + * characters with entities. + */ + public static String contentToString(String s) { + StringBuffer result = new StringBuffer(); + + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + + switch (c) { + case '<': + result.append("<"); + break; + case '>': + result.append(">"); + break; + case '&': + result.append("&"); + break; + case '"': + result.append("""); + break; + case '\'': + result.append("'"); + break; + default: + result.append(c); + } + } + + return result.toString(); + } + +} + diff --git a/src/org/apache/fop/tools/AreaTreeBuilder.java b/src/org/apache/fop/tools/AreaTreeBuilder.java index 70698e630..e77713da8 100644 --- a/src/org/apache/fop/tools/AreaTreeBuilder.java +++ b/src/org/apache/fop/tools/AreaTreeBuilder.java @@ -16,6 +16,8 @@ import org.apache.fop.render.*; 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.fo.FOUserAgent; import org.apache.log.*; import org.apache.log.format.*; @@ -25,8 +27,14 @@ import org.apache.log.output.*; import java.io.*; import java.util.*; +import java.awt.geom.Rectangle2D; +import java.util.StringTokenizer; + import org.w3c.dom.*; +import org.apache.batik.dom.svg.SVGDOMImplementation; +import org.apache.batik.dom.util.DOMUtilities; + /** * Area tree tester. * The purpose of this class is to create and render an area tree @@ -38,14 +46,15 @@ import org.w3c.dom.*; */ public class AreaTreeBuilder { private Logger log; - String baseName = "temp"; + //String baseName = "temp"; /** */ public static void main(String[] args) { AreaTreeBuilder atb = new AreaTreeBuilder(); - atb.runTests(); + atb.runTests(args[0], args[1], args[2]); + System.exit(0); } public AreaTreeBuilder() { @@ -67,35 +76,46 @@ public class AreaTreeBuilder { /** * */ - protected void runTests() { + protected void runTests(String in, String type, String out) { log.debug("Starting tests"); - runTest(); + runTest(in, type, out); log.debug("Finished"); } /** */ - protected void runTest() { + protected void runTest(String in, String type, String out) { + Renderer rend = null; + if ("xml".equals(type)) { + rend = new XMLRenderer(); + } else if ("pdf".equals(type)) { + rend = new PDFRenderer(); + } else if ("svg".equals(type)) { + rend = new SVGRenderer(); + } + FontInfo fi = new FontInfo(); + rend.setupFontInfo(fi); + rend.setUserAgent(new FOUserAgent()); + AreaTree.StorePagesModel sm = AreaTree.createStorePagesModel(); - TreeLoader tl = new TreeLoader(); + TreeLoader tl = new TreeLoader(fi); tl.setTreeModel(sm); try { InputStream is = - new BufferedInputStream(new FileInputStream("doc.xml")); + new BufferedInputStream(new FileInputStream(in)); tl.buildAreaTree(is); - renderAreaTree(sm); + renderAreaTree(sm, rend, out); } catch (IOException e) { log.error("error reading file" + e.getMessage(), e); } } - protected void renderAreaTree(AreaTree.StorePagesModel sm) { + protected void renderAreaTree(AreaTree.StorePagesModel sm, + Renderer rend, String out) { try { - OutputStream os = new BufferedOutputStream( - new FileOutputStream(baseName + ".xml")); + OutputStream os = + new BufferedOutputStream(new FileOutputStream(out)); - Renderer rend = new XMLRenderer(); - //Renderer rend = new PDFRenderer(); rend.setLogger(log); rend.startRenderer(os); @@ -109,6 +129,19 @@ public class AreaTreeBuilder { while (c < pagec) { PageViewport page = sm.getPage(count, c); c++; + ObjectOutputStream tempstream = new ObjectOutputStream( + new BufferedOutputStream( + new FileOutputStream("temp.ser"))); + page.savePage(tempstream); + tempstream.close(); + File temp = new File("temp.ser"); + log.debug("page serialized to: " + temp.length()); + temp = null; + ObjectInputStream in = new ObjectInputStream( + new BufferedInputStream( + new FileInputStream("temp.ser"))); + page.loadPage(in); + in.close(); rend.renderPage(page); } count++; @@ -129,8 +162,10 @@ public class AreaTreeBuilder { class TreeLoader { AreaTree areaTree; AreaTree.AreaTreeModel model; - TreeLoader() { + FontInfo fontInfo; + TreeLoader(FontInfo fi) { + fontInfo = fi; } public void setTreeModel(AreaTree.AreaTreeModel mo) { @@ -163,7 +198,6 @@ class TreeLoader { readPageSequence((Element) obj); } } - } public void readPageSequence(Element root) { @@ -202,14 +236,14 @@ class TreeLoader { } public PageViewport readPageViewport(Element root) { - String bounds = root.getAttribute("bounds"); + Rectangle2D bounds = getRectangle(root, "bounds"); PageViewport viewport = null; NodeList childs = root.getChildNodes(); for (int i = 0; i < childs.getLength(); i++) { Node obj = childs.item(i); if (obj.getNodeName().equals("page")) { Page page = readPage((Element) obj); - viewport = new PageViewport(page); + viewport = new PageViewport(page, bounds); } } return viewport; @@ -228,8 +262,32 @@ class TreeLoader { return page; } + Rectangle2D getRectangle(Element root, String attr) { + String rect = root.getAttribute(attr); + StringTokenizer st = new StringTokenizer(rect, " "); + int x = 0, y = 0, w = 0, h = 0; + if (st.hasMoreTokens()) { + String tok = st.nextToken(); + x = Integer.parseInt(tok); + } + if (st.hasMoreTokens()) { + String tok = st.nextToken(); + y = Integer.parseInt(tok); + } + if (st.hasMoreTokens()) { + String tok = st.nextToken(); + w = Integer.parseInt(tok); + } + if (st.hasMoreTokens()) { + String tok = st.nextToken(); + h = Integer.parseInt(tok); + } + Rectangle2D r2d = new Rectangle2D.Float(x, y, w, h); + return r2d; + } + public RegionViewport readRegionViewport(Page page, Element root) { - RegionViewport reg = new RegionViewport(); + RegionViewport reg = new RegionViewport(getRectangle(root, "rect")); NodeList childs = root.getChildNodes(); for (int i = 0; i < childs.getLength(); i++) { Node obj = childs.item(i); @@ -257,18 +315,100 @@ class TreeLoader { public Region readRegion(Element root, int type) { Region reg; if (type == Region.BODY) { - reg = new BodyRegion(); + BodyRegion br = new BodyRegion(); + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj.getNodeName().equals("beforeFloat")) { + BeforeFloat bf = readBeforeFloat((Element) obj); + br.setBeforeFloat(bf); + } else if (obj.getNodeName().equals("mainReference")) { + MainReference mr = readMainReference((Element) obj); + br.setMainReference(mr); + } else if (obj.getNodeName().equals("footnote")) { + Footnote foot = readFootnote((Element) obj); + br.setFootnote(foot); + } + } + reg = br; } else { reg = new Region(type); + List blocks = getBlocks(root); + for (int i = 0; i < blocks.size(); i++) { + Block obj = (Block) blocks.get(i); + reg.addBlock(obj); + } } + return reg; + } + + public BeforeFloat readBeforeFloat(Element root) { + BeforeFloat bf = new BeforeFloat(); List blocks = getBlocks(root); for (int i = 0; i < blocks.size(); i++) { Block obj = (Block) blocks.get(i); - reg.addBlock(obj); + bf.addBlock(obj); } - return reg; + return bf; } + public MainReference readMainReference(Element root) { + MainReference mr = new MainReference(); + List spans = getSpans(root); + for (int i = 0; i < spans.size(); i++) { + Span obj = (Span) spans.get(i); + mr.addSpan(obj); + } + return mr; + } + + List getSpans(Element root) { + ArrayList list = new ArrayList(); + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj.getNodeName().equals("span")) { + List flows = getFlows((Element) obj); + Span span = new Span(flows.size()); + for (int j = 0; j < flows.size(); j++) { + Flow flow = (Flow) flows.get(j); + span.addFlow(flow); + } + list.add(span); + } + } + return list; + } + + List getFlows(Element root) { + ArrayList list = new ArrayList(); + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj.getNodeName().equals("flow")) { + Flow flow = new Flow(); + List blocks = getBlocks((Element) obj); + for (int j = 0; j < blocks.size(); j++) { + Block block = (Block) blocks.get(j); + flow.addBlock(block); + } + list.add(flow); + } + } + return list; + } + + public Footnote readFootnote(Element root) { + Footnote foot = new Footnote(); + List blocks = getBlocks(root); + for (int i = 0; i < blocks.size(); i++) { + Block obj = (Block) blocks.get(i); + foot.addBlock(obj); + } + return foot; + } + + List getBlocks(Element root) { ArrayList list = new ArrayList(); NodeList childs = root.getChildNodes(); @@ -276,6 +416,10 @@ class TreeLoader { Node obj = childs.item(i); if (obj.getNodeName().equals("block")) { Block block = new Block(); + List props = getProperties((Element) obj); + for (int count = 0; count < props.size(); count++) { + block.addProperty((Property) props.get(count)); + } addBlockChildren(block, (Element) obj); list.add(block); } @@ -301,11 +445,19 @@ class TreeLoader { // error } LineArea line = new LineArea(); - List inlines = getInlineAreas((Element)obj); - for (int j = 0; j < inlines.size(); j++) { - InlineArea inline = (InlineArea) inlines.get(j); - line.addInlineArea(inline); - } + List props = getProperties((Element) obj); + for (int count = 0; count < props.size(); count++) { + line.addProperty((Property) props.get(count)); + } + String height = ((Element) obj).getAttribute("height"); + int h = Integer.parseInt(height); + line.setHeight(h); + + List inlines = getInlineAreas((Element) obj); + for (int j = 0; j < inlines.size(); j++) { + InlineArea inline = (InlineArea) inlines.get(j); + line.addInlineArea(inline); + } block.addLineArea(line); type = 2; @@ -322,6 +474,7 @@ class TreeLoader { if (obj.getNodeName().equals("char")) { Character ch = new Character(getString((Element) obj).charAt(0)); + addProperties((Element) obj, ch); list.add(ch); } else if (obj.getNodeName().equals("space")) { Space space = new Space(); @@ -329,15 +482,223 @@ class TreeLoader { int w = Integer.parseInt(width); space.setWidth(w); list.add(space); - } else if (obj.getNodeName().equals("container")) { } else if (obj.getNodeName().equals("viewport")) { + Viewport viewport = getViewport((Element) obj); + if (viewport != null) { + list.add(viewport); + } } else if (obj.getNodeName().equals("leader")) { + Leader leader = getLeader((Element) obj); + if (leader != null) { + list.add(leader); + } + } else if (obj.getNodeName().equals("word")) { + Word word = getWord((Element) obj); + if (word != null) { + list.add(word); + } } else { } } return list; } + Viewport getViewport(Element root) { + Area child = null; + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj.getNodeName().equals("container")) { + child = getContainer((Element) obj); + } else if (obj.getNodeName().equals("foreignObject")) { + child = getForeignObject((Element) obj); + } else if (obj.getNodeName().equals("image")) { + child = getImage((Element) obj); + } + } + if (child == null) { + return null; + } + Viewport viewport = new Viewport(child); + return viewport; + } + + Container getContainer(Element root) { + Container cont = new Container(); + List blocks = getBlocks(root); + for (int i = 0; i < blocks.size(); i++) { + Block obj = (Block) blocks.get(i); + cont.addBlock(obj); + } + return cont; + } + + ForeignObject getForeignObject(Element root) { + Document doc; + String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI; + + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj instanceof Element) { + //System.out.println(obj.getNodeName()); + Element rootEle = (Element) obj; + String space = rootEle.getAttribute("xmlns"); + if (space.equals(svgNS)) { + try { + doc = javax.xml.parsers.DocumentBuilderFactory.newInstance(). + newDocumentBuilder().newDocument(); + Node node = doc.importNode(obj, true); + doc.appendChild(node); + DOMImplementation impl = + SVGDOMImplementation.getDOMImplementation(); + // due to namespace problem attributes are not cloned + //doc = DOMUtilities.deepCloneDocument(doc, impl); + + ForeignObject fo = new ForeignObject(doc, svgNS); + return fo; + } catch (Exception e) { + e.printStackTrace(); + } + } else { + try { + doc = javax.xml.parsers.DocumentBuilderFactory.newInstance(). + newDocumentBuilder().newDocument(); + Node node = doc.importNode(obj, true); + doc.appendChild(node); + ForeignObject fo = new ForeignObject(doc, space); + return fo; + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + return null; + } + + Image getImage(Element root) { + String url = root.getAttribute("url"); + Image image = new Image(url); + return image; + } + + Leader getLeader(Element root) { + Leader leader = new Leader(); + String rs = root.getAttribute("ruleStyle"); + if ("solid".equals(rs)) { + leader.setRuleStyle(Leader.SOLID); + } else if ("dotted".equals(rs)) { + leader.setRuleStyle(Leader.DOTTED); + } else if ("dashed".equals(rs)) { + leader.setRuleStyle(Leader.DASHED); + } else if ("double".equals(rs)) { + leader.setRuleStyle(Leader.DOUBLE); + } else if ("groove".equals(rs)) { + leader.setRuleStyle(Leader.GROOVE); + } else if ("ridge".equals(rs)) { + leader.setRuleStyle(Leader.RIDGE); + } + String rt = root.getAttribute("ruleThickness"); + int thick = Integer.parseInt(rt); + leader.setRuleThickness(thick); + addProperties(root, leader); + return leader; + } + + Word getWord(Element root) { + String url = root.getAttribute("url"); + Word word = new Word(); + addProperties(root, word); + return word; + } + + public void addProperties(Element ele, InlineArea inline) { + List props = getProperties(ele); + for (int count = 0; count < props.size(); count++) { + inline.addProperty((Property) props.get(count)); + } + String str = ele.getAttribute("width"); + + } + + public List getProperties(Element ele) { + ArrayList list = new ArrayList(); + String str = ele.getAttribute("props"); + StringTokenizer st = new StringTokenizer(str, ";"); + while (st.hasMoreTokens()) { + String tok = st.nextToken(); + int index = tok.indexOf(":"); + String id = tok.substring(0, index); + String val = tok.substring(index + 1); + Property prop = new Property(); + if ("internal-link".equals(id)) { + prop.propType = Property.INTERNAL_LINK; + prop.data = val; + list.add(prop); + } else if ("external-link".equals(id)) { + prop.propType = Property.EXTERNAL_LINK; + prop.data = val; + list.add(prop); + } else if ("font-family".equals(id)) { + prop.propType = Property.FONT_FAMILY; + prop.data = val; + list.add(prop); + } else if ("font-size".equals(id)) { + prop.propType = Property.FONT_SIZE; + prop.data = Integer.valueOf(val); + list.add(prop); + } else if ("font-weight".equals(id)) { + prop.propType = Property.FONT_WEIGHT; + prop.data = val; + list.add(prop); + } else if ("font-style".equals(id)) { + prop.propType = Property.FONT_STYLE; + prop.data = val; + list.add(prop); + } else if ("color".equals(id)) { + prop.propType = Property.COLOR; + prop.data = val; + list.add(prop); + } else if ("background".equals(id)) { + prop.propType = Property.BACKGROUND; + prop.data = val; + list.add(prop); + } else if ("underline".equals(id)) { + prop.propType = Property.UNDERLINE; + prop.data = new Boolean(val); + list.add(prop); + } else if ("overline".equals(id)) { + prop.propType = Property.OVERLINE; + prop.data = new Boolean(val); + list.add(prop); + } else if ("linethrough".equals(id)) { + prop.propType = Property.LINETHROUGH; + prop.data = new Boolean(val); + list.add(prop); + } else if ("offset".equals(id)) { + prop.propType = Property.OFFSET; + prop.data = Integer.valueOf(val); + list.add(prop); + } else if ("shadow".equals(id)) { + prop.propType = Property.SHADOW; + prop.data = val; + list.add(prop); + } + } + return list; + } + + public List getRanges(Element ele) { + ArrayList list = new ArrayList(); + String str = ele.getAttribute("ranges"); + StringTokenizer st = new StringTokenizer(str, ";"); + while (st.hasMoreTokens()) { + String tok = st.nextToken(); + } + return list; + } + public String getString(Element ele) { String str = ""; NodeList childs = ele.getChildNodes(); @@ -351,6 +712,5 @@ class TreeLoader { return str; } - } -- 2.39.5