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