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-ffa450edef68pull/30/head
@@ -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. |
@@ -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; |
@@ -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); | |||
} | |||
} | |||
@@ -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; | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} | |||
*/ | |||
@@ -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; | |||
} | |||
@@ -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; | |||
} |
@@ -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; |
@@ -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(); | |||
} | |||
} |
@@ -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; | |||
} | |||
@@ -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; |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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 | |||
} | |||
} | |||
} | |||
@@ -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); | |||
@@ -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); |
@@ -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); | |||
*/ | |||
} | |||
@@ -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); | |||
} | |||
} | |||
@@ -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; | |||
} | |||
@@ -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); | |||
} | |||
@@ -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("</pageSequence>"); | |||
writeEndTag("</areaTree>"); | |||
this.writer.flush(); | |||
log.debug("written out XML"); | |||
} | |||
public void renderPage(PageViewport page) | |||
throws IOException, FOPException { | |||
writeStartTag("<pageViewport>"); | |||
public void renderPage(PageViewport page) throws IOException, | |||
FOPException { | |||
writeStartTag("<pageViewport bounds=\"" + | |||
createString(page.getViewArea()) + "\">"); | |||
writeStartTag("<page>"); | |||
super.renderPage(page); | |||
super.renderPage(page); | |||
writeEndTag("</page>"); | |||
writeEndTag("</pageViewport>"); | |||
} | |||
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("</pageSequence>"); | |||
} | |||
startedSequence = true; | |||
if (startedSequence) { | |||
writeEndTag("</pageSequence>"); | |||
} | |||
startedSequence = true; | |||
writeStartTag("<pageSequence>"); | |||
if(seqTitle != null) { | |||
writeStartTag("<title>"); | |||
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("</title>"); | |||
} | |||
writeEndTag("</title>"); | |||
} | |||
} | |||
protected void renderRegionViewport(RegionViewport port) { | |||
if(port != null) { | |||
writeStartTag("<regionViewport>"); | |||
Region region = port.getRegion(); | |||
if (region.getRegionClass() == Region.BEFORE) { | |||
writeStartTag("<regionBefore>"); | |||
renderRegion(region); | |||
writeEndTag("</regionBefore>"); | |||
} else if (region.getRegionClass() == Region.START) { | |||
writeStartTag("<regionStart>"); | |||
renderRegion(region); | |||
writeEndTag("</regionStart>"); | |||
} else if (region.getRegionClass() == Region.BODY) { | |||
writeStartTag("<regionBody>"); | |||
renderBodyRegion((BodyRegion)region); | |||
writeEndTag("</regionBody>"); | |||
} else if (region.getRegionClass() == Region.END) { | |||
writeStartTag("<regionEnd>"); | |||
renderRegion(region); | |||
writeEndTag("</regionEnd>"); | |||
} else if (region.getRegionClass() == Region.AFTER) { | |||
writeStartTag("<regionAfter>"); | |||
renderRegion(region); | |||
writeEndTag("</regionAfter>"); | |||
if (port != null) { | |||
writeStartTag("<regionViewport rect=\"" + | |||
createString(port.getViewArea()) + "\">"); | |||
Region region = port.getRegion(); | |||
if (region.getRegionClass() == Region.BEFORE) { | |||
writeStartTag("<regionBefore>"); | |||
renderRegion(region); | |||
writeEndTag("</regionBefore>"); | |||
} else if (region.getRegionClass() == Region.START) { | |||
writeStartTag("<regionStart>"); | |||
renderRegion(region); | |||
writeEndTag("</regionStart>"); | |||
} else if (region.getRegionClass() == Region.BODY) { | |||
writeStartTag("<regionBody>"); | |||
renderBodyRegion((BodyRegion) region); | |||
writeEndTag("</regionBody>"); | |||
} else if (region.getRegionClass() == Region.END) { | |||
writeStartTag("<regionEnd>"); | |||
renderRegion(region); | |||
writeEndTag("</regionEnd>"); | |||
} else if (region.getRegionClass() == Region.AFTER) { | |||
writeStartTag("<regionAfter>"); | |||
renderRegion(region); | |||
writeEndTag("</regionAfter>"); | |||
} | |||
writeEndTag("</regionViewport>"); | |||
} | |||
writeEndTag("</regionViewport>"); | |||
} | |||
} | |||
} | |||
protected void renderBeforeFloat(BeforeFloat bf) { | |||
writeStartTag("<beforeFloat>"); | |||
super.renderBeforeFloat(bf); | |||
super.renderBeforeFloat(bf); | |||
writeEndTag("</beforeFloat>"); | |||
} | |||
} | |||
protected void renderFootnote(Footnote footnote) { | |||
writeStartTag("<footnote>"); | |||
super.renderFootnote(footnote); | |||
super.renderFootnote(footnote); | |||
writeEndTag("</footnote>"); | |||
} | |||
} | |||
protected void renderMainReference(MainReference mr) { | |||
writeStartTag("<mainReference>"); | |||
super.renderMainReference(mr); | |||
writeStartTag("<mainReference columnGap=\"" + | |||
mr.getColumnGap() + "\" width=\"" + mr.getWidth() + "\">"); | |||
Span span = null; | |||
List spans = mr.getSpans(); | |||
for (int count = 0; count < spans.size(); count++) { | |||
span = (Span) spans.get(count); | |||
writeStartTag("<span>"); | |||
for (int c = 0; c < span.getColumnCount(); c++) { | |||
Flow flow = (Flow) span.getFlow(c); | |||
renderFlow(flow); | |||
} | |||
writeEndTag("</span>"); | |||
} | |||
writeEndTag("</mainReference>"); | |||
} | |||
} | |||
// the normal flow reference area contains stacked blocks | |||
protected void renderFlow(Flow flow) { | |||
writeStartTag("<flow>"); | |||
super.renderFlow(flow); | |||
writeEndTag("</flow>"); | |||
} | |||
protected void renderBlock(Block block) { | |||
writeStartTag("<block>"); | |||
super.renderBlock(block); | |||
String prop = ""; | |||
List list = block.getPropertyList(); | |||
if (list != null) { | |||
prop = " props=\"" + getPropString(list) + "\""; | |||
} | |||
writeStartTag("<block" + prop + ">"); | |||
super.renderBlock(block); | |||
writeEndTag("</block>"); | |||
} | |||
protected void renderLineArea(LineArea line) { | |||
writeStartTag("<lineArea>"); | |||
super.renderLineArea(line); | |||
String prop = ""; | |||
List list = line.getPropertyList(); | |||
if (list != null) { | |||
prop = " props=\"" + getPropString(list) + "\""; | |||
} | |||
writeStartTag("<lineArea height=\"" + line.getHeight() + "\"" + | |||
prop + ">"); | |||
super.renderLineArea(line); | |||
writeEndTag("</lineArea>"); | |||
} | |||
public void renderCharacter(org.apache.fop.area.inline.Character ch) { | |||
writeElement("<char>" + ch.getChar() + "</char>"); | |||
} | |||
public void renderViewport(Viewport viewport) { | |||
writeStartTag("<viewport>"); | |||
super.renderViewport(viewport); | |||
writeEndTag("</viewport>"); | |||
} | |||
public void renderImage(Image image) { | |||
writeElement("<image url=\"" + image.getURL() + "\"/>"); | |||
} | |||
public void renderContainer(Container cont) { | |||
writeStartTag("<container>"); | |||
super.renderContainer(cont); | |||
writeEndTag("</container>"); | |||
} | |||
public void renderForeignObject(ForeignObject fo) { | |||
writeStartTag("<foreignObject>"); | |||
Document doc = fo.getDocument(); | |||
String ns = fo.getNameSpace(); | |||
context.setProperty(XMLXMLHandler.WRITER, writer); | |||
userAgent.renderXML(context, doc, ns); | |||
writeEndTag("</foreignObject>"); | |||
} | |||
public void renderCharacter(org.apache.fop.area.inline.Character ch) { | |||
String prop = ""; | |||
List list = ch.getPropertyList(); | |||
if (list != null) { | |||
prop = " props=\"" + getPropString(list) + "\""; | |||
} | |||
writeElement("<char" + prop + ">" + ch.getChar() + "</char>"); | |||
} | |||
public void renderInlineSpace(Space space) { | |||
writeElement("<space width=\"" + space.getWidth() + "\"/>"); | |||
writeElement("<space width=\"" + space.getWidth() + "\"/>"); | |||
} | |||
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("<leader ruleStyle=\"" + style + | |||
"\" ruleThickness=\"" + area.getRuleThickness() + "\"/>"); | |||
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; | |||
} | |||
} | |||
@@ -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("</"); | |||
w.write(n.getNodeName()); | |||
w.write(">"); | |||
} else { | |||
w.write("/>"); | |||
} | |||
break; | |||
case Node.TEXT_NODE: | |||
w.write(contentToString(n.getNodeValue())); | |||
break; | |||
case Node.CDATA_SECTION_NODE: | |||
w.write("<![CDATA["); | |||
w.write(n.getNodeValue()); | |||
w.write("]]>"); | |||
break; | |||
case Node.ENTITY_REFERENCE_NODE: | |||
w.write("&"); | |||
w.write(n.getNodeName()); | |||
w.write(";"); | |||
break; | |||
case Node.PROCESSING_INSTRUCTION_NODE: | |||
w.write("<?"); | |||
w.write(n.getNodeName()); | |||
w.write(n.getNodeValue()); | |||
w.write("?>"); | |||
break; | |||
case Node.COMMENT_NODE: | |||
w.write("<!--"); | |||
w.write(n.getNodeValue()); | |||
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(); | |||
} | |||
} | |||
@@ -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; | |||
} | |||
} | |||